jpayne@69: /* jpayne@69: * tkArray.h -- jpayne@69: * jpayne@69: * An array is a sequence of items, stored in a contiguous memory region. jpayne@69: * Random access to any item is very fast. New items can be either appended jpayne@69: * or prepended. An array may be traversed in the forward or backward direction. jpayne@69: * jpayne@69: * Copyright (c) 2018-2019 by Gregor Cramer. jpayne@69: * jpayne@69: * See the file "license.terms" for information on usage and redistribution of jpayne@69: * this file, and for a DISCLAIMER OF ALL WARRANTIES. jpayne@69: */ jpayne@69: jpayne@69: /* jpayne@69: * Note that this file will not be included in header files, it is the purpose jpayne@69: * of this file to be included in source files only. Thus we are not using the jpayne@69: * prefix "Tk_" here for functions, because all the functions have private scope. jpayne@69: */ jpayne@69: jpayne@69: /* jpayne@69: * ------------------------------------------------------------------------------- jpayne@69: * Use the array in the following way: jpayne@69: * ------------------------------------------------------------------------------- jpayne@69: * typedef struct { int key, value; } Pair; jpayne@69: * TK_PTR_ARRAY_DEFINE(MyArray, Pair); jpayne@69: * MyArray *arr = NULL; jpayne@69: * if (MyArray_IsEmpty(arr)) { jpayne@69: * MyArray_Append(&arr, MakePair(1, 2)); jpayne@69: * MyArray_Append(&arr, MakePair(2, 3)); jpayne@69: * for (i = 0; i < MyArray_Size(arr); ++i) { jpayne@69: * Pair *p = MyArray_Get(arr, i); jpayne@69: * printf("%d -> %d\n", p->key, p->value); jpayne@69: * ckfree(p); jpayne@69: * } jpayne@69: * MyArray_Free(&arr); jpayne@69: * assert(arr == NULL); jpayne@69: * } jpayne@69: * ------------------------------------------------------------------------------- jpayne@69: * Or with aggregated elements: jpayne@69: * ------------------------------------------------------------------------------- jpayne@69: * typedef struct { int key, value; } Pair; jpayne@69: * TK_ARRAY_DEFINE(MyArray, Pair); jpayne@69: * Pair p1 = { 1, 2 }; jpayne@69: * Pair p2 = { 2, 3 }; jpayne@69: * MyArray *arr = NULL; jpayne@69: * if (MyArray_IsEmpty(arr)) { jpayne@69: * MyArray_Append(&arr, p1); jpayne@69: * MyArray_Append(&arr, p2); jpayne@69: * for (i = 0; i < MyArray_Size(arr); ++i) { jpayne@69: * const Pair *p = MyArray_Get(arr, i); jpayne@69: * printf("%d -> %d\n", p->key, p->value); jpayne@69: * } jpayne@69: * MyArray_Free(&arr); jpayne@69: * assert(arr == NULL); jpayne@69: * } jpayne@69: * ------------------------------------------------------------------------------- jpayne@69: */ jpayne@69: jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Two array types will be provided: jpayne@69: * Use TK_ARRAY_DEFINE if your array is aggregating the elements. Use jpayne@69: * TK_PTR_ARRAY_DEFINE if your array contains pointers to elements. But jpayne@69: * in latter case the array is not responsible for the lifetime of the jpayne@69: * elements. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_ElemSize: Returns the memory size for one array element. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_BufferSize: Returns the memory size for given number of elements. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_IsEmpty: Array is empty? jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Size: Number of elements in array. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Capacity: Capacity of given array. This is the maximal number of jpayne@69: * elements fitting into current array memory without resizing the buffer. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_SetSize: Set array size, new size must not exceed the capacity of jpayne@69: * the array. This function has to be used with care when increasing the jpayne@69: * array size. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_First: Returns position of first element in array. Given array jpayne@69: * may be NULL. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Last: Returns position after last element in array. Given array jpayne@69: * may be empty. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Front: Returns first element in array. Given array must not be jpayne@69: * empty. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Back: Returns last element in array. Given array must not be jpayne@69: * empty. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Resize: Resize buffer of array for given number of elements. The jpayne@69: * array may grow or shrink. Note that this function is not initializing jpayne@69: * the increased buffer. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_ResizeAndClear: Resize buffer of array for given number of jpayne@69: * elements. The array may grow or shrink. The increased memory will be jpayne@69: * filled with zeroes. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Clear: Fill specified range with zeroes. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Free: Resize array to size zero. This function will release the jpayne@69: * array buffer. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Append: Insert given element after end of array. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_PopBack: Shrink array by one element. Given array must not be jpayne@69: * empty. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Get: Random access to array element at given position. The given jpayne@69: * index must not exceed current array size. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Set: Replace array element at given position with new value. The jpayne@69: * given index must not exceed current array size. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: /* jpayne@69: * Array_Find: Return index position of element which matches given jpayne@69: * argument. If not found then -1 will be returned. jpayne@69: */ jpayne@69: /*************************************************************************/ jpayne@69: jpayne@69: #ifndef TK_ARRAY_DEFINED jpayne@69: #define TK_ARRAY_DEFINED jpayne@69: jpayne@69: #include "tkInt.h" jpayne@69: jpayne@69: #if defined(__GNUC__) || defined(__clang__) jpayne@69: # define __TK_ARRAY_UNUSED __attribute__((unused)) jpayne@69: #else jpayne@69: # define __TK_ARRAY_UNUSED jpayne@69: #endif jpayne@69: jpayne@69: #define TK_ARRAY_DEFINE(AT, ElemType) /* AT = type of array */ \ jpayne@69: /* ------------------------------------------------------------------------- */ \ jpayne@69: typedef struct AT { \ jpayne@69: size_t size; \ jpayne@69: size_t capacity; \ jpayne@69: ElemType buf[1]; \ jpayne@69: } AT; \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Init(AT *arr) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: arr->size = 0; \ jpayne@69: arr->capacity = 0; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_ElemSize() \ jpayne@69: { \ jpayne@69: return sizeof(ElemType); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_BufferSize(size_t numElems) \ jpayne@69: { \ jpayne@69: return numElems*sizeof(ElemType); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_IsEmpty(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return !arr || arr->size == 0u; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_Size(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->size : 0u; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_Capacity(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->capacity : 0u; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_First(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->buf : NULL; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Last(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->buf + arr->size : NULL; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Front(AT *arr) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return &arr->buf[0]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Back(AT *arr) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return &arr->buf[arr->size - 1]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Resize(AT **arrp, size_t newSize) \ jpayne@69: { \ jpayne@69: assert(arrp); \ jpayne@69: assert(!*arrp || (*arrp)->size != 0xdeadbeef); \ jpayne@69: if (newSize == 0) { \ jpayne@69: assert(!*arrp || ((*arrp)->size = 0xdeadbeef)); \ jpayne@69: ckfree(*arrp); \ jpayne@69: *arrp = NULL; \ jpayne@69: } else { \ jpayne@69: int init = *arrp == NULL; \ jpayne@69: size_t memSize = AT##_BufferSize(newSize - 1) + sizeof(AT); \ jpayne@69: *arrp = ckrealloc(*arrp, memSize); \ jpayne@69: if (init) { \ jpayne@69: (*arrp)->size = 0; \ jpayne@69: } else if (newSize < (*arrp)->size) { \ jpayne@69: (*arrp)->size = newSize; \ jpayne@69: } \ jpayne@69: (*arrp)->capacity = newSize; \ jpayne@69: } \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Clear(AT *arr, size_t from, size_t to) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(to <= AT##_Capacity(arr)); \ jpayne@69: assert(from <= to); \ jpayne@69: memset(arr->buf + from, 0, AT##_BufferSize(to - from)); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_ResizeAndClear(AT **arrp, size_t newSize) \ jpayne@69: { \ jpayne@69: size_t oldCapacity; \ jpayne@69: assert(arrp); \ jpayne@69: oldCapacity = *arrp ? (*arrp)->capacity : 0; \ jpayne@69: AT##_Resize(arrp, newSize); \ jpayne@69: if (newSize > oldCapacity) { \ jpayne@69: AT##_Clear(*arrp, oldCapacity, newSize); \ jpayne@69: } \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_SetSize(AT *arr, size_t newSize) \ jpayne@69: { \ jpayne@69: assert(newSize <= AT##_Capacity(arr)); \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: if (arr) { \ jpayne@69: arr->size = newSize; \ jpayne@69: } \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Append(AT **arrp, ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(arrp); \ jpayne@69: if (!*arrp) { \ jpayne@69: AT##_Resize(arrp, 1); \ jpayne@69: } else if ((*arrp)->size == (*arrp)->capacity) { \ jpayne@69: AT##_Resize(arrp, (*arrp)->capacity + ((*arrp)->capacity + 1)/2); \ jpayne@69: } \ jpayne@69: (*arrp)->buf[(*arrp)->size++] = *elem; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_PopBack(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return arr->size -= 1; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Get(const AT *arr, size_t at) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(at < AT##_Size(arr)); \ jpayne@69: return (ElemType *) &arr->buf[at]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Set(AT *arr, size_t at, ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(at < AT##_Size(arr)); \ jpayne@69: arr->buf[at] = *elem; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Free(AT **arrp) \ jpayne@69: { \ jpayne@69: AT##_Resize(arrp, 0); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_Find(const AT *arr, const ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: if (arr) { \ jpayne@69: const ElemType *buf = arr->buf; \ jpayne@69: size_t i; \ jpayne@69: for (i = 0; i < arr->size; ++i) { \ jpayne@69: if (memcmp(&buf[i], elem, sizeof(ElemType)) == 0) { \ jpayne@69: return (int) i; \ jpayne@69: } \ jpayne@69: } \ jpayne@69: } \ jpayne@69: return -1; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_Contains(const AT *arr, const ElemType *elem) \ jpayne@69: { \ jpayne@69: return AT##_Find(arr, elem) != -1; \ jpayne@69: } \ jpayne@69: /* ------------------------------------------------------------------------- */ jpayne@69: jpayne@69: #define TK_PTR_ARRAY_DEFINE(AT, ElemType) /* AT = type of array */ \ jpayne@69: /* ------------------------------------------------------------------------- */ \ jpayne@69: typedef struct AT { \ jpayne@69: size_t size; \ jpayne@69: size_t capacity; \ jpayne@69: ElemType *buf[1]; \ jpayne@69: } AT; \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_ElemSize() \ jpayne@69: { \ jpayne@69: return sizeof(ElemType); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_BufferSize(size_t numElems) \ jpayne@69: { \ jpayne@69: return numElems*sizeof(ElemType *); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_IsEmpty(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return !arr || arr->size == 0; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType ** \ jpayne@69: AT##_First(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->buf : NULL; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType ** \ jpayne@69: AT##_Last(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->buf + arr->size : NULL; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Front(AT *arr) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return arr->buf[0]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Back(AT *arr) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return arr->buf[arr->size - 1]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_Size(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->size : 0; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_Capacity(const AT *arr) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: return arr ? arr->capacity : 0; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Resize(AT **arrp, size_t newCapacity) \ jpayne@69: { \ jpayne@69: assert(arrp); \ jpayne@69: assert(!*arrp || (*arrp)->size != 0xdeadbeef); \ jpayne@69: if (newCapacity == 0) { \ jpayne@69: assert(!*arrp || ((*arrp)->size = 0xdeadbeef)); \ jpayne@69: ckfree(*arrp); \ jpayne@69: *arrp = NULL; \ jpayne@69: } else { \ jpayne@69: int init = *arrp == NULL; \ jpayne@69: size_t memSize = AT##_BufferSize(newCapacity - 1) + sizeof(AT); \ jpayne@69: *arrp = ckrealloc(*arrp, memSize); \ jpayne@69: if (init) { \ jpayne@69: (*arrp)->size = 0; \ jpayne@69: } else if (newCapacity < (*arrp)->size) { \ jpayne@69: (*arrp)->size = newCapacity; \ jpayne@69: } \ jpayne@69: (*arrp)->capacity = newCapacity; \ jpayne@69: } \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Clear(AT *arr, size_t from, size_t to) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(arr->size != 0xdeadbeef); \ jpayne@69: assert(to <= AT##_Capacity(arr)); \ jpayne@69: assert(from <= to); \ jpayne@69: memset(arr->buf + from, 0, AT##_BufferSize(to - from)); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_ResizeAndClear(AT **arrp, size_t newCapacity) \ jpayne@69: { \ jpayne@69: size_t oldCapacity; \ jpayne@69: assert(arrp); \ jpayne@69: oldCapacity = *arrp ? (*arrp)->capacity : 0; \ jpayne@69: AT##_Resize(arrp, newCapacity); \ jpayne@69: if (newCapacity > oldCapacity) { \ jpayne@69: AT##_Clear(*arrp, oldCapacity, newCapacity); \ jpayne@69: } \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_SetSize(AT *arr, size_t newSize) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(newSize <= AT##_Capacity(arr)); \ jpayne@69: arr->size = newSize; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Append(AT **arrp, ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(arrp); \ jpayne@69: if (!*arrp) { \ jpayne@69: AT##_Resize(arrp, 1); \ jpayne@69: } else if ((*arrp)->size == (*arrp)->capacity) { \ jpayne@69: AT##_Resize(arrp, (*arrp)->capacity + ((*arrp)->capacity + 1)/2); \ jpayne@69: } \ jpayne@69: (*arrp)->buf[(*arrp)->size++] = elem; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static size_t \ jpayne@69: AT##_PopBack(AT *arr) \ jpayne@69: { \ jpayne@69: assert(!AT##_IsEmpty(arr)); \ jpayne@69: return arr->size -= 1; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static ElemType * \ jpayne@69: AT##_Get(const AT *arr, size_t at) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(at < AT##_Size(arr)); \ jpayne@69: return arr->buf[at]; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Set(AT *arr, size_t at, ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(arr); \ jpayne@69: assert(at < AT##_Size(arr)); \ jpayne@69: arr->buf[at] = elem; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static void \ jpayne@69: AT##_Free(AT **arrp) \ jpayne@69: { \ jpayne@69: AT##_Resize(arrp, 0); \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_Find(const AT *arr, const ElemType *elem) \ jpayne@69: { \ jpayne@69: assert(!arr || arr->size != 0xdeadbeef); \ jpayne@69: if (arr) { \ jpayne@69: ElemType *const *buf = arr->buf; \ jpayne@69: size_t i; \ jpayne@69: for (i = 0; i < arr->size; ++i) { \ jpayne@69: if (buf[i] == elem) { \ jpayne@69: return (int) i; \ jpayne@69: } \ jpayne@69: } \ jpayne@69: } \ jpayne@69: return -1; \ jpayne@69: } \ jpayne@69: \ jpayne@69: __TK_ARRAY_UNUSED \ jpayne@69: static int \ jpayne@69: AT##_Contains(const AT *arr, const ElemType *elem) \ jpayne@69: { \ jpayne@69: return AT##_Find(arr, elem) != -1; \ jpayne@69: } \ jpayne@69: /* ------------------------------------------------------------------------- */ jpayne@69: jpayne@69: #endif /* TK_ARRAY_DEFINED */ jpayne@69: jpayne@69: /* jpayne@69: * Local Variables: jpayne@69: * mode: c jpayne@69: * c-basic-offset: 4 jpayne@69: * fill-column: 105 jpayne@69: * End: jpayne@69: * vi:set ts=8 sw=4: jpayne@69: */