123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653 |
- /*
- * Copyright (c) 2013 Hugh Bailey <[email protected]>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #pragma once
- #include "c99defs.h"
- #include <string.h>
- #include <stdlib.h>
- #include <assert.h>
- #include "bmem.h"
- #ifdef __cplusplus
- extern "C" {
- #endif
- /*
- * Dynamic array.
- *
- * NOTE: Not type-safe when using directly.
- * Specifying size per call with inline maximizes compiler optimizations
- *
- * See DARRAY macro at the bottom of the file for slightly safer usage.
- */
- #define DARRAY_INVALID ((size_t)-1)
- struct darray {
- void *array;
- size_t num;
- size_t capacity;
- };
- static inline void darray_init(struct darray *dst)
- {
- dst->array = NULL;
- dst->num = 0;
- dst->capacity = 0;
- }
- static inline void darray_free(struct darray *dst)
- {
- bfree(dst->array);
- dst->array = NULL;
- dst->num = 0;
- dst->capacity = 0;
- }
- static inline size_t darray_alloc_size(const size_t element_size,
- const struct darray *da)
- {
- return element_size * da->num;
- }
- static inline void *darray_item(const size_t element_size,
- const struct darray *da, size_t idx)
- {
- return (void *)(((uint8_t *)da->array) + element_size * idx);
- }
- static inline void *darray_end(const size_t element_size,
- const struct darray *da)
- {
- if (!da->num)
- return NULL;
- return darray_item(element_size, da, da->num - 1);
- }
- static inline void darray_reserve(const size_t element_size, struct darray *dst,
- const size_t capacity)
- {
- void *ptr;
- if (capacity == 0 || capacity <= dst->capacity)
- return;
- ptr = bmalloc(element_size * capacity);
- if (dst->array) {
- if (dst->num)
- memcpy(ptr, dst->array, element_size * dst->num);
- bfree(dst->array);
- }
- dst->array = ptr;
- dst->capacity = capacity;
- }
- static inline void darray_ensure_capacity(const size_t element_size,
- struct darray *dst,
- const size_t new_size)
- {
- size_t new_cap;
- void *ptr;
- if (new_size <= dst->capacity)
- return;
- new_cap = (!dst->capacity) ? new_size : dst->capacity * 2;
- if (new_size > new_cap)
- new_cap = new_size;
- ptr = bmalloc(element_size * new_cap);
- if (dst->array) {
- if (dst->capacity)
- memcpy(ptr, dst->array, element_size * dst->capacity);
- bfree(dst->array);
- }
- dst->array = ptr;
- dst->capacity = new_cap;
- }
- static inline void darray_clear(struct darray *dst)
- {
- dst->num = 0;
- }
- static inline void darray_resize(const size_t element_size, struct darray *dst,
- const size_t size)
- {
- int b_clear;
- size_t old_num;
- if (size == dst->num) {
- return;
- } else if (size == 0) {
- dst->num = 0;
- return;
- }
- b_clear = size > dst->num;
- old_num = dst->num;
- darray_ensure_capacity(element_size, dst, size);
- dst->num = size;
- if (b_clear)
- memset(darray_item(element_size, dst, old_num), 0,
- element_size * (dst->num - old_num));
- }
- static inline void darray_copy(const size_t element_size, struct darray *dst,
- const struct darray *da)
- {
- if (da->num == 0) {
- darray_free(dst);
- } else {
- darray_resize(element_size, dst, da->num);
- memcpy(dst->array, da->array, element_size * da->num);
- }
- }
- static inline void darray_copy_array(const size_t element_size,
- struct darray *dst, const void *array,
- const size_t num)
- {
- darray_resize(element_size, dst, num);
- memcpy(dst->array, array, element_size * dst->num);
- }
- static inline void darray_move(struct darray *dst, struct darray *src)
- {
- darray_free(dst);
- memcpy(dst, src, sizeof(struct darray));
- src->array = NULL;
- src->capacity = 0;
- src->num = 0;
- }
- static inline size_t darray_find(const size_t element_size,
- const struct darray *da, const void *item,
- const size_t idx)
- {
- size_t i;
- assert(idx <= da->num);
- for (i = idx; i < da->num; i++) {
- void *compare = darray_item(element_size, da, i);
- if (memcmp(compare, item, element_size) == 0)
- return i;
- }
- return DARRAY_INVALID;
- }
- static inline size_t darray_push_back(const size_t element_size,
- struct darray *dst, const void *item)
- {
- darray_ensure_capacity(element_size, dst, ++dst->num);
- memcpy(darray_end(element_size, dst), item, element_size);
- return dst->num - 1;
- }
- static inline void *darray_push_back_new(const size_t element_size,
- struct darray *dst)
- {
- void *last;
- darray_ensure_capacity(element_size, dst, ++dst->num);
- last = darray_end(element_size, dst);
- memset(last, 0, element_size);
- return last;
- }
- static inline size_t darray_push_back_array(const size_t element_size,
- struct darray *dst,
- const void *array, const size_t num)
- {
- size_t old_num;
- if (!dst)
- return 0;
- if (!array || !num)
- return dst->num;
- old_num = dst->num;
- darray_resize(element_size, dst, dst->num + num);
- memcpy(darray_item(element_size, dst, old_num), array,
- element_size * num);
- return old_num;
- }
- static inline size_t darray_push_back_darray(const size_t element_size,
- struct darray *dst,
- const struct darray *da)
- {
- return darray_push_back_array(element_size, dst, da->array, da->num);
- }
- static inline void darray_insert(const size_t element_size, struct darray *dst,
- const size_t idx, const void *item)
- {
- void *new_item;
- size_t move_count;
- assert(idx <= dst->num);
- if (idx == dst->num) {
- darray_push_back(element_size, dst, item);
- return;
- }
- move_count = dst->num - idx;
- darray_ensure_capacity(element_size, dst, ++dst->num);
- new_item = darray_item(element_size, dst, idx);
- memmove(darray_item(element_size, dst, idx + 1), new_item,
- move_count * element_size);
- memcpy(new_item, item, element_size);
- }
- static inline void *darray_insert_new(const size_t element_size,
- struct darray *dst, const size_t idx)
- {
- void *item;
- size_t move_count;
- assert(idx <= dst->num);
- if (idx == dst->num)
- return darray_push_back_new(element_size, dst);
- move_count = dst->num - idx;
- darray_ensure_capacity(element_size, dst, ++dst->num);
- item = darray_item(element_size, dst, idx);
- memmove(darray_item(element_size, dst, idx + 1), item,
- move_count * element_size);
- memset(item, 0, element_size);
- return item;
- }
- static inline void darray_insert_array(const size_t element_size,
- struct darray *dst, const size_t idx,
- const void *array, const size_t num)
- {
- size_t old_num;
- assert(array != NULL);
- assert(num != 0);
- assert(idx <= dst->num);
- old_num = dst->num;
- darray_resize(element_size, dst, dst->num + num);
- memmove(darray_item(element_size, dst, idx + num),
- darray_item(element_size, dst, idx),
- element_size * (old_num - idx));
- memcpy(darray_item(element_size, dst, idx), array, element_size * num);
- }
- static inline void darray_insert_darray(const size_t element_size,
- struct darray *dst, const size_t idx,
- const struct darray *da)
- {
- darray_insert_array(element_size, dst, idx, da->array, da->num);
- }
- static inline void darray_erase(const size_t element_size, struct darray *dst,
- const size_t idx)
- {
- assert(idx < dst->num);
- if (idx >= dst->num || !--dst->num)
- return;
- memmove(darray_item(element_size, dst, idx),
- darray_item(element_size, dst, idx + 1),
- element_size * (dst->num - idx));
- }
- static inline void darray_erase_item(const size_t element_size,
- struct darray *dst, const void *item)
- {
- size_t idx = darray_find(element_size, dst, item, 0);
- if (idx != DARRAY_INVALID)
- darray_erase(element_size, dst, idx);
- }
- static inline void darray_erase_range(const size_t element_size,
- struct darray *dst, const size_t start,
- const size_t end)
- {
- size_t count, move_count;
- assert(start <= dst->num);
- assert(end <= dst->num);
- assert(end > start);
- count = end - start;
- if (count == 1) {
- darray_erase(element_size, dst, start);
- return;
- } else if (count == dst->num) {
- dst->num = 0;
- return;
- }
- move_count = dst->num - end;
- if (move_count)
- memmove(darray_item(element_size, dst, start),
- darray_item(element_size, dst, end),
- move_count * element_size);
- dst->num -= count;
- }
- static inline void darray_pop_back(const size_t element_size,
- struct darray *dst)
- {
- assert(dst->num != 0);
- if (dst->num)
- darray_erase(element_size, dst, dst->num - 1);
- }
- static inline void darray_join(const size_t element_size, struct darray *dst,
- struct darray *da)
- {
- darray_push_back_darray(element_size, dst, da);
- darray_free(da);
- }
- static inline void darray_split(const size_t element_size, struct darray *dst1,
- struct darray *dst2, const struct darray *da,
- const size_t idx)
- {
- struct darray temp;
- assert(da->num >= idx);
- assert(dst1 != dst2);
- darray_init(&temp);
- darray_copy(element_size, &temp, da);
- darray_free(dst1);
- darray_free(dst2);
- if (da->num) {
- if (idx)
- darray_copy_array(element_size, dst1, temp.array,
- temp.num);
- if (idx < temp.num - 1)
- darray_copy_array(element_size, dst2,
- darray_item(element_size, &temp, idx),
- temp.num - idx);
- }
- darray_free(&temp);
- }
- static inline void darray_move_item(const size_t element_size,
- struct darray *dst, const size_t from,
- const size_t to)
- {
- void *temp, *p_from, *p_to;
- if (from == to)
- return;
- temp = malloc(element_size);
- if (!temp) {
- bcrash("darray_move_item: out of memory");
- return;
- }
- p_from = darray_item(element_size, dst, from);
- p_to = darray_item(element_size, dst, to);
- memcpy(temp, p_from, element_size);
- if (to < from)
- memmove(darray_item(element_size, dst, to + 1), p_to,
- element_size * (from - to));
- else
- memmove(p_from, darray_item(element_size, dst, from + 1),
- element_size * (to - from));
- memcpy(p_to, temp, element_size);
- free(temp);
- }
- static inline void darray_swap(const size_t element_size, struct darray *dst,
- const size_t a, const size_t b)
- {
- void *temp, *a_ptr, *b_ptr;
- assert(a < dst->num);
- assert(b < dst->num);
- if (a == b)
- return;
- temp = malloc(element_size);
- if (!temp)
- bcrash("darray_swap: out of memory");
- a_ptr = darray_item(element_size, dst, a);
- b_ptr = darray_item(element_size, dst, b);
- memcpy(temp, a_ptr, element_size);
- memcpy(a_ptr, b_ptr, element_size);
- memcpy(b_ptr, temp, element_size);
- free(temp);
- }
- /*
- * Defines to make dynamic arrays more type-safe.
- * Note: Still not 100% type-safe but much better than using darray directly
- * Makes it a little easier to use as well.
- *
- * I did -not- want to use a gigantic macro to generate a crapload of
- * typesafe inline functions per type. It just feels like a mess to me.
- */
- #define DARRAY(type) \
- union { \
- struct darray da; \
- struct { \
- type *array; \
- size_t num; \
- size_t capacity; \
- }; \
- }
- #define da_init(v) darray_init(&v.da)
- #define da_free(v) darray_free(&v.da)
- #define da_alloc_size(v) (sizeof(*v.array) * v.num)
- #define da_end(v) darray_end(sizeof(*v.array), &v.da)
- #define da_reserve(v, capacity) \
- darray_reserve(sizeof(*v.array), &v.da, capacity)
- #define da_resize(v, size) darray_resize(sizeof(*v.array), &v.da, size)
- #define da_clear(v) darray_clear(&v.da)
- #define da_copy(dst, src) darray_copy(sizeof(*dst.array), &dst.da, &src.da)
- #define da_copy_array(dst, src_array, n) \
- darray_copy_array(sizeof(*dst.array), &dst.da, src_array, n)
- #define da_move(dst, src) darray_move(&dst.da, &src.da)
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #ifdef __cplusplus
- #define da_type_test(v, item) \
- ({ \
- if (false) { \
- auto _t = v.array; \
- _t = (item); \
- (void)_t; \
- *(v).array = *(item); \
- } \
- })
- #else
- #define da_type_test(v, item) \
- ({ \
- if (false) { \
- const typeof(*v.array) *_t; \
- _t = (item); \
- (void)_t; \
- *(v).array = *(item); \
- } \
- })
- #endif
- #endif // ENABLE_DARRAY_TYPE_TEST
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_find(v, item, idx) \
- ({ \
- da_type_test(v, item); \
- darray_find(sizeof(*v.array), &v.da, item, idx); \
- })
- #else
- #define da_find(v, item, idx) darray_find(sizeof(*v.array), &v.da, item, idx)
- #endif
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_push_back(v, item) \
- ({ \
- da_type_test(v, item); \
- darray_push_back(sizeof(*v.array), &v.da, item); \
- })
- #else
- #define da_push_back(v, item) darray_push_back(sizeof(*v.array), &v.da, item)
- #endif
- #ifdef __GNUC__
- /* GCC 12 with -O2 generates a warning -Wstringop-overflow in da_push_back_new,
- * which could be false positive. Extract the macro here to avoid the warning.
- */
- #define da_push_back_new(v) \
- ({ \
- __typeof__(v) *d = &(v); \
- darray_ensure_capacity(sizeof(*d->array), &d->da, ++d->num); \
- memset(&d->array[d->num - 1], 0, sizeof(*d->array)); \
- &d->array[d->num - 1]; \
- })
- #else
- #define da_push_back_new(v) darray_push_back_new(sizeof(*v.array), &v.da)
- #endif
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_push_back_array(dst, src_array, n) \
- ({ \
- da_type_test(dst, src_array); \
- darray_push_back_array(sizeof(*dst.array), &dst.da, src_array, \
- n); \
- })
- #else
- #define da_push_back_array(dst, src_array, n) \
- darray_push_back_array(sizeof(*dst.array), &dst.da, src_array, n)
- #endif
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_push_back_da(dst, src) \
- ({ \
- da_type_test(dst, src.array); \
- darray_push_back_darray(sizeof(*dst.array), &dst.da, &src.da); \
- })
- #else
- #define da_push_back_da(dst, src) \
- darray_push_back_darray(sizeof(*dst.array), &dst.da, &src.da)
- #endif
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_insert(v, idx, item) \
- ({ \
- da_type_test(v, item); \
- darray_insert(sizeof(*v.array), &v.da, idx, item); \
- })
- #else
- #define da_insert(v, idx, item) \
- darray_insert(sizeof(*v.array), &v.da, idx, item)
- #endif
- #define da_insert_new(v, idx) darray_insert_new(sizeof(*v.array), &v.da, idx)
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_insert_array(dst, idx, src_array, n) \
- ({ \
- da_type_test(dst, src_array); \
- darray_insert_array(sizeof(*dst.array), &dst.da, idx, \
- src_array, n); \
- })
- #else
- #define da_insert_array(dst, idx, src_array, n) \
- darray_insert_array(sizeof(*dst.array), &dst.da, idx, src_array, n)
- #endif
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_insert_da(dst, idx, src) \
- ({ \
- da_type_test(dst, src.array); \
- darray_insert_darray(sizeof(*dst.array), &dst.da, idx, \
- &src.da); \
- })
- #else
- #define da_insert_da(dst, idx, src) \
- darray_insert_darray(sizeof(*dst.array), &dst.da, idx, &src.da)
- #endif
- #define da_erase(dst, idx) darray_erase(sizeof(*dst.array), &dst.da, idx)
- #ifdef ENABLE_DARRAY_TYPE_TEST
- #define da_erase_item(dst, item) \
- ({ \
- da_type_test(dst, item); \
- darray_erase_item(sizeof(*dst.array), &dst.da, item); \
- })
- #else
- #define da_erase_item(dst, item) \
- darray_erase_item(sizeof(*dst.array), &dst.da, item)
- #endif
- #define da_erase_range(dst, from, to) \
- darray_erase_range(sizeof(*dst.array), &dst.da, from, to)
- #define da_pop_back(dst) darray_pop_back(sizeof(*dst.array), &dst.da);
- #define da_join(dst, src) darray_join(sizeof(*dst.array), &dst.da, &src.da)
- #define da_split(dst1, dst2, src, idx) \
- darray_split(sizeof(*src.array), &dst1.da, &dst2.da, &src.da, idx)
- #define da_move_item(v, from, to) \
- darray_move_item(sizeof(*v.array), &v.da, from, to)
- #define da_swap(v, idx1, idx2) darray_swap(sizeof(*v.array), &v.da, idx1, idx2)
- #ifdef __cplusplus
- }
- #endif
|