Skip to content

Instantly share code, notes, and snippets.

@kdrnic
Last active April 29, 2019 07:12
Show Gist options
  • Save kdrnic/654982a5dfff4d5cfb9f8bd589ba3a23 to your computer and use it in GitHub Desktop.
Save kdrnic/654982a5dfff4d5cfb9f8bd589ba3a23 to your computer and use it in GitHub Desktop.
A GNU C dynamic array implementation, inspired by Javascript arrays, and desired to be safe if possible
#ifndef ARR_H
#define ARR_H
#ifndef assert
#define assert()
#endif
#define arr_alloc malloc
#define arr_calloc(a,b) arr_alloc((a) * (b))
#define arr_cleanup __attribute__ ((__cleanup__(arr_cleanup_func)))
#define arr_t(t) \
struct \
{ \
t *data; \
int len, siz; \
char is_static; \
}
typedef arr_t(void*) arr_void;
typedef arr_t(char*) arr_str;
typedef arr_t(int) arr_int;
typedef arr_t(char) arr_char;
typedef arr_t(float) arr_float;
typedef arr_t(double) arr_double;
void arr_cleanup_func(void *v);
#define arr_empty {.len = 0, .siz = 0, .data = 0, .is_static = 0}
#define arr_reserve(pl, max)\
({\
__typeof__(pl) _pl = (pl);\
\
assert(_pl);\
assert(!_pl->is_static);\
\
_pl->siz = max;\
_pl->data = realloc(_pl->data, sizeof(*_pl->data) * _pl->siz);\
\
(void) 0;\
})
#define arr_unreserve(pl)\
({\
__typeof__(pl) _pl = (pl);\
\
assert(_pl);\
assert(!_pl->is_static);\
\
_pl->siz = _pl->len;\
_pl->data = realloc(_pl->data, sizeof(*_pl->data) * _pl->siz);\
\
(void) 0;\
})
#define arr_cpy(pl, out)\
({\
const __typeof__(pl) _pl = (pl);\
__typeof__(out) _out = (out);\
\
assert(_pl);\
assert(_out);\
assert(!_out->is_static);\
assert(!_out->siz);\
assert(__builtin_types_compatible_p(__typeof__(_pl->data), __typeof__(_out->data)));\
\
_out->siz = _pl->len;\
_out->len = _pl->len;\
_out->data = arr_calloc(_pl->len, sizeof(*_out->data));\
memcpy(_out->data, _pl->data, sizeof(*_out->data) * _pl->len);\
\
(void) 0;\
})
#define arr_join(a, b, out)\
({\
const __typeof__(a) _a = (a);\
const __typeof__(b) _b = (b);\
__typeof__(out) _out = out;\
\
assert(__builtin_types_compatible_p(__typeof__(_a->data), __typeof__(_b->data)));\
assert(__builtin_types_compatible_p(__typeof__(_a->data), __typeof__(_out->data)));\
assert(_a);\
assert(_b);\
assert(_out);\
assert(!_out->is_static);\
assert(!_out->siz);\
\
_out->len = _out->siz = _a->len + _b->len;\
_out->data = arr_alloc(sizeof(*_out->data) * _out->siz);\
memcpy(_out->data, _a->data, sizeof(*_out->data) * _a->len);\
memcpy(_out->data + _a->len, _b->data, sizeof(*_out->data) * _b->len);\
\
(void) 0;\
})
#define arr_cat(a, b)\
({\
__typeof__(a) _a = (a);\
const __typeof__(b) _b = (b);\
\
assert(__builtin_types_compatible_p(__typeof__(_a->data), __typeof__(_b->data)));\
assert(_a);\
assert(!_a->is_static);\
\
if(_b){\
_a->siz = _a->len + _b->len;\
_a->data = realloc(_a->data, sizeof(*_a->data) * _a->siz);\
memcpy(_a->data + _a->len, _b->data, sizeof(*_a->data) * _b->len);\
_a->len += _b->len;\
}\
\
_a->len;\
})
#define arr_push(pl, p)\
({\
__typeof__(pl) _pl = (pl);\
__typeof__(p) _p = (p);\
\
assert(__builtin_types_compatible_p(__typeof__(*_pl->data), __typeof__(_p)));\
assert(_pl);\
assert(!_pl->is_static);\
\
if(_pl->len + 1 > _pl->siz){\
_pl->siz = _pl->siz * 2;\
if(!_pl->siz) _pl->siz = 1;\
_pl->data = realloc(_pl->data, sizeof(*_pl->data) * _pl->siz);\
}\
_pl->data[_pl->len++] = _p;\
\
_pl->len;\
})
#define arr_free(pl)\
({\
__typeof__(pl) _pl = (pl);\
\
assert(_pl);\
assert(!_pl->is_static);\
assert(_pl->data);\
\
free(_pl->data);\
_pl->data = 0;\
_pl->len = 0;\
_pl->siz = 0;\
\
(void) 0;\
})
//Unlike Js Array.prototype.splice, doesn't return an array of deleted
#define arr_splice(pl, start, del_count, items...)\
({\
__typeof__(pl) _pl = (pl);\
const int _start = (start);\
const int _del_count = (del_count) + 0; /*del_count_ is thus optional*/\
const __typeof__(*_pl->data) _zero;\
const __typeof__(*_pl->data) _items[] = {_zero, items}; /*_items is thus also optional*/\
const int _item_count = (sizeof(_items) / sizeof(_zero)) - 1;\
int _i, _j;\
\
assert(_pl);\
assert(!_pl->is_static);\
assert(_start >= 0);\
assert(_start < _pl->len);\
assert(_start + _del_count <= _pl->len);\
\
/*printf("%d %d %d %d\n", _pl->len, _item_count, _del_count, _pl->len - _del_count + _item_count);*/\
\
_pl->siz = _pl->len - _del_count + _item_count;\
if(_pl->siz > _pl->len) _pl->data = realloc(_pl->data, _pl->siz * sizeof(*_pl->data));\
memmove(_pl->data + _start + _item_count, _pl->data + _start + _del_count, (_pl->len - _start - _del_count) * sizeof(_pl->data));\
for(_i = _start, _j = 1; _j <= _item_count; _i++, _j++){\
_pl->data[_i] = _items[_j];\
}\
_pl->len = _pl->siz;\
\
_pl->len;\
})
//Remove @idx without keeping order
#define arr_remove(pl, idx)\
({\
__typeof__(pl) _pl = (pl);\
const int _idx = idx;\
\
assert(_pl);\
assert(_idx < _pl->len);\
\
_pl->data[_idx] = _pl->data[--_pl->len];\
\
_pl->len;\
})
//Filter in-place, doesn't keep order
#define arr_sievef(pl, test)\
({\
__typeof__(pl) _pl = (pl);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
int _i;\
\
assert(_pl);\
assert(_test);\
\
for(_i = 0; _i < _pl->len;){\
if(!_test(_pl->data + _i, _i, _pl->data)) _pl->data[_i] = _pl->data[--_pl->len];\
else _i++;\
}\
\
_pl->len;\
})
#define arr_sieve(pl, test)\
({\
__typeof__(pl) _pl = pl;\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len;){\
if(!test(_pl->data[_i], _i, _pl->data)) _pl->data[_i] = _pl->data[--_pl->len];\
else _i++;\
}\
\
_pl->len;\
})
#define ARR_ITEMS_FIRST(_a, ...) ((_a))
#define arr_of(items...)\
({\
arr_void *_arr_tmp = __builtin_alloca(sizeof(arr_void));\
__typeof__(ARR_ITEMS_FIRST(items)) _items[] = {items};\
\
_arr_tmp->is_static = 0;\
_arr_tmp->len = sizeof(_items) / sizeof(_items[0]);\
_arr_tmp->siz = _arr_tmp->len;\
_arr_tmp->data = arr_calloc(sizeof(ARR_ITEMS_FIRST(items)), _arr_tmp->len);\
memcpy(_arr_tmp->data, _items, _arr_tmp->len * sizeof(ARR_ITEMS_FIRST(items)));\
\
_arr_tmp;\
})
#define arr_everyf(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
int _i, _res = 1;\
\
assert(_pl);\
assert(_test);\
\
for(_i = 0; _res && _i < _pl->len; _i++){\
_res = _res && _test(_pl->data + _i, _i, _pl->data);\
}\
\
_res;\
})
#define arr_fill(pl, val)\
({\
__typeof__(pl) _pl = (pl);\
const __typeof__(val) _val = (val);\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
_pl->data[_i] = _val;\
}\
\
(void) 0;\
})
#define arr_filterf(pl, test, out)\
({\
const __typeof__(pl) _pl = (pl);\
__typeof__(out) _out = (out);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
int _i;\
char *_cache = malloc(_pl->len * sizeof(*_pl->data));\
\
assert(_pl);\
assert(_test);\
assert(_out);\
assert(!_out->siz);\
\
_out->len = 0;\
for(_i = 0; _i < _pl->len; _i++){\
if((_cache[_i] = _test(_pl->data + _i, _i, _pl->data))){\
_out->len++;\
}\
}\
_out->data = arr_calloc(sizeof(*_pl->data), _out->len);\
_out->siz = 0;\
for(_i = 0; _i < _pl->len; _i++){\
if(_cache[_i]){\
_out->data[_out->siz++] = _pl->data[_i];\
}\
}\
free(_cache);\
\
(void) 0;\
})
#define arr_findf(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
__typeof__(*_pl->data) _res;\
int _i;\
\
assert(_pl);\
assert(_test);\
\
for(_i = 0; _i < _pl->len; _i++){\
if(_test(_pl->data + _i, _i, _pl->data)){\
_res = _pl->data[_i];\
break;\
}\
}\
\
_res;\
})
#define arr_findidxf(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
int _i;\
\
assert(_pl);\
assert(_test);\
\
for(_i = 0; _i < _pl->len; _i++){\
if(_test(_pl->data + _i, _i, _pl->data)){\
break;\
}\
}\
\
_i;\
})
#define arr_foreachf(pl, func)\
({\
__typeof__(pl) _pl = (pl);\
const void (*_func)(__typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (func);\
int _i;\
\
assert(_func);\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
_func(_pl->data + _i, _i, _pl->data);\
}\
\
(void) 0;\
})
#define arr_somef(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
const int (*_test)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (test);\
int _i, _res = 0;\
\
assert(_pl);\
assert(_test);\
\
for(_i = 0; (!_res) && _i < _pl->len; _i++){\
_res = _res || _test(_pl->data + _i, _i, _pl->data);\
}\
\
_res;\
})
#define arr_includes(pl, val)\
({\
const __typeof__(pl) _pl = (pl);\
const __typeof__(*_pl->data) _val = (val);\
int _i, _res = 0;\
\
assert(_pl);\
\
for(_i = 0; (!_res) && _i < _pl->len; _i++){\
_res = _res || (_pl->data[_i] == _val);\
}\
\
_res;\
})
#define arr_idxof(pl, val)\
({\
const __typeof__(pl) _pl = (pl);\
const __typeof__(*_pl->data) _val = (val);\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
if(_pl->data[_i] == _val) break;\
}\
\
_i;\
})
#define arr_mapf(pl, func, out)\
({\
const __typeof__(pl) _pl = (pl);\
const __typeof__(*_pl->data) (*_func)(const __typeof__(*_pl->data) *, int, const __typeof__(*_pl->data) *) = (func);\
__typeof__(out) _out = (out);\
int _i;\
\
assert(_pl);\
assert(_func);\
assert(_out);\
assert(!_out->siz);\
\
_out->siz = _out->len = _pl->len;\
_out->data = arr_calloc(sizeof(*_out->data), _out->len);\
for(_i = 0; _i < _pl->len; _i++){\
_out->data[_i] = _func(_pl->data + _i, _i, _pl->data);\
}\
\
(void) 0;\
})
#define arr_pop(pl)\
({\
__typeof__(pl) _pl = (pl);\
\
assert(_pl);\
assert(!_pl->is_static);\
assert(_pl->len);\
\
_pl->len--;\
\
_pl->len;\
})
#define arr_reverse(pl)\
({\
__typeof__(pl) _pl = (pl);\
int i;\
\
assert(_pl);\
\
for(i = 0; i < _pl->len / 2; i++){\
const __typeof__(*_pl->data) _tmp = _pl->data[i];\
_pl->data[i] = _pl->data[_pl->len - 1 - i];\
_pl->data[_pl->len - 1 - i] = _tmp;\
}\
\
(void) 0;\
})
//TODO: make keep order
#define arr_shift(pl)\
({\
__typeof__(pl) _pl = (pl);\
const __typeof__(*_pl->data) _tmp = _pl->data[_pl->len - 1];\
\
assert(_pl);\
assert(!_pl->is_static);\
assert(_pl->len);\
\
_pl->data[0] = _tmp;\
_pl->len--;\
\
_pl->len;\
})
#define arr_sort(pl, func)\
({\
__typeof__(pl) _pl = (pl);\
const int (*_func)(const __typeof__(*_pl->data) *, const __typeof__(*_pl->data) *) = (func);\
\
assert(_pl);\
assert(_func);\
\
qsort(_pl->data, _pl->len, sizeof(*_pl->data), (int (*)(const void *, const void *))_func);\
\
(void) 0;\
})
#define arr_every(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
int _i, _res = 1;\
\
assert(_pl);\
\
for(_i = 0; _res && _i < _pl->len; _i++){\
_res = _res && test(_pl->data[_i], _i, _pl->data);\
}\
\
_res;\
})
#define arr_filter(pl, test, out)\
({\
const __typeof__(pl) _pl = (pl);\
int _i;\
char *_cache = malloc(_pl->len * sizeof(*_pl->data));\
__typeof__(out) _out = (out);\
\
assert(_pl);\
assert(_out);\
assert(!_out->siz);\
\
_out->len = 0;\
for(_i = 0; _i < _pl->len; _i++){\
if((_cache[_i] = test(_pl->data[_i], _i, _pl->data))){\
_out->len++;\
}\
}\
_out->data = arr_calloc(sizeof(*_pl->data), _out->len);\
_out->siz = 0;\
for(_i = 0; _i < _pl->len; _i++){\
if(_cache[_i]){\
_out->data[_out->siz++] = _pl->data[_i];\
}\
}\
free(_cache);\
\
(void) 0;\
})
#define arr_find(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
__typeof__(*_pl->data) _res;\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
if(test(_pl->data[_i], _i, _pl->data)){\
_res = _pl->data[_i];\
break;\
}\
}\
\
_res;\
})
#define arr_findidx(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
if(test(_pl->data[_i], _i, _pl->data)){\
break;\
}\
}\
\
_i;\
})
#define arr_foreach(pl, func)\
({\
__typeof__(pl) _pl = (pl);\
int _i;\
\
assert(_pl);\
\
for(_i = 0; _i < _pl->len; _i++){\
func(_pl->data[_i], _i, _pl->data);\
}\
\
(void) 0;\
})
#define arr_some(pl, test)\
({\
const __typeof__(pl) _pl = (pl);\
int _i, _res = 0;\
\
assert(_pl);\
\
for(_i = 0; (!_res) && _i < _pl->len; _i++){\
_res = _res || test(_pl->data[_i], _i, _pl->data);\
}\
\
_res;\
})
#define arr_map(pl, func, out)\
({\
const __typeof__(pl) _pl = (pl);\
__typeof__(out) _out = (out);\
int _i;\
\
assert(_pl);\
assert(_out);\
assert(!_out->siz);\
\
_out->siz = _out->len = _pl->len;\
_out->data = arr_calloc(sizeof(*_out->data), _out->len);\
for(_i = 0; _i < _pl->len; _i++){\
_out->data[_i] = func(_pl->data[_i], _i, _pl->data);\
}\
\
(void) 0;\
})
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment