Last active
April 29, 2019 07:12
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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