Memory Tracking and Arrays

Abstract

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.

1. TrackMem

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.

Example Problems:

  1. A structure contains pointers to other objects (e.g. strings) which must be disposed of when this structure is freed.  To make matters worse, the structure contains pointers to other compound types (e.g. a tuple) containing references to data that must also be disposed of.
    Solution:
    Associate data referenced by the structure and all related components to its most immediate "parent".  For instance, associate references owned by the tuple member to the tuple, and associate all member pointers of the structure -- including the pointer to the tuple -- with the structure.
  2. As you rely on certain library functions which allocate memory, you would like to wrap an existing allocation and link it to a memory tracking tree.
    Solution:
    Create a link to the object you wish to allocate.  If releasing this object is a delicate task or requires more than calling the default destructor (stdlib free()), set up an appropriate destructor function too.
  3. Freeing a certain object is not as straightforward as releasing all memory allocations.
    Solution:
    At the moment it is only possible to set destructors for links.  Create a dummy link as a child of an allocation and set up an appropriate destructor.
  4. In the course of some data-manipulating operation, we would like to ensure that failure conditions are trapped and that all consumed resources are released.  Since we trap multiple conditions, we want to keep the error-recovery process as simple as possible.
    Solution:
    Link all temporary data together logically such that memory cleanup involves only a single function call to free them.  Procedural cleanup of selected objects can be performed by creating links to these objects and setting up appropriate destructors.
  5. You wish to hide private administrative data in some allocation so that a user will not be able to touch it.
    Solution:
    Add a variable number of tags to the object to hold your administrative data blocks.  To retrieve it them, use the appropriate functions.  These admin blocks will be released automatically and though they are not considered children.

2. TrackArray

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.

Example Problems:

  1. You are building an array of string pointers to return to a user, therefore your array contains 'char *' type objects.  You want to ensure that all strings are freed when the array is disposed of.
    Solution:
    Declare a template for arrays of 'char *'.  Allocate the strings using TrackMem primitives with the array base pointer as parent.
  2. You are building an array of objects dynamically containing an indeterminate number of objects.
    Solution:
    Declare an appropriate template array type.  Use the Add() and Insert() operations to fill in the array.  TrackArray will ensure that the array is extended as efficiently as possible.
  3. You want to pass a TrackArray off as a normal array.
    Solution:
    No problem.  The base pointer may be used directly.
  4. You want to clearly identify which pointers represent normal arrays and which represent TrackArrays.
    Solution:
    Use the TrackArray_[type] typedefs for array base pointers, and/or TrackArrayElem_[type] typedefs for array elements.

3. TrackArrayIndirect

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.

  1. You must construct an array of pointers to equally-sized objects for use by the calling function.  The calling function is unaware of any special background processing and is instructed to explicitly call some other function to free the array it got.  You are only manipulating small amounts of data or would benefit more from random access than you would from using a list or other container.
    Solution:
    Declare an appropriate template type, then build your array using TrackArrayIndirect primitives.  When finished, return the base pointer to a caller as (MyType *)[].  The destructor function can be generic: it need not know the process used to construct the array and can free it by directly calling TrackMem.

1.0 TrackMem Interface

1.1 TrackMemAlloc()

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.

Input

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.

Output

Returns a pointer to a new TrackMem object of specified size, or NULL on failure.


1.2 TrackMemClone()

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.

Input

memParent Pointer to the TrackMem object to use as parent of new allocation.
memSource Pointer to the TrackMem object to clone.

Output

Returns a pointer to a new TrackMem object consisting of an exact duplicate of the specified source object, or NULL on failure.

Remarks

This operation DOES NOT clone or reassign the children of the source object.


1.3 TrackMemDupMemory()

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.

Input

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.

Output

Returns a pointer to a new TrackMem object containing an exact duplicate of the source buffer in user space, or NULL on failure.


1.4 TrackMemDupString()

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.

Input

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.

Output

Returns a pointer to a new TrackMem object containing an exact duplicate of the source string in user space, or NULL on failure.


1.5 TrackMemLink()

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().

Input

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.

Output

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.

Remarks

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.


1.6 TrackMemRealloc()

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.

Input

mem Pointer to the TrackMem object to resize.
size Desired new size of user data space.

Output

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.

Remarks

This function behaves differently with LINKs.  Please refer to TrackMemLink().


1.7 TrackMemReallocTagSpace()

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().

Input

mem Pointer to the TrackMem object whose tag space is to be resized.
sizeTags Desired new size of tag space.

Output

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.

Remarks

This function has no effect on the contents or location of a LINK.


1.8 TrackMemFree()

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.

Input

mem Pointer to the TrackMem object to be freed.

Remarks

This function behaves differently with LINKs.  Please refer to TrackMemLink().


1.9 TrackMemFreeChildren()

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.

Input

mem Pointer to the TrackMem object whose children are to be freed.

Remarks

This function behaves differently with LINKs.  Please refer to TrackMemLink().


1.10 TrackMemUnlink()

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()).

Input

mem Pointer to the TrackMem object to be "unlinked".

Output

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.

Remarks

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.


1.11 TrackMemReassign()

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.

Input

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.

1.12 TrackMemReassignChildren()

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.

Input

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.

1.13 TrackMemGetData()

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.

Input

mem Pointer to the TrackMem object to examine.

Output

Returns a pointer to the target data controlled by the selected TrackMem object.

Remarks

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.


1.14 TrackMemGetParent()

TMEM void *TrackMemGetParent(
    const TMEM void *mem);

Locate the parent of this TrackMem object and return a pointer to it.

Input

mem Pointer to the TrackMem object to examine.

Output

Returns the address of the TrackMem object functioning as the parent of this object.


1.15 TrackMemGetSize()

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.

Input

mem Pointer to the TrackMem object to examine.

Output

Returns a size_t representing the size of the allocation this object refers to, in bytes.


1.16 TrackMemGetTagSpaceSize()

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().

Input

mem Pointer to the TrackMem object to examine.

Output

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.


1.17 TrackMemTagSet()

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.

Input

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.

Output

Returns a pointer to the user tag storage buffer which has been allocated, or NULL on failure.  The storage buffer is not initialised.

Remarks

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.


1.18 TrackMemTagAdd()

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.

Input

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.

Output

Returns a pointer to the user tag storage buffer which has been allocated, or NULL on failure.  The storage buffer is not initialised.

Remarks

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.


1.19 TrackMemTagFind()

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().

Input

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.

Output

Returns a pointer to the tag storage space, or NULL if no tag of the specified type was found.

Remarks

The volatility and lifetime of tag storage pointers is the same as those for their host TrackMem object.


1.20 TrackMemTagSetLinkDestructor()

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.

Input

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).

Output

Returns TRUE if the destructor was added successfully, else returns FALSE.

Remarks

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)


1.21 TrackMemTagUnset()

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.

Input

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.

2.0 TrackArray Interface

2.1 TrackArrayNew()

TrackArray *TrackArrayNew(
    TMEM void *memParent,
    size_t     size,
    int        initial);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.2 TrackArrayClone()

TrackArray *TrackArrayClone(
    TMEM void  *memParent,
    TrackArray *arraySource);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.3 TrackArrayDelete()

void TrackArrayDelete(
    TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.4 TrackArrayUnlink()

void *TrackArrayUnlink(
    TrackArray *arraySource);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.5 TrackArrayResize()

int TrackArrayResize(
    TrackArray **array,
    int          numElems);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.6 TrackArrayEnsureStorageForElem()

void TrackArrayEnsureStorageForElem(
    TrackArray **array,
    int          elemIndex);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.7 TrackArrayGetSize()

int TrackArrayGetSize(
    const TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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).

*/


2.8 TrackArrayGetElemSize()

size_t TrackArrayGetElemSize(
    const TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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 *).)

*/


2.9 TrackArrayGetIndexByRef()

int TrackArrayGetIndexByRef(
    const TrackArray *array,
    const void       *elemRef);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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);

*/


2.10 TrackArrayGetElemByRef()

void TrackArrayGetElemByRef(
    const TrackArray *array,
    const void       *elemRef,
    void             *targetBuffer);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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

*/


2.11 TrackArraySetElemByRef()

void TrackArraySetElemByRef(
    TrackArray *array,
    void       *elemRef,
    const void *sourceBuffer);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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

*/


2.12 TrackArrayAddLast()

void *TrackArrayAddLast(
    TrackArray **array,
    const void  *sourceBuffer);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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().

*/


2.14 TrackArrayRemoveLast()

void TrackArrayRemoveLast(
    TrackArray **array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.15 TrackArrayInsertAt()

void TrackArrayInsertAt(
    TrackArray **array,
    int          elemIndex,
    const void  *sourceBuffer);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.16 TrackArrayRemoveAt()

void TrackArrayRemoveAt(
    TrackArray **array,
    int          elemIndex);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.17 TrackArrayInsertManyAt()

void *TrackArrayInsertManyAt(
    TrackArray *array,
    int         elemFirstIndex,
    int         elemCount,
    const void *sourceArray);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.18 TrackArrayAppendMany()

void *TrackArrayAppendMany(
    TrackArray **array,
    int          elemCount,
    const void  *sourceArray);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.19 TrackArrayRemoveManyAt()

void TrackArrayRemoveManyAt(
    TrackArray **array,
    int          elemFirstIndex,
    int          elemCount);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.20 TrackArrayGetManyAt()

void TrackArrayGetManyAt(
    const TrackArray *array,
    int               elemFirstIndex,
    int               elemCount,
    void             *targetArray);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.21 TrackArraySetManyAt()

void TrackArraySetManyAt(
    TrackArray **array,
    int          elemFirstIndex,
    int          elemCount,
    const void  *targetArray);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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)

*/


2.22 TrackArrayElemAt()

void *TrackArrayElemAt(
    const TrackArray *array,
    int               elemIndex);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*

*/


2.23 TrackArrayElemFirst()

void *TrackArrayElemFirst(
    const TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.24 TrackArrayElemLast()

void *TrackArrayElemLast(
    const TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.25 TrackArrayElemEndMark()

void *TrackArrayElemEndMark(
    const TrackArray *array);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.26 TrackArrayElemNext()

void *TrackArrayElemNext(
    const TrackArray *array,
    const void       *elemRef);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


2.27 TrackArrayElemSkip()

void *TrackArrayElemSkip(
    const TrackArray *array,
    const void       *elemRef,
    int               elemSkipCount);

Input

array Base pointer of the TrackArray to manipulate.
memSource Initial size of user data we want to store here.

Output

Remarks

 

 

/* ---------------------------------------------------------------------------

* 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.

*/


Template Interfaces

****** 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(...)).

1. TrackArray

 

 

/*** 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.

*/

2. TrackArrayIndirect

 

 

/*** 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 w.r.t. TrackMem

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.

Implementation Notes

Allocation Scheme

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).

Techniques Used to Improve Efficiency

Debugging Facilities

Limitations

Future

Corel Corporation
Linux Printing (APS) Development Team
April 2000.