#ifndef _AL_ARRAY_TYPED_H #define _AL_ARRAY_TYPED_H #ifndef AL_HAVE_GNU_EXTENSIONS #error "missing required GNU C extensions" #endif #define AL_EMPTY_DEFAULT(...) AL_EMPTY_DEFAULT_0(__VA_ARGS__, , ) #define AL_EMPTY_DEFAULT_0(FUNC, T, S, ...) FUNC(T, S) #define AL_PASTER_EVALUATOR(X, Y) X##_##Y #define AL_PASTER(X, Y) AL_PASTER_EVALUATOR(X, Y) #define _array(N, ...) AL_PASTER(array, AL_PASTER(N, __VA_ARGS__)) #define _al_array_init(N, ...) AL_PASTER(_array_init, AL_PASTER(N, __VA_ARGS__)) #define _al_array_data(N, ...) AL_PASTER(_array_data, AL_PASTER(N, __VA_ARGS__)) #define _al_array_reserve(N, ...) AL_PASTER(_array_reserve, AL_PASTER(N, __VA_ARGS__)) #define __al_array_reserve_internal(N, ...) AL_PASTER(_array_reserve_internal, AL_PASTER(N, __VA_ARGS__)) #define _al_array_at(N, ...) AL_PASTER(_array_at, AL_PASTER(N, __VA_ARGS__)) #define _al_array_last(N, ...) AL_PASTER(_array_last, AL_PASTER(N, __VA_ARGS__)) #define _al_array_push(N, ...) AL_PASTER(_array_push, AL_PASTER(N, __VA_ARGS__)) #define _al_array_pop(N, ...) AL_PASTER(_array_pop, AL_PASTER(N, __VA_ARGS__)) #define _al_array_remove_at(N, ...) AL_PASTER(_array_remove_at, AL_PASTER(N, __VA_ARGS__)) #define _al_array_pop_at(N, ...) AL_PASTER(_array_pop_at, AL_PASTER(N, __VA_ARGS__)) #define _al_array_insert(N, ...) AL_PASTER(_array_insert, AL_PASTER(N, __VA_ARGS__)) #define _al_array_free(N, ...) AL_PASTER(_array_free, AL_PASTER(N, __VA_ARGS__)) #define array(...) AL_EMPTY_DEFAULT(_array, __VA_ARGS__) #define al_array_init(...) AL_EMPTY_DEFAULT(_al_array_init, __VA_ARGS__) #define al_array_data(...) AL_EMPTY_DEFAULT(_al_array_data, __VA_ARGS__) #define _al_array_reserve_internal(...) AL_EMPTY_DEFAULT(__al_array_reserve_internal, __VA_ARGS__) #define al_array_reserve(...) AL_EMPTY_DEFAULT(_al_array_reserve, __VA_ARGS__) #define al_array_at(...) AL_EMPTY_DEFAULT(_al_array_at, __VA_ARGS__) #define al_array_last(...) AL_EMPTY_DEFAULT(_al_array_last, __VA_ARGS__) #define al_array_push(...) AL_EMPTY_DEFAULT(_al_array_push, __VA_ARGS__) #define al_array_pop(...) AL_EMPTY_DEFAULT(_al_array_pop, __VA_ARGS__) #define al_array_remove_at(...) AL_EMPTY_DEFAULT(_al_array_remove_at, __VA_ARGS__) #define al_array_pop_at(...) AL_EMPTY_DEFAULT(_al_array_pop_at, __VA_ARGS__) #define al_array_insert(...) AL_EMPTY_DEFAULT(_al_array_insert, __VA_ARGS__) #define al_array_free(...) AL_EMPTY_DEFAULT(_al_array_free, __VA_ARGS__) #define AL_ARRAY_DEFINE_FUNCTIONS(N, T, ...) \ static inline T *al_array_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i) \ { \ return &al_array_data(N, __VA_ARGS__)(a)[i]; \ } \ static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \ { \ return al_array_at(N, __VA_ARGS__)(a, a->size - 1); \ } \ static void al_array_reserve(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 size); \ static inline void al_array_push(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *value) \ { \ al_array_reserve(N, __VA_ARGS__)(a, a->size + 1); \ *al_array_at(N, __VA_ARGS__)(a, a->size++) = *value; \ } \ static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, T *ret) \ { \ *ret = *al_array_at(N, __VA_ARGS__)(a, --a->size); \ } \ static inline void al_array_remove_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i) \ { \ if (UNLIKELY(i == a->size - 1)) { \ a->size--; \ } else { \ al_memmove(al_array_at(N, __VA_ARGS__)(a, i), al_array_at(N, __VA_ARGS__)(a, i + 1), \ sizeof(T) * (--a->size - i)); \ } \ } \ static inline void al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i, T *ret) \ { \ *ret = *al_array_at(N, __VA_ARGS__)(a, i); \ al_array_remove_at(N, __VA_ARGS__)(a, i); \ } \ static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 i, T *item) \ { \ if (a->size > i) { \ al_array_reserve(N, __VA_ARGS__)(a, a->size + 1); \ al_memmove(al_array_at(N, __VA_ARGS__)(a, i + 1), al_array_at(N, __VA_ARGS__)(a, i), \ sizeof(T) * (a->size - i)); \ a->size++; \ } else { \ al_array_reserve(N, __VA_ARGS__)(a, i + 1); \ a->size = i + 1; \ } \ *al_array_at(N, __VA_ARGS__)(a, i) = *item; \ } \ static inline void _al_array_reserve_internal(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a, u32 size) \ { \ if (size < al_grow_limit) { \ size = al_next_power_of_two(size + 1); \ } else { \ size = (size + al_grow_limit) & ~al_grow_limit; \ } \ if (a->alloc >= size) return; \ a->data = (!a->data) ? al_malloc(sizeof(T) * size) : al_realloc(a->data, sizeof(T) * size); \ a->alloc = size; \ } \ static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *a) \ { \ if (a->data != NULL) al_free(a->data); \ } #define AL_ARRAY_DEFINE(N, T) \ typedef struct array(N) array(N); \ struct array(N) { \ u32 size; \ u32 alloc; \ T *data; \ }; \ static inline void al_array_init(N)(array(N) *a) \ { \ a->size = 0; \ a->alloc = 0; \ a->data = NULL; \ } \ static inline T *al_array_data(N)(array(N) *a) \ { \ return a->data; \ } \ AL_ARRAY_DEFINE_FUNCTIONS(N, T,) \ static inline void al_array_reserve(N)(array(N) *a, u32 size) \ { \ _al_array_reserve_internal(N)(a, size); \ } #define AL_ARRAY_INLINE_STORAGE_DEFINE(N, T, S) \ typedef struct array(N, S) array(N, S); \ struct array(N, S) { \ u32 size; \ u32 alloc; \ T *data; \ T inline_data[S]; \ }; \ static inline void al_array_init(N, S)(array(N, S) *a) \ { \ a->size = 0; \ a->alloc = S; \ a->data = NULL; \ } \ static inline T *al_array_data(N, S)(array(N, S) *a) \ { \ if (a->data) return a->data; \ else return a->inline_data; \ } \ AL_ARRAY_DEFINE_FUNCTIONS(N, T, S) \ static inline void al_array_reserve(N, S)(array(N, S) *a, u32 size) \ { \ if (S >= size) return; \ bool copy_inline = a->data == NULL; \ _al_array_reserve_internal(N, S)(a, size); \ if (UNLIKELY(copy_inline)) { \ al_memcpy(a->data, a->inline_data, sizeof(T) * a->size); \ } \ } #endif // _AL_ARRAY_TYPED_H