Story Library
Home   Hierarchy   Classes   Files   Functions   Modules   Pages  

Utilities Overview

Reference Counting, Smart Pointers, Sharing and Imutability

To simplify memory management, many text engine objects use a reference-counting scheme inherited from Story::CRefCount. You should not delete such objects directly in case someone else has kept a pointer to them (and their destructor is protected to remind you). Instead, use the Story::CPtr smart pointer template. This looks after the reference counts for you.

Many objects are also immutable. This just means they can't be changed, which means they can be extensively shared without fear of side effects. The class Story::CIsImmutable extends Story::CRefCount with a protocol for inquiring whether an object is currently immutable, for getting hold of a mutable copy of an immutable object and vice versa. Story::CValuePtr is another smart pointer, similar to Story::CPtr except that it points only to immutable objects and gives them value semantics. That is to say, two Story::CValuePtr compare equal if the things they point to compare equal, even if the pointers themselves are different.

Finally, some objects (eg Story::CParaAtts) can be fully shared. This means that the engine keeps a global pool of shared objects, and you can call a function GetShared() on the object to return an identical copy of it that comes from the shared pool. This is neat because you can test shared objects for equality just by comparing their addresses, which is much faster than comparing them field by field.

An object which cannot be shared may treat GetShared() as a no-op and return "this". Some objects are perminantly mutable or immutable and have a function called Clone(), which may return "this" if the object is immutable.

Here, then, is the life-cycle of a typical shared object (for example, a Story::CGlyphAttsDelta). You start with a mutable one. Either you create it from scratch, with new CGlyphAttsDelta, or you copy it from an existing object using Story::CGlyphAttsDelta::GetImmutable(). Then you change its attributes to get it into the state you want. Then you call Story::CGlyphAttsDelta::GetShared(). GetShared() looks for an identical object in a shared objects pool, and returns it if it finds it. In that case, the original object has its reference count decremented and will soon be deleted. If there is no such object, GetShared() calls GetImmutable() on itself, adds the immutable version to the pool, and returns that. GetImmutable() first checks whether the object is already immutable; if it is, it just returns itself. Otherwise it copies the object and calls MakeImmutable() on the copy. Once MakeImmutable() has been called on an object, it is immutable for ever more.

In summary, Story::CPtr avoids memory leaks and dangling pointers, even in the presence of exceptions. Story::CValuePtr avoids unwanted side-effects and allows casual sharing to reduce memory consumption. Story::CValuePtr together with GetShared() ensures maximum sharing, minimises memory consumption, and provides fast equality tests.

Other utilities

The engine has a handful of general purpose classes, macros, functions and templates. Many of these are mixin classes, used with inheritance to add some facility to a class in a standard way.

Story::CClientData is a mixin class used to store an arbitrary CObject pointer on behalf of the client application. See Client Data.

Story::CComparable and Story::CComparable2 are mixin classes which inject comparison operators into the outer namespace. These define !=, >, >= and <= in terms of == and <.

Story::CCachedHash is a mixin class which provides a cached version of GetHash in terms of another function GetUncachedHash. The engine makes extensive use of hashing for speeding up comparisons. This class avoids recalculating them unnecessarily. GetHash has more hashing functions.

Story::CFixedArray is a templated array of fixed size indexed by some enumerated type. It is safer than a C-array and has less overhead than a std::vector.

Story::iterator_wrapper is a template which a non-const iterator into one that cannot be written through. This usually means that *i returns a pointer to a writable, non-const object, but code like "*i = p" is not allowed. To change an object in an engine's container you should use methods (such as Insert() or Delete()) on the container itself, not write through an iterator.

Story::CNumberFormatter is a class which understand Roman Numerals and other formats commonly used for page numbers. It is used by Story::CGlyphListNum.

Story::CStoryException is the type of exceptions which the story throws directly (as opposed to those thrown by libraries and client code, such as std::bad_alloc). It inherits from CException (which is why it has a longer name).

ArExt declares some utilities to help with serialization and MFC's runtime type information system.

Utils declares some general purpose functions and templates, such as conversions, range-checks, Min and Max, Implies.

Dump declares some macros which may be useful for debugging.

See also Utility Classes.


Serif Story Documentation.
This content last built on 30 Oct 2003.