The TrackMem and TrackArray modules supply memory management facilities for APS. Mostly, these constructions help to reduce effective overhead, and greatly simplify the task of passing data to a library user and ensuring that it is released correctly.
TrackMem is a memory resources tracking module based on a hierarchial dependency tree. Its primary feature is to provide primitives for incrementally building complex compound objects consisting of multiple allocations and for freeing them as a whole or in parts. To this end, memory allocations are linked into a tree such that an object can be directly associated with a set of subordinate allocations which, by default, will be released automatically with their parent allocation. The most immediate benefit is to simplify internal memory management for compound objects such as arrays of pointers to objects or structures containing strings. It also improves data abstraction by providing hierarchial relationships very similar to a high-level description of an object. e.g. Strings which "belong" to a structure are children of the allocation such that given a string we can locate the structure, or given a structure we can locate all of the storage it uses. Naturally, this greatly simplifies resource control, error handling and fault-tolerance, and offers the potential to entirely wipe out memory leaks. TrackMem also offers advanced features for more complex tasks: reassignment of allocations and late binding, binding to existing objects, user-defined destructors, extensible user tag space.
TrackArray implements dynamically resizable linear arrays on top of the TrackMem subsystem. It is primarily intended for creating arrays of equally-sized structures, though it may also be used to hold pointers, native datatypes, or even "void". TrackArray is implemented in two parts: the core controlling code, and a macro-based template. The latter provides all the benefits of type checking and eases setting array elements by value; without substantially increasing overhead (or even at all, if the implementation is made inline). If you intend to manipulate pointers to structures, consider using the TrackArrayIndirect wrapper template below. The main feature of these primitives is that C-style indexing is still supported, i.e. the array handle is actually a base pointer.
TrackArrayIndirect builds on the TrackArray template and primitive code to support arrays of pointers to (usually equal-sized) objects. For instance, you are constructing an array of pointers to data structures. Specifically, this template performs all necessary indirection to simplify the task of adding new elements as much as possible. Note the TrackArrayIndirect template may be used on any suitable array of pointers. Likewise, TrackArray may be used directly on an array declared with TrackArrayIndirect.
TMEM void *TrackMemAlloc( TMEM void *memParent, size_t size, size_t sizeTags);
Builds a hierarchy of dependant memory allocations from a common source. To create the initial hierarchial segment, alloc with memParent = NULL.
memParent | Pointer to the TrackMem object to use as parent of new allocation. |
size | Initial size of user data we want to store here. |
sizeTags | Initial size of tag space to preallocate. |
Returns a pointer to a new TrackMem object of specified size, or NULL on failure.
TMEM void *TrackMemClone( TMEM void *memParent, const tmem void *memSource);
Creates an exact duplicate of an existing TrackMem allocation including the size and contents of its Tag and User spaces. The new allocation is then attached to the designated parent's tree. It is dangerous to perform this operation on LINKs as the result is a new LINK pointing to the same target object. Therefore it is possible for the target object to be released twice unless no destructor is specified.
memParent | Pointer to the TrackMem object to use as parent of new allocation. |
memSource | Pointer to the TrackMem object to clone. |
Returns a pointer to a new TrackMem object consisting of an exact duplicate of the specified source object, or NULL on failure.
This operation DOES NOT clone or reassign the children of the source object.
TMEM void *TrackMemDupMemory( TMEM void *memParent, const void *memSource, size_t size, size_t sizeTags);
Allocates space for a duplicate of an existing memory block and copies it to the new buffer. Unlike TrackMemClone, this function does not assume that the memory source is an TrackMem object and the duplicate memory block does not inherit any tags.
memParent | Pointer to the TrackMem object to use as parent of new allocation. |
memSource | Pointer to the memory block to clone. |
size | Size of the memory block to clone. |
sizeTags | Initial size of tag space to preallocate. |
Returns a pointer to a new TrackMem object containing an exact duplicate of the source buffer in user space, or NULL on failure.
TMEM void *TrackMemDupString( TMEM void *memParent, const char *strSource, size_t sizeTags);
Duplicate a string and link to a parent's tree, or NULL on failure. Unlike TrackMemClone, this function does not assume that the memory source is an TrackMem object and the duplicate memory block does not inherit any tags.
memParent | Pointer to the TrackMem object to use as parent of new allocation. |
strSource | Pointer to the string to clone. |
sizeTags | Initial size of tag space to preallocate. |
Returns a pointer to a new TrackMem object containing an exact duplicate of the source string in user space, or NULL on failure.
TMEM void *TrackMemLink( TMEM void *memParent, const void *memTarget, size_t sizeTarget, size_t sizeTags);
Allocates a MemTrack object to function as a resource tracking identifier for a object of linked memory. The contents of the target are not copied as with TrackMemClone() but will be freed by TrackMemFree() as if the object had been allocated in the usual way. By default, LINKs are disposed of using the system's standard deallocator (usually stdlib's free()), but this behaviour may be changed using MemTrackTagSetLinkDestructor().
memParent | Pointer to the TrackMem object to use as parent of new allocation. |
memTarget | Pointer to the object to use as target of this link. |
sizeTarget | Optional size of the target object in bytes. May be 0, but is required by TrackMemRealloc in order to correctly absorb links. |
sizeTags | Initial size of tag space to preallocate. |
Returns a fictional pointer to a TrackMem object, or NULL on failure. Do not attempt to dereference this pointer as it does not refer to any particular region of interest. Use TrackMemGetData() to locate the target of a link given this pointer.
TrackMemRealloc() will assume the link pointer refers to memory and will clone it unless the size was specified as 0. It will then dispose of the target object using the specified destructor. In short, the link is absorbed by TrackMemRealloc() -- if this is not desirable, set the size to 0 and/or don't call TrackMemRealloc().
TrackMemFree() will search for a destructor specified by TrackMemTagSetLinkDestructor() before attempting to free the target object.
TMEM void *TrackMemRealloc( TMEM void *mem, size_t size);
Extends/shrinks an existing allocation and copies as much of the contents as will fit, and preserves all hierarchial and tag information. To extend the size of tag space use TrackMemReallocTagSpace(). Calling this function invalidates any pointers into tag space or into user space.
mem | Pointer to the TrackMem object to resize. |
size | Desired new size of user data space. |
Returns a pointer to the extended object, or NULL on failure. There are no guarantees that the original object will still be valid if this fails (but it should be). The returned pointer may not necessarily be different from the old one.
This function behaves differently with LINKs. Please refer to TrackMemLink().
TMEM void *TrackReallocTagSpace( TMEM void *mem, size_t sizeTags);
Extends/shrinks the current allocated size of tag space. Note that shrinking tag space is for internal purposes only and may cause unpredictable behaviour if there are currently allocated tags in the region which is discarded. Calling this function invalidates any pointers into tag space or into user space. There should be no reason for anyone to use this at the moment, see TrackMemTagAdd().
mem | Pointer to the TrackMem object whose tag space is to be resized. |
sizeTags | Desired new size of tag space. |
Returns a pointer to the extended object, or NULL on failure. There are no guarantees that the original object will still be valid if this fails (but it should be). The returned pointer may not necessarily be different from the old one.
This function has no effect on the contents or location of a LINK.
void TrackMemFree( TMEM void *mem);
Recursively frees all of the children of a TrackMem object, then frees the object itself. In the case of LINKs, special destructors may be called to free the target object.
mem | Pointer to the TrackMem object to be freed. |
This function behaves differently with LINKs. Please refer to TrackMemLink().
void TrackMemFreeChildren( TMEM void *mem);
Recursively frees all of the children of a TrackMem object, but not the object. In the case of LINKs, special destructors may be called to free the target object.
mem | Pointer to the TrackMem object whose children are to be freed. |
This function behaves differently with LINKs. Please refer to TrackMemLink().
void *TrackMemUnlink( TMEM void *mem);
Orphans the children of a TrackMem object [as if TrackMemReassignChildren(NULL, mem) were called], then removes the object from the tracking tree, releasing any associated resources. All tags are lost. If this is a LINK, the returned pointer is a pointer to the target, if not, it points to a buffer with the contents of the old TrackMem object. This effectively allows the memory block to be released using the system's default deallocator (usually stdlib free()).
mem | Pointer to the TrackMem object to be "unlinked". |
Returns a pointer to the data that was associated with the TrackMem object, or NULL on failure. There are no guarantees that the original object will still be valid if this fails (but it should be). The returned pointer may not necessarily be different from the old one.
Differs from TrackMemReassign(NULL, mem) in that the target's storage pointer is returned and the linking structure itself is unlinked and freed.
This operation is fairly efficient as it generally involves moving the user data to the head of the original object's storage then lopping off the end of the old allocation, and returning the old base pointer.
void TrackMemReassign( TMEM void *memParent, TMEM void *mem);
Explicitly reassigns a TrackMem object from its current parent to become a child of the new parent. This means that if the new parent if not NULL, then this object will automatically be freed when the new parent is freed. Preserves the location (user space pointer) and all data, tags and children of the object to be reassigned.
memParent | Pointer to the TrackMem object to use as new parent of the specified TrackMem object, or NULL to indicate no parent (orphans tree). |
mem | Pointer to the TrackMem object to be reassigned. |
void TrackMemReassignChildren( TMEM void *memParent, TMEM void *mem);
Explicitly reassigns the direct children of a TrackMem object to become children of the new parent. This means that if the new parent if not NULL, then these objects will automatically be freed when the new parent is freed. Preserves the location (user space pointer) and all data, tags and children of the objects to be reassigned.
memParent | Pointer to the TrackMem object to use as new parent of the specified TrackMem object, or NULL to indicate no parent (orphans all children's trees). |
mem | Pointer to the TrackMem object whose children are to be reassigned. |
void *TrackMemGetData( const TMEM void *mem);
Safely get a pointer to the data this TrackMem object represents. Except in the case of a LINK, the returned pointer should always equal the source pointer.
mem | Pointer to the TrackMem object to examine. |
Returns a pointer to the target data controlled by the selected TrackMem object.
Use this if you are trying to locate the target of a LINK or if you are unsure of the type of TrackMem object you are referring to.
TMEM void *TrackMemGetParent( const TMEM void *mem);
Locate the parent of this TrackMem object and return a pointer to it.
mem | Pointer to the TrackMem object to examine. |
Returns the address of the TrackMem object functioning as the parent of this object.
size_t TrackMemGetSize( const TMEM void *mem);
Get size of a tracked allocation. In the case of LINKs, this is the size that was specified by the user upon creation; otherwise, it represents the size of the largest quantity of data that can be stored by this TrackMem object without reallocation. The value returned will already be greater than or equal to the size requested upon allocation.
mem | Pointer to the TrackMem object to examine. |
Returns a size_t representing the size of the allocation this object refers to, in bytes.
size_t TrackMemGetTagSpaceSize( const TMEM void *mem);
Gets the amount of tag space that is currently associated with a given TrackMem object. This is only useful during reallocation of tag space and does not guarantee that a particular number or size of tags may actually be stored here due to administrative overhead. There should be no reason for anyone to use this at the moment, see TrackMemTagAdd().
mem | Pointer to the TrackMem object to examine. |
Returns a size_t representing the effective size of this object's allocated tag space, in bytes. May be 0 if no tag space was allocated.
void *TrackMemTagSet( TMEM void *mem, TrackMem_TagType tagType, size_t tagSize);
Sets a tag in a TrackMem object using pre-allocated storage as specified during initial allocation or TrackMemReallocTagSpace(). If a tag of the same type exists, TrackMemTagSet will remove it before adding the new one even if the operation fails due to insufficient tag space. To remove a tag, use TrackMemTagUnset() with the same tag type.
Please use TrackMemTagAdd() even if you think there's enough room, unless you are concerned about the TrackMem object being reallocated and thereby invalidating all pointers.
mem | Pointer to the TrackMem object to be tagged. |
tagType | An 8bit unsigned integer uniquely identifying the type of tag to be set. This should equal TRACKMEM_TAG_BASE_USER plus some unique integer between 0x00 and 0x7F, inclusive. |
tagSize | The size of the tag to be added. |
Returns a pointer to the user tag storage buffer which has been allocated, or NULL on failure. The storage buffer is not initialised.
The volatility and lifetime of tag storage pointers is the same as those for their host TrackMem object.
Individual tags cannot be resized without first removing them from an object then adding a new one of the desired size.
void *TrackMemTagAdd( TMEM void **mem, TrackMem_TagType tagType, size_t tagSize);
Adds a tag to a TrackMem object like TrackMemTagSet(), even if there is currently insufficient tag space. If necessary, this function will reallocate the existing tag space using TrackMemReallocTagSpace(). Calling this function invalidates any pointers into tag space or into user space.
mem | Reference to a pointer to the TrackMem object to be tagged, and potentially reallocated / moved. |
tagType | An 8bit unsigned integer uniquely identifying the type of tag to be added. This should equal TRACKMEM_TAG_BASE_USER plus some unique integer between 0x00 and 0x7F, inclusive. |
tagSize | The size of the tag to be added. |
Returns a pointer to the user tag storage buffer which has been allocated, or NULL on failure. The storage buffer is not initialised.
The volatility and lifetime of tag storage pointers is the same as those for their host TrackMem object.
Individual tags cannot be resized without first removing them from an object then adding a new one of the desired size.
void *TrackMemTagFind( const TMEM void *mem, TrackMem_TagType tagType, size_t *tagSize);
Locates a tag's storage in a TrackMem object given a unique identifier. The tag must have been previously added using either TrackMemTagSet() or TrackMemTagAdd().
mem | Pointer to the TrackMem object to be examined. |
tagType | An 8bit unsigned integer uniquely identifying the type of tag to be located. This should equal TRACKMEM_TAG_BASE_USER plus some unique integer between 0x00 and 0x7F, inclusive. |
tagSize | Pointer to a size_t to contain the size of the tag that was located. May be NULL if the size need not be reported. |
Returns a pointer to the tag storage space, or NULL if no tag of the specified type was found.
The volatility and lifetime of tag storage pointers is the same as those for their host TrackMem object.
int TrackMemTagSetLinkDestructor( TMEM void *mem, TrackMem_DestructorType dType, void *dFunc);
Sets the destructor for a TrackMem LINK object. Before the TrackMem object is released, the specified destructor will be called to free its target.
mem | Pointer to the TrackMem LINK object for whose target to select a new destructor. |
dType | The type of destructor to be used for the target of this LINK. Select from one of the constants below. |
dFunc | Pointer to the function to call, or NULL when appropriate. |
Acceptable parameters for dType:
TrackMem_DestructorType constants Usage TRACKMEM_DESTRUCTOR_DEFAULT NULL [don't care]
Uses system's default destructor (usually stdlib free()).TRACKMEM_DESTRUCTOR_NONE NULL [don't care]
Does not attempt to dispose of the object.TRACKMEM_DESTRUCTOR_SIMPLE typedef void (*TrackMem_LinkDestructorFunc)(void *link);
Destructor whose first argument is a pointer to the target object.TRACKMEM_DESTRUCTOR_SPECIAL typedef void (*TrackMem_LinkSpecialDestructorFunc)(void *link, TMEM *ref);
Destructor whose first argument is a pointer to the target object, and whose second argument is a pointer to the TrackMem object being released (allows you to examine tags).
Returns TRUE if the destructor was added successfully, else returns FALSE.
Do not perform any operation which threatens to invalidate pointers to user or tag space from within a destructor. (eg. resizing user or tag space, freeing, or unlinking)
void TrackMemTagUnset( TMEM void *mem, TrackMem_TagType tagType);
Remove a tag that was previously added by TrackMemTagSet() or TrackMemTagAdd() from a TrackMem object. It is safe to call this function to remove a tag which does not exist, though it may reflect bad design on the user's part.
mem | Pointer to the TrackMem object from which to remove a tag. |
tagType | An 8bit unsigned integer uniquely identifying the type of tag to be removed. This should equal TRACKMEM_TAG_BASE_USER plus some unique integer between 0x00 and 0x7F, inclusive. |
TrackArray *TrackArrayNew( TMEM void *memParent, size_t size, int initial);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayNew()
*
* Create a new array control structure for elements of a specific
* size. The array is created blank initially.
*
* It is legal to cast the returned pointer directly to a native C/C++
* array base pointer type of the appropriate size and manipulate the
* elements directly. Of course, no type checking will be performed on
* such a pointer but in return you can expect a very good performance
* increase. *8) [So it'll crash faster if you're not careful!]
*
* Note: The address of the array may change if it is resized.
* This is an unavoidable side-effect of doing things in C.
* To get around this, keep only one copy of the address or
* use a double-indirection scheme.
*
* Parameters: memparent - pointer to memory block to use as parent
* size - size of a native storage element of this
* array (all elements are equally-sized)
* initial - initial number of elements to allocate
* (must be >= 0)
*
* Returns a pointer to a TrackMem object containing the array. This
* pointer may be directly used to manipulate array contents.
* (ie. You can use this as a drop-in malloc() replacement assuming you
* replace calls to free() with appropriate TrackArrayDelete() calls)
*/
TrackArray *TrackArrayClone( TMEM void *memParent, TrackArray *arraySource);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayClone()
*
* Clones an existing array excluding any dependancies it may have. Though
* TrackMemClone() is sufficient for this operation, it is recommended to
* use this one instead as it will also compact the array and purge any
* unnecessary administrative data (assuming there was any).
*
* Note: To clone a C-style array you should do the following instead:
* (note, appropriate casts may be necessary)
*
* Elem *array, *oldArray;
* array = TrackArrayNew(parent, sizeof(Elem), numElems);
* if (array) memcpy(array, oldArray, sizeof(Elem) * numElems);
*
* Parameters: memparent - pointer to memory block to use as parent
* array - pointer to an existing array which will be
* cloned
*
* Returns a pointer to a TrackMem object containing the array. This
* pointer may be directly used to manipulate array contents.
* (ie. You can use this as a drop-in malloc() replacement assuming you
* replace calls to free() with appropriate TrackArrayDelete() calls)
*/
void TrackArrayDelete( TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayDelete()
*
* Disposes of an existing array and any of the dependancies it might have
* had. Follows the same rules as TrackMemFree() regarding destructor call
* ordering, etc...
*
* Parameters: array - pointer to array base pointer to free
*
* Provided for completeness. Arrays may be deleted simply by
* calling TrackMemFree() on the base pointer. Of course, using this is
* more explicit and generally a Good Idea.
*/
void *TrackArrayUnlink( TrackArray *arraySource);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayUnlink()
*
* Disposes of all the memory tracking info that was tied with an array
* and returns a plain-jane C-style array which may be freed using the
* default destructor specified by the memFree() macro of the TrackMem
* subsystem. Follows the same rules as TrackMemUnlink().
*
* Avoid doing this on arrays with memory tracked dependancies as they
* will be orphaned and may only be subsequently freed via explicit
* specification of TrackMemFree().
*
* Parameters: array - pointer to an existing array which will be
* unlinked
*
* Remember: Once unlinked you may no longer use any of the TrackArray...()
* functions on this array or any TrackMem...() primitives.
* The returned array may also have a different base address.
*
* Provided for completeness. Arrays may be unlinked simply by calling
* TrackMemUnlink() on the base pointer.
*/
int TrackArrayResize( TrackArray **array, int numElems);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayResize()
*
* Adjusts the size of an array increasing or decreasing the bounds (and
* amount of allocated storage) as necessary. As usual, if space for 'n'
* elements has been allocated, then the largest available index is 'n-1'.
* If 'n' == 0, then the array will be considered empty.
*
* Let x = old number of elements
* Let y = new number of elements
* if (y == x) then {
* no change
* } else if (y > x) then {
* array elements 0 through x-1 will be preserved
* array elements x through y-1 will be uninitialized (assume garbage!)
* } else if (y != 0) then {
* array elements 0 through y-1 will be preserved
* array elements y through x-1 will be discarded (assume inaccessible)
* --> note no external resources used by the elements will be
* released; you must explicitely free any such resources
* } else {
* all array elements will be discarded (as above)
* Beware! Most access (get) operations will throw exceptions.
* }
*
* Note, though some implementations may choose to preallocate storage
* for more elements than necessary (e.g. classic doubling scheme), this
* should not be assumed. Moreover, one should assume that Resize()
* performs the most efficient rellocation scheme possible for a given
* implementation so please don't try to second-guess the algorithm
* -- ie. Please don't re-implement a doubling scheme as it may make
* the algo less efficient.
*
* Parameters: array - pointer to pointer to an existing array to be
* resized
* numElems - new number of elements to allocate
*
* Returns TRUE on success, FALSE otherwise.
*
* On some implementations, the result of a failed resize will be the
* destruction of the array. In these cases *array will be set to NULL
* whenever possible. (check the results and cross your fingers)
*/
void TrackArrayEnsureStorageForElem( TrackArray **array, int elemIndex);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayEnsureStorageForElem()
*
* Ensure that there is enough storage for the specified element. This may
* be useful in cases where you are not sure if storage was allocated for
* a specific element. Additionally this may provide useful hints to a
* derived implementation supporting partial sparse arrays.
*
* if (elem >= TrackArrayGetSize(array)) TrackArrayResize(array, elem + 1);
*
* Parameters: array - pointer to pointer to an existing array to be
* verified / resized
* elem - element number to ensure storage for
*
* Returns TRUE on success, FALSE otherwise.
*/
int TrackArrayGetSize( const TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayGetSize()
*
* Get the size of the array in terms of how many elements it contains. This
* function may very well return 0 to indicate that the array has no storage
* capacity.
*
* Parameters: array - pointer to an array to examine
*
* Returns the size of the array (in #'s of elements).
*/
size_t TrackArrayGetElemSize( const TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayGetElemSize()
*
* Get the size of each elements in multiples of sizeof(char *) (usually
* bytes). This function may return 0 to indicate that the elements are
* sizeless. Generally that is a rather useless "feature".
*
* Parameters: array - pointer to an array to examine
*
* Returns the size of each element of the array (in multiples of
* sizeof(char *).)
*/
int TrackArrayGetIndexByRef( const TrackArray *array, const void *elemRef);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayGetIndexByRef()
*
* Get the index of an element given a reference to its storage location in
* the array. Please use this whenever it is necessary to convert a pointer
* to an address.
*
* Note: Checks bounds and asserts in case of misaligned pointers.
*
* Parameters: array - pointer to an array to examine
* elem - pointer to element's storage
*
* Returns an integer representing this element's index in the array.
* The following assertions are valid:
* ASSERT(TrackArrayGetIndexByRef(array, TrackArrayElemAt(array, num)) \
* == num);
* ASSERT(TrackArrayGetIndexByRef(array, & array[num]) == num);
*/
void TrackArrayGetElemByRef( const TrackArray *array, const void *elemRef, void *targetBuffer);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayGetElemByRef()
*
* Fills in the supplied buffer with the contents of the element referenced
* by the given pointer. This function essentially performs a memmove() on
* the data using the full element width as assigned by the array. A net
* advantage of this call is that it disambiguates operations which are
* designed to manipulate array contents.
*
* Performs the equivalent of:
* memmove(data, elem, TrackArrayGetElemSize(array));
*
* Parameters: array - pointer to an array to be examined
* elem - reference to element to fetch
* data - user-supplied buffer where data should be
* stored
*/
void TrackArraySetElemByRef( TrackArray *array, void *elemRef, const void *sourceBuffer);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArraySetElemByRef()
*
* Stores the contents of the supplied buffer into the array element
* referenced by the given pointer. This function essentially performs a
* memmove() on the data using the full element width as assigned by the array.
* A net advantage of this call is that it disambiguates operations which are
* designed to manipulate array contents.
*
* Performs the equivalent of:
* memmove(elem, data, TrackArrayGetElemSize(array));
*
* Parameters: array - pointer to an array to be modified
* elem - reference to element to modify
* data - user-supplied buffer from which data should be
* fetched
*/
void *TrackArrayAddLast( TrackArray **array, const void *sourceBuffer);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayAddLast()
*
* Add an element to the end of an array. Increases the effective user-
* addressable size of the array by 1 element and extends the physical
* storage if necessary so that the new element will fit.
*
* If data is NOT NULL, copies source data into the new slot, else
* creates space but does not copy.
*
* Parameters: array - pointer to pointer to an array to be modified
* data - pointer to a buffer containing initialization
* data for the element (ignored if NULL)
*
* Returns pointer to new element's storage.
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*/
void TrackArrayRemoveLast( TrackArray **array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayRemoveLast()
*
* Remove an element from the end of the array. Decreases the effective user-
* addressable size of the array by 1 element and shrinks the physical
* storage if possible and desirable [implementation-defined].
*
* Parameters: array - pointer to pointer to an array to be modified
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (array must not be empty)
*/
void TrackArrayInsertAt( TrackArray **array, int elemIndex, const void *sourceBuffer);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayInsertAt()
*
* Insert an element at position elem. Increases the effective user-
* addressable size of the array by 1 element and extends the physical
* storage if necessary so that the new element will fit.
*
* Parameters: array - pointer to pointer to an array to be modified
* elem - index before which to insert the new element
* (existing elements are pushed down such that
* array[elem] contains the new element)
* data - pointer to a buffer containing initialization
* data for the element which is copied to the
* new slot unless NULL)
*
* Returns pointer to new element's storage.
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void TrackArrayRemoveAt( TrackArray **array, int elemIndex);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayRemoveAt()
*
* Remove an element at position elem. Decreases the effective user-
* addressable size of the array by 1 element and shrinks the physical
* storage if possible and desirable [implementation-defined].
*
* Parameters: array - pointer to pointer to an array to be modified
* elem - index of element to be removed (existing elements
* (existing elements are moved up such that
* array[elem] is removed)
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (0 <= x < length)
*/
void *TrackArrayInsertManyAt( TrackArray *array, int elemFirstIndex, int elemCount, const void *sourceArray);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayInsertManyAt()
*
* Insert many elements such that the first new elements is given the
* specified index and that the old element from that index is pushed
* down beyond the space consumed by the new entries. Increases the
* effective user-addressable size of the array by the total count of
* elements inserted.
*
* Functionally, this is equivalent to the iterative application of
* TrackArrayInsertAt() but far more efficient.
*
* Parameters: array - pointer to pointer to an array to be modified
* elem - index before which to insert the first new
* element (existing elements are pushed down)
* count - number of elements to insert
* data - pointer to a buffer containing initialization
* data for the element which is copied to the
* new slot unless NULL)
*
* Returns pointer to first new element's storage.
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void *TrackArrayAppendMany( TrackArray **array, int elemCount, const void *sourceArray);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayAppendMany()
*
* Appends many elements to the tail of an array such that the last
* element of the array becomes the last element of the source data.
* Increases the effective user-addressable size of the array by the
* total count of elements appended.
*
* Functionally, this is equivalent to the iterative application of
* TrackArrayAddLast() but far more efficient.
*
* Parameters: array - pointer to pointer to an array to be modified
* elem - index before which to insert the first new
* element (existing elements are pushed down)
* count - number of elements to append
* data - pointer to a buffer containing initialization
* data for the element which is copied to the
* new slot unless NULL)
*
* Returns pointer to first new element's storage.
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void TrackArrayRemoveManyAt( TrackArray **array, int elemFirstIndex, int elemCount);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayRemoveManyAt()
*
* Remove many elements from the middle / end of an array such that
* all elements in the range [elem]..[elem+count-1] are removed.
* Decreases the effective user-addressable size of the array by the
* total count of elements removed and shrinks the physical storage
* if possible and desirable [implementation-defined].
*
* Functionally, this is equivalent to the iterative application of
* TrackArrayRemoveAt() / TrackArrayRemoveLast() but far more efficient.
*
* Parameters: array - pointer to pointer to an array to be modified
* elem - index before which to insert the first new
* element (existing elements are pushed down)
* count - number of elements to be removed
*
* Note: This function modified the array's base pointer if it was necessary
* to reallocate the storage, and is subject to the same rules as
* TrackArrayResize().
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void TrackArrayGetManyAt( const TrackArray *array, int elemFirstIndex, int elemCount, void *targetArray);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayGetManyAt()
*
* Extracts a number of elements from an array and stores them in the user-
* provided buffer.
*
* Functionally, this is equivalent to performing a mass memmove() on a
* segment of the array, but also incorporates bounds checking.
*
* Parameters: array - pointer to an array to be examined
* elem - index at which to start extracting elements
* count - number of elements to get
* buffer - user buffer where the data is to be stored
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void TrackArraySetManyAt( TrackArray **array, int elemFirstIndex, int elemCount, const void *targetArray);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArraySetManyAt()
*
* Sets a number of an array's elements based on the contents of the user-
* provided buffer.
*
* Functionally, this is equivalent to performing a mass memmove() on a
* segment of the array, but also incorporates bounds checking.
*
* Parameters: array - pointer to an array to be modified
* elem - index at which to start setting elements
* count - number of elements to set
* buffer - user buffer from which the data is to be fetched
*
* ASSERT's on out of bounds. (0 <= x <= length)
*/
void *TrackArrayElemAt( const TrackArray *array, int elemIndex);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemAt()
*
* Get the address of the storage space for the specified element.
*
* Parameters: array - pointer to array to be examined
* elem - index of element to seek to (must be in
* addressable bounds of array)
*
* Returns a pointer to the element's storage in the array.
*
* ASSERT's on out of bounds. (0 <= x < length)
*
* This function is not required to access members as it is quite legal
* for one to simply cast the array pointer to a more useful pointer
* type and use normal indexing procedures.
*
*/
void *TrackArrayElemFirst( const TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemFirst()
*
* Get the address of the storage space for the first element of
* the array (zero-th index).
*
* Parameters: array - pointer to array to be examined
*
* Returns a pointer to the element's storage in the array.
*
* ASSERT's if array length is 0.
* See TrackArrayElemAt() for indexing information.
*/
void *TrackArrayElemLast( const TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemLast()
*
* Get the address of the storage space for the last element of
* the array ((bound-1)-th index).
*
* Parameters: array - pointer to array to be examined
*
* Returns a pointer to the element's storage in the array.
*
* ASSERT's if array length is 0.
* See TrackArrayElemAt() for indexing information.
*/
void *TrackArrayElemEndMark( const TrackArray *array);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemEndMark()
*
* Get the address of the storage space for the element one beyond
* the end of the array.
*
* Parameters: array - pointer to array to be examined
*
* Returns a pointer to the element's storage in the array.
*
* This function always succeeds (assuming the array is valid)
* See TrackArrayElemAt() for indexing information.
*/
void *TrackArrayElemNext( const TrackArray *array, const void *elemRef);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemNext()
*
* Given the address of an array element, get the address of the next
* element of the same array. If ptrelem = NULL, returns first element
* of the array (assuming it has any).
*
* Parameters: array - pointer to array to be examined
* ptrelem - pointer to element's storage -- used as start
* point for locating the next one
*
* Returns a pointer to the element's storage in the array.
*
* This function tests bounds and will cause an ASSERT() if these
* bounds are exceeded, but allows one to step to the "end marker"
* positions (one past the end). (ie. stepped two past the end)
*
* Note: Checks for misaligned source elements.
*/
void *TrackArrayElemSkip( const TrackArray *array, const void *elemRef, int elemSkipCount);
array | Base pointer of the TrackArray to manipulate. |
memSource | Initial size of user data we want to store here. |
/* ---------------------------------------------------------------------------
* TrackArrayElemSkip()
*
* Given the address of an array element, get the address of an
* element indexed 'num' elements away (signed value). If ptrelem = NULL,
* indexes from beginning of array.
*
* Parameters: array - pointer to array to be examined
* ptrelem - pointer to element's storage -- used as start
* point for skipping past many
* num - number of elements to skip
*
* Returns a pointer to the element's storage in the array.
*
* This function tests bounds and will cause an ASSERT() if these
* bounds are exceeded, but allows one to step to the "end marker"
* positions (one past the end). (ie. stepped two past the end)
*
* Note: Checks for misaligned source elements.
*/
****** FIXME ****** While parameterized types are not available in C, the support has been created using a pair of macros which generate the appropriate declarations (prototypes) and implementation for each member function. The namespace is partitioned by tagging the type name to the end of each base function name prefixed by a '_' (e.g. DynArrayNew_PtrChar(...), DynArrayNew_Int(...)).
/*** TrackArray "Template" ***/
/*
* The templates defined in these steps produce functions of
* the form TrackArray[Operation]_[Type]. With the exception of
* New, InsertAt and AddLast, their functionality mimics that
* of the generic routines.
*
* The templates also produce type TrackArray_[Type] which is equivalent
* to [Type]*. Please use this whenever possible (except in places where
* the public interface is not to disclose an underlying type) as it
* improves overall readability of constructs using TrackArray.
*
* New types:
* TrackArray_[Type] - base pointer to array
* TrackArrayElem_[Type] - type of an element of that array
* TrackArrayElemRef_[Type] - type of a reference to an array element
* stored inside an array (don't use for
* arbitrary element references)
*
* Member function differences:
* TrackArrayNew_[Type] - does not require element size
* TrackArrayInsertAt_[Type] - accepts plain types (not buffers)
* TrackArrayAddLast_[Type] - accepts plain types (not buffers)
* TrackArrayGetElemByRef_[Type] - does not exist, use indirection
* and assignment operation on ref ptr
* TrackArraySetElemByRef_[Type] - does not exist, use indirection
* and assignment operation on ref ptr
*
* Template instantiation must occur in two phases.
* First declare the template members (prototypes) using
* the TrackArray_Declare() operation anywhere these operations are
* needed.
* Then instantiate the template in one module using the
* TrackArray_Implement() operation.
*
* TrackArray_Declare() requires the specification of a name (1st arg) and
* a base type (2nd arg). The 1st arg is used in the function declarations
* to distinguish between differently-types function (e.g. Int), the 2nd
* specifies the actual storage type of an array element and may be either
* a primitive type or a compound type. The 2nd arg should not contain
* cv-modifiers (const, volatile) as that may result in compile-time
* errors and is not really desirable anyhow.
*
* TrackArray_Implement() requires the name provided in a previous Declare()
* operation (ie. its first arg).
*
* If TRACKARRAY_STORAGE is declared, it may be used to specify that
* an implementation should be made "inline", "extern", or "static".
* e.g. #define TRACKARRAY_STORAGE static inline
* TrackArray_Declare(Int, int)
* TrackArray_Implement(Int)
* #undef TRACKARRAY_STORAGE
*
* Declaring the operations as inline is safe and requires little
* additional overhead (in many cases, it may even reduce the effective
* code footprint) as the member functions are fairly trivial. There
* may be substantial gains from doing this, if at all possible.
*/
/*** TrackArrayIndirect "Template" ***/
/*
* The templates defined in these steps produce functions of
* the form TrackArrayIndirect[Operation]_[Type]. These template
* functions build upon the TrackArray templates to provide transparent
* access to members of an array of pointers. Specifically, this allows
* the user to construct an array of pointers to objects while adding
* and removing individual elements of the array as complete objects.
*
* Fundamentally, each operation prefixed with Indirect implies that the
* target of the operation is not the pointer type of the array, but
* the object type of the contents.
*
* The array is comprised of a set of pointers and a set of objects.
* By default, these objects are allocated as children of the array's
* base pointer, but they may be reassigned by the user to displace
* individual entitites. Similarly, it is legal for the user to directly
* modify the contents of the array of pointers so long as he ensures that
* ALL pointers are valid members or NULL.
*
*
*
* Summary of new operations:
*
* newArray = TrackArrayIndirectNew_[Type](parent, num)
* - creates an array linked to parent with initially num objects
* (array pointers reference new uninitialized objects)
*
* *elem = TrackArrayIndirectNewElem_[Type](parent)
* - creates storage for a new element of this array
*
* TrackArrayIndirectDelete_[Type](array)
* - deletes all individually-references objects of the array, then
* deletes array of pointers
*
* TrackArrayIndirectDeleteElem_[Type](elem)
* - frees the storage for an element of this array
*
* newArray = TrackArrayIndirectClone_[Type](array)
* - clones all individually-referenced objects of the array and
* attaches them to a new array with a newly built list of pointers
*
* success = TrackArrayIndirectResize_[Type](ptrarray, num)
* - resizes the array, creating/deleting objects at the tail as necessary
*
* success = TrackArrayEnsureStorageForElem_[Type](ptrarray, index)
* - ensures that element 'index' will fit, resizing if necessary
*
* size = TrackArrayIndirectGetSize_[Type](array)
* - returns number of elements in the array
*
* size = TrackArrayIndirectGetElemSize_[Type](array)
* - returns default size of the objects of the array in multiples of
* sizeof(char *)
*
* index = TrackArrayIndirectGetIndexByRef_[Type](array, *elem)
* - returns the index number of a given element by references as found
* by scanning the list of pointers for a matching element (ASSERT's on
* failure)
*
* *elem = TrackArrayIndirectAddLast_[Type](ptrarray, elemsource)
* *elem = TrackArrayIndirectAddLastByRef_[Type](ptrarray, *elemsource)
* - returns a reference to a new object added at the tail of the array
* (initializes with shallow-copy of elemsource if not NULL)
*
* *elem = TrackArrayIndirectInsertAt_[Type](ptrarray, index, elemsource)
* *elem = TrackArrayIndirectInsertAtByRef_[Type](ptrarray, index, *elemsource)
* - returns a reference to a new object inserted at position 'index'
* (initializes with shallow-copy of elemsource if not NULL)
*
* TrackArrayIndirectRemoveLast_[Type](ptrarray)
* - removes the last element and frees using TrackMemFree()
*
* TrackArrayIndirectRemoveAt_[Type](ptrarray)
* - removes the element at position 'index' and frees using TrackMemFree()
*
* *elem = TrackArrayIndirectInsertManyAt_[Type](ptrarray, index, count,
* *elemsource)
* - inserts a series of elements at position 'index' and initializes
* via shallow-copy from 'elemsource' which is a contiguous array of
* elements of same size, unless NULL
* <initialization unimplemented -- procedure may change>
*
* *elem = TrackArrayIndirectAppendMany_[Type](ptrarray, count, *elemsource)
* - add a series of elements to the tail of the array as if
* TrackArrayIndirectInsertManyAt_[Type]() had been called on that
* position.
* <initialization unimplemented -- procedure may change>
*
* TrackArrayIndirectRemoveManyAt_[Type](ptrarray, index, count)
* - removes a series of elements at position 'index' as if they had been
* iteratively removed by TrackArrayIndirectRemoveAt_[Type]().
*
* *elem = TrackArrayIndirectElemAt_[Type](array, index)
* - returns a pointer to the object of the element at a particular index
*
* *elem = TrackArrayIndirectElemFirst_[Type](array)
* - returns a pointer to the first object
*
* *elem = TrackArrayIndirectElemLast_[Type](array)
* - returns a pointer to the last object
*
*** Maybe someday someone will get around to completing this interface... ***
*/
APS still only incompletely uses the library for memory management purposes but is in the process of being gently migrated wherever appropriate. Nevertheless, all allocation which, directly or indirectly, are returned to the user are managed by the library. Please note, Aps_ReleaseBuffer() only understands TrackMem constructs. Please use Aps_ReleaseBuffer() only for things which are supplied by high-level API functions or by functions which provide services to these functions. Similarly, for internal uses of TrackMem, you should use the explicit destructor calls which provide type-checking.
Blocks consist of three chunks:
Tag space is of variable size and contains any tags that have been linked to this object by the user. The size of tag space is guaranteed to fall on a native alignment boundary. Tags consist of a list of TrackMem_Tag structures defined in trackmem.c. The maximum size of tag space is < 65536 bytes.
Admin space is of fixed size and contains all necessary information for the module to perform its resource-tracking duties. The size of admin space is guaranteed to fall on a native alignment boundary. The structure stored here is defined by TrackMem_Block in trackmem.c.
User space is of arbitrary size and is of variable size. It has no fixed upper or lower bound on size: 0 is a valid minimal size and represents a distinct entity. Upon allocation the user receives a pointer to the current base of user space (it is not fixed!). The library performs simple pointer arithmetic to obtain a pointer to Admin space.
N.B. The physical layout of these blocks is defined by the concatenation of Tag, Admin and User space (in that order).
Corel Corporation
Linux Printing (APS) Development Team
April 2000.