TsctlArray

From embeddedTS Manuals

The tsctl library provides the Array data structure and functions for manipulating Arrays.

We use case to distinguish between a C array (lower case) and a libtsctl Array (upper case). An Array looks just like a C pointer, so as a convention we try to distinguish it by attaching the pointer symbol directly to the type, e.g. "char* x" while attaching it to the variable name for a regular C pointer, e.g. "char *x".

The Array can be treated just like a C pointer in most cases. You can pass it to C functions which have no knowledge of the Array type. An implicitly created null element follows the last element of every Array, so functions which expect null-terminated C strings will work on char* Arrays. You can also use pointers to iterate forward through an Array, testing for the null terminator to find the end (unless your array contains null values). Just like C arrays you should not try to access elements before the first or after the last.

However, similar to a C array, the Array pointer is special. When calling Array functions, you must pass the pointer to the start of the Array, not a pointer to another element in the Array. If you iterate backwards using a pointer you must test against the Array pointer itself, since there is no null marker before the first element.

The Array type is designed with embedded systems in mind. The Array functions are common to all Arrays, regardless of element type, and take and return void pointers to the Array and element values. Therefore, there are a small number of functions to learn. All functions are static inline and rely on the memxxx string functions, which generally should result in code that is quite efficient. Internally, Arrays are length delimited, eliminating the need to iterate across the entire length of the Array just to determine its length. The basic string.h functions (strcmp, strncmp, strdup, strlen, strcpy) can be trivially replaced with Array function calls, but since they are generic to all Arrays they are not just limited to strings.

Functional Grouping

Convenience Macros

A(type,value)

This macro constructs a pointer of type to the given value. Array functions which put values into the Array or search the array for a value require a pointer to the value in question. However, sometimes it is desirable to use literal values. This macro makes it possible to do either in a uniform way. Example:

   char *str = ASCIIZ("1234");
   char x = '5'
   str = ArrayAppend(str,A(char,'5')); // directly append a char to the array
   str = ArrayAppend(str,A(char,x)); // append a char from a char variable to the array
   str = ArrayAppend(str,&x); // same as previous statement

ARR(...)

This macro constructs a literal for initializing an Array. The parameters are the elements of the Array. Example:

   ArrayAuto(char,str,ARR("abc123")); // { 'a', 'b', 'c', '1', '2', '3' }
   ArrayAuto(int,iarr,ARR(1,2,3)); // { 1, 2, 3 }

Of(...)

This macro is required whenever comma separated arguments are to be used as the value parameter to the A macro. This is because otherwise the pre-processor would mistakenly interpret the arguments as additional arguments to the A macro, instead of being part of the value parameter. Example:

   struct x { int a, b; };
   // ...
   xarr = ArrayInsert(xarr,A(struct x,Of(1,2)));
   //  inserts an element containing { .a=1, .b=2 }


Allocation

void *ArrayAlloc(unsigned count,unsigned elementBytes);

Dynamically allocates an uninitialized Array with count elements each elementBytes in size. Returns a pointer to the Array.

void ArrayFree(void *arr);

Frees the dynamically allocated Array pointed to by arr, which must have been previously returned by an allocating function.

void *ArraySize(void *arr,unsigned count);

Resizes the Array pointed to by arr, which must have been previously returned by an allocating function, to have count elements. Returns a new pointer to the Array, after which the previous pointer arr is no longer valid.

void *ArraySizeAuto(void *arr,unsigned count);

The function changes the size of the Array arr without actually changing its allocation. This is useful for changing the length of an Array allocated with one of the Auto functions, but it can also be used with a dynamically allocated array. The pointer returned will always be the same pointer passed.

char *ASCIIZ(const char *str);

Dynamically allocates a char* Array, initializing it with the null-terminate C string passed. Returns a pointer to the char* Array.

ArrayAuto(type,name,value);

This macro can be used either to create a global variable Array (when used outside of a function) or a local variable Array (when used inside a function), with the corresponding scope. The type is the C type of the array, such as "char", "int", etc. The name is name of the (pointer) variable to be created to the Array. The value is the initial value for the array. If the value is a C string, the length of the array will include the null terminator character.

ArrayAuto0(type,name,value);

This macro is similar to ArrayAuto. It is intended to be used for initializing from C strings. The only difference from ArrayAuto is that the length of the array will NOT include the null terminator character.

ArrayAutoOfSize(type,name,size);

This macro is similar to ArrayAuto. However, instead of creating an initialized array with a given value, it instead creates an uninitialized array of the specified size.

ASCIIZLocal(str);

Do not use this macro, as it relies on the scope of a declaration within an expression being defined. It apparently is not - this macro will work properly with some compilers but not with others.

This macro is used to initialize a local char* array initialized from a null-terminated C string. It "returns" a char*, and so should must be assigned to a local variable of that type to be useful. Example:

   int func() {
       char *str = ASCIIZLocal("abc123");
       ...


void *ArrayDup(void *arr);

This function dynamically allocates a new Array which is identical in element count and element size to the Array arr, and initializes each element to have the same value as the corresponding element in arr.

Introspection

unsigned ArrayElementSize(const void *arr);

This function returns the byte length of each element in the Array arr.

unsigned ArrayLength(const void *arr);

This function returns the number of elements in the Array arr.

void *ArrayCompareFunction(const void *arr);

This function returns the comparison function for the Array arr.

Normalization

unsigned ArrayIndex(void *arr,int index);

The function normalizes the index for the specified Array arr. A negative index references elements starting with -1 for the last element, -2 for the next to last element, etc. If the normalized index is before the first element, 0 is returned to reference the first element. A positive index beyond the last element of the array (ArrayLength(arr)-1) is normalized to the last element in the array.

Sets

void *ArrayJoin(void *arr1,void *arr2);

This function creates and returns a new Array which contains the contents of the arr2 concatenated to the contents of arr1. The original array arr1 and arr2 are unchanged.

void *ArrayRange(void *arr,int index1,int index2);

This function creates and returns a new Array which contains a subset of the original Array arr. It will contain elements index1 to index2 of arr, inclusively. Both indicies will be automatically normalized by the function before use.

Comparison

int ArrayCompare(const void *arr1,const void *arr2);

This function compares the two Arrays passed and returns a positive number if arr1 > arr2, a negative number if arr1 < arr2, and 0 if the two Arrays have identical contents.

int ArrayCompare1(const void *arr1,const void *arr2);

This function is similar to ArrayCompare(). The only difference is that the comparison is done only for the length of arr1.

Insertion and Removal

void *ArrayAfter(void *arr,unsigned index,void *value);

This function inserts an element into Array arr after the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayBefore(void *arr,unsigned index,void *value);

This function inserts an element into Array arr before the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayPush(void *arr,void *value);

This function inserts an element into Array arr before the first element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayQueue(void *arr,void *value);

This function inserts an element into Array arr after the last element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayDelete(void *arr,int index,unsigned len);

This function deletes the number of elements specified by len from the Array arr, starting at the element normalized from the index specified. The new pointer to the Array is returned.

void *ArrayPop(void *arr,void *value);

This function copies the value of the first element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

void *ArrayPull(void *arr,void *value);

This function copies the value of the last element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

Searching, Sorting and Sorted Insertion/Replacement

void ArraySort(void *arr,int (*Compare)(const void *,const void *));

The Array arr is sorted in place using the comparison function Compare, which must return positive if the first element is greater than the second, negative if the first element is less than the second, or zero if the two elements are equal. The comparison function is retained internally by the Array. If a null pointer is passed for Compare, the comparison function is effectively removed (marking the Array as un-sorted), and no sorting is done.

unsigned ArrayFind(void *arr,void *value);

The Array arr is searched for element with a value equal to that pointed to by value. The internally retained comparison function is used, so the Array must first be sorted before this function can be called. The return value is the index in the array where the specified value would be inserted to keep the Array sorted. To determine if an exact match was found, apply the comparison function to the element at the index returned and the value passed to test for equality.

void *ArrayFindEq(void *arr,void *value);

The Array arr is searched for element with a value equal to that pointed to by value. The internally retained comparison function is used, so the Array must first be sorted before this function can be called. If the element matching the value is found, a pointer to the element is returned. Otherwise, null is returned.

unsigned ArrayFindWith(void *arr,void *value, int (*Compare)(const void *,const void *));

This function is similar to the ArrayFind() function. The only difference is that the specified comparison function Compare is used instead of the internally retained function. The passed function must be compatible with the internally retained function. In practice what this means is that since the Array is sorted using the internally retained function and a binary search is performed, the passed function must adhere to the same sort order.

void *ArrayInsert(void *arr,void *value);

This function is only valid on a sorted Array. The value pointed to by value is copied to the Array, into an element inserted such that the Array remains sorted.

void *ArrayReplace(void *arr,void *value);

This function is only valid on a sorted Array. The function is similar to ArrayInsert(). The only difference is that if the value is already found in the array, it is replaced by the search value, instead of a new element being inserted. If the value is not found, it is inserted.

void *ArrayReplaceWith(void *arr,void *value,int (*Compare)(const void *,const void *));

This function is similar to ArrayReplace(). The only difference is that the the text to determine whether to insert or replace is done with the passed comparison function Compare, instead of the internally retained function.

void *ArrayFindDelete(void *arr,void *value);

The function is only valid on a sorted Array. It searched for an element equal to the value pointed to by value. If the element is found, it is deleted. Otherwise, the array is unchanged. The new pointer to the Array is returned.

Alphabetical

A(type,value)

This macro constructs a pointer of type to the given value. Array functions which put values into the Array or search the array for a value require a pointer to the value in question. However, sometimes it is desirable to use literal values. This macro makes it possible to do either in a uniform way. Example:

   char *str = ASCIIZ("1234");
   char x = '5'
   str = ArrayAppend(str,A(char,'5')); // directly append a char to the array
   str = ArrayAppend(str,A(char,x)); // append a char from a char variable to the array
   str = ArrayAppend(str,&x); // same as previous statement

ARR(...)

This macro constructs a literal for initializing an Array. The parameters are the elements of the Array. Example:

   ArrayAuto(char,str,ARR("abc123")); // { 'a', 'b', 'c', '1', '2', '3' }
   ArrayAuto(int,iarr,ARR(1,2,3)); // { 1, 2, 3 }

void *ArrayAfter(void *arr,unsigned index,void *value);

This function inserts an element into Array arr after the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayAlloc(unsigned count,unsigned elementBytes);

Dynamically allocates an uninitialized Array with count elements each elementBytes in size. Returns a pointer to the Array.

ArrayAuto(type,name,value);

This macro can be used either to create a global variable Array (when used outside of a function) or a local variable Array (when used inside a function), with the corresponding scope. The type is the C type of the array, such as "char", "int", etc. The name is name of the (pointer) variable to be created to the Array. The value is the initial value for the array. If the value is a C string, the length of the array will include the null terminator character.

ArrayAuto0(type,name,value);

This macro is similar to ArrayAuto. It is intended to be used for initializing from C strings. The only difference from ArrayAuto is that the length of the array will NOT include the null terminator character.

ArrayAutoOfSize(type,name,size);

This macro is similar to ArrayAuto. However, instead of creating an initialized array with a given value, it instead creates an uninitialized array of the specified size.

void *ArrayBefore(void *arr,unsigned index,void *value);

This function inserts an element into Array arr before the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

int ArrayCompare(const void *arr1,const void *arr2);

This function compares the two Arrays passed and returns a positive number if arr1 > arr2, a negative number if arr1 < arr2, and 0 if the two Arrays have identical contents.

int ArrayCompare1(const void *arr1,const void *arr2);

This function is similar to ArrayCompare(). The only difference is that the comparison is done only for the length of arr1.

void *ArrayCompareFunction(const void *arr);

This function returns the comparison function for the Array arr.

void *ArrayDelete(void *arr,int index,unsigned len);

This function deletes the number of elements specified by len from the Array arr, starting at the element normalized from the index specified. The new pointer to the Array is returned.

void *ArrayDup(void *arr);

This function dynamically allocates a new Array which is identical in element count and element size to the Array arr, and initializes each element to have the same value as the corresponding element in arr.

unsigned ArrayElementSize(const void *arr);

This function returns the byte length of each element in the Array arr.

unsigned ArrayFind(void *arr,void *value);

The Array arr is searched for element with a value equal to that pointed to by value. The internally retained comparison function is used, so the Array must first be sorted before this function can be called. The return value is the index in the array where the specified value would be inserted to keep the Array sorted. To determine if an exact match was found, apply the comparison function to the element at the index returned and the value passed to test for equality.

void *ArrayFindDelete(void *arr,void *value);

The function is only valid on a sorted Array. It searched for an element equal to the value pointed to by value. If the element is found, it is deleted. Otherwise, the array is unchanged. The new pointer to the Array is returned.

void *ArrayFindEq(void *arr,void *value);

The Array arr is searched for element with a value equal to that pointed to by value. The internally retained comparison function is used, so the Array must first be sorted before this function can be called. If the element matching the value is found, a pointer to the element is returned. Otherwise, null is returned.

unsigned ArrayFindWith(void *arr,void *value, int (*Compare)(const void *,const void *));

This function is similar to the ArrayFind() function. The only difference is that the specified comparison function Compare is used instead of the internally retained function. The passed function must be compatible with the internally retained function. In practice what this means is that since the Array is sorted using the internally retained function and a binary search is performed, the passed function must adhere to the same sort order.

void ArrayFree(void *arr);

Frees the dynamically allocated Array pointed to by arr, which must have been previously returned by an allocating function.

unsigned ArrayIndex(void *arr,int index);

The function normalizes the index for the specified Array arr. A negative index references elements starting with -1 for the last element, -2 for the next to last element, etc. If the normalized index is before the first element, 0 is returned to reference the first element. A positive index beyond the last element of the array (ArrayLength(arr)-1) is normalized to the last element in the array.

void *ArrayInsert(void *arr,void *value);

This function is only valid on a sorted Array. The value pointed to by value is copied to the Array, into an element inserted such that the Array remains sorted.

void *ArrayJoin(void *arr1,void *arr2);

This function creates and returns a new Array which contains the contents of the arr2 concatenated to the contents of arr1. The original array arr1 and arr2 are unchanged.

unsigned ArrayLength(const void *arr);

This function returns the number of elements in the Array arr.

void *ArrayPop(void *arr,void *value);

This function copies the value of the first element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

void *ArrayPull(void *arr,void *value);

This function copies the value of the last element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

void *ArrayPush(void *arr,void *value);

This function inserts an element into Array arr before the first element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayQueue(void *arr,void *value);

This function inserts an element into Array arr after the last element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayRange(void *arr,int index1,int index2);

This function creates and returns a new Array which contains a subset of the original Array arr. It will contain elements index1 to index2 of arr, inclusively. Both indicies will be automatically normalized by the function before use.

void *ArrayReplace(void *arr,void *value);

This function is only valid on a sorted Array. The function is similar to ArrayInsert(). The only difference is that if the value is already found in the array, it is replaced by the search value, instead of a new element being inserted. If the value is not found, it is inserted.

void *ArrayReplaceWith(void *arr,void *value,int (*Compare)(const void *,const void *));

This function is similar to ArrayReplace(). The only difference is that the the text to determine whether to insert or replace is done with the passed comparison function Compare, instead of the internally retained function.

void *ArraySize(void *arr,unsigned count);

Resizes the Array pointed to by arr, which must have been previously returned by an allocating function, to have count elements. Returns a new pointer to the Array, after which the previous pointer arr is no longer valid.

void *ArraySizeAuto(void *arr,unsigned count);

The function changes the size of the Array arr without actually changing its allocation. This is useful for changing the length of an Array allocated with one of the Auto functions, but it can also be used with a dynamically allocated array. The pointer returned will always be the same pointer passed.

void ArraySort(void *arr,int (*Compare)(const void *,const void *));

The Array arr is sorted in place using the comparison function Compare, which must return positive if the first element is greater than the second, negative if the first element is less than the second, or zero if the two elements are equal. The comparison function is retained internally by the Array. If a null pointer is passed for Compare, the comparison function is effectively removed (marking the Array as un-sorted), and no sorting is done.

char *ASCIIZ(const char *str);

Dynamically allocates a char* Array, initializing it with the null-terminate C string passed. Returns a pointer to the char* Array.

ASCIIZLocal(str);

Do not use this macro, as it relies on the scope of a declaration within an expression being defined. It apparently is not - this macro will work properly with some compilers but not with others.

This macro is used to initialize a local char* array initialized from a null-terminated C string. It "returns" a char*, and so should must be assigned to a local variable of that type to be useful. Example:

   int func() {
       char *str = ASCIIZLocal("abc123");
       ...

Of(...)

This macro is required whenever comma separated arguments are to be used as the value parameter to the A macro. This is because otherwise the pre-processor would mistakenly interpret the arguments as additional arguments to the A macro, instead of being part of the value parameter. Example:

   struct x { int a, b; };
   // ...
   xarr = ArrayInsert(xarr,A(struct x,Of(1,2)));
   //  inserts an element containing { .a=1, .b=2 }



Allocating Functions

Only pointers returned by any of the allocating functions may be passed to ArraySize() or ArrayFree(). All pointers returned by these functions must be passed to ArrayFree() before they go out of scope to avoid leaking memory, unless they are subsequently passed to an altering function in which case the above applies to the returned pointer as the original pointer is invalid.

The following functions allocate a new Array:

void *ArrayAlloc(unsigned count,unsigned elementBytes);

Dynamically allocates an uninitialized Array with count elements each elementBytes in size. Returns a pointer to the Array.

char *ASCIIZ(const char *str);

Dynamically allocates a char* Array, initializing it with the null-terminate C string passed. Returns a pointer to the char* Array.

void *ArrayDup(void *arr);

This function dynamically allocates a new Array which is identical in element count and element size to the Array arr, and initializes each element to have the same value as the corresponding element in arr.

void *ArrayJoin(void *arr1,void *arr2);

This function creates and returns a new Array which contains the contents of the arr2 concatenated to the contents of arr1. The original array arr1 and arr2 are unchanged.

void *ArrayRange(void *arr,int index1,int index2);

This function creates and returns a new Array which contains a subset of the original Array arr. It will contain elements index1 to index2 of arr, inclusively. Both indicies will be automatically normalized by the function before use.


The following functions alter the allocation of an existing array and thus return a new Array. The return value should be assigned to the variable passed as the array to each function.

void *ArraySize(void *arr,unsigned count);

Resizes the Array pointed to by arr, which must have been previously returned by an allocating function, to have count elements. Returns a new pointer to the Array, after which the previous pointer arr is no longer valid.

void *ArrayAfter(void *arr,unsigned index,void *value);

This function inserts an element into Array arr after the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayBefore(void *arr,unsigned index,void *value);

This function inserts an element into Array arr before the specified normalized index obtained from index. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayPush(void *arr,void *value);

This function inserts an element into Array arr before the first element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayQueue(void *arr,void *value);

This function inserts an element into Array arr after the last element. The value of the element is copied from the value pointer passed. The new pointer to the Array is returned.

void *ArrayDelete(void *arr,int index,unsigned len);

This function deletes the number of elements specified by len from the Array arr, starting at the element normalized from the index specified. The new pointer to the Array is returned.

void *ArrayPop(void *arr,void *value);

This function copies the value of the first element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

void *ArrayPull(void *arr,void *value);

This function copies the value of the last element of the Array arr to the location pointed to by value, and then deletes it from the array. The new pointer to the Array is returned.

void *ArrayInsert(void *arr,void *value);

This function is only valid on a sorted Array. The value pointed to by value is copied to the Array, into an element inserted such that the Array remains sorted.

void *ArrayReplace(void *arr,void *value);

This function is only valid on a sorted Array. The function is similar to ArrayInsert(). The only difference is that if the value is already found in the array, it is replaced by the search value, instead of a new element being inserted. If the value is not found, it is inserted.

void *ArrayReplaceWith(void *arr,void *value,int (*Compare)(const void *,const void *));

This function is similar to ArrayReplace(). The only difference is that the the text to determine whether to insert or replace is done with the passed comparison function Compare, instead of the internally retained function.

void *ArrayFindDelete(void *arr,void *value);

The function is only valid on a sorted Array. It searched for an element equal to the value pointed to by value. If the element is found, it is deleted. Otherwise, the array is unchanged. The new pointer to the Array is returned.