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