#ifndef _AL_ARRAY_TYPED_H #define _AL_ARRAY_TYPED_H #ifndef AL_HAVE_GNU_EXTENSIONS #error "missing required GNU C extensions" #endif #include "macros.h" #define AL_EMPTY_DEFAULT_1(FUNC, T, S, ...) FUNC(T, S) #define AL_EMPTY_DEFAULT(...) AL_EMPTY_DEFAULT_1(__VA_ARGS__, , ) #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__) *array, u32 i) \ { \ return &al_array_data(N, __VA_ARGS__)(array)[i]; \ } \ static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \ { \ return al_array_at(N, __VA_ARGS__)(array, array->count - 1); \ } \ static inline void al_array_reserve(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 count); \ static inline void al_array_push(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T value) \ { \ al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \ *al_array_at(N, __VA_ARGS__)(array, array->count++) = value; \ } \ static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i, T item) \ { \ al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \ if (i != array->count - 1) { \ al_memmove(al_array_at(N, __VA_ARGS__)(array, i + 1), al_array_at(N, __VA_ARGS__)(array, i), \ (array->count - i) * sizeof(T)); \ } \ array->count++; \ *al_array_at(N, __VA_ARGS__)(array, i) = item; \ } \ static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T *ret) \ { \ *ret = *al_array_at(N, __VA_ARGS__)(array, --array->count); \ } \ static inline void al_array_remove_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \ { \ if (UNLIKELY(i == array->count - 1)) { \ array->count--; \ } else { \ al_memmove(al_array_at(N, __VA_ARGS__)(array, i), al_array_at(N, __VA_ARGS__)(array, i + 1), \ (--array->count - i) * sizeof(T)); \ } \ } \ static inline T al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \ { \ T ret = *al_array_at(N, __VA_ARGS__)(array, i); \ al_array_remove_at(N, __VA_ARGS__)(array, i); \ return ret; \ } \ static inline void _al_array_reserve_internal(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 size) \ { \ array->alloc = al_growing_allocation((void **)&array->data, array->alloc, size, al_realloc); \ } \ static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \ { \ if (array->data) al_free(array->data); \ } #define AL_ARRAY_DEFINE(N, T) \ typedef struct array(N) array(N); \ struct array(N) { \ u32 count; \ u32 alloc; \ T *data; \ }; \ static inline void al_array_init(N)(array(N) *array) \ { \ array->count = 0; \ array->alloc = 0; \ array->data = NULL; \ } \ static inline T *al_array_data(N)(array(N) *array) \ { \ return array->data; \ } \ AL_ARRAY_DEFINE_FUNCTIONS(N, T,) \ static inline void al_array_reserve(N)(array(N) *array, u32 count) \ { \ _al_array_reserve_internal(N)(array, count * sizeof(T)); \ } #define AL_ARRAY_INLINE_STORAGE_DEFINE(N, T, S) \ typedef struct array(N, S) array(N, S); \ struct array(N, S) { \ u32 count; \ u32 alloc; \ T *data; \ T inline_data[S]; \ }; \ static inline void al_array_init(N, S)(array(N, S) *array) \ { \ array->count = 0; \ array->alloc = S * sizeof(T); \ array->data = NULL; \ } \ static inline T *al_array_data(N, S)(array(N, S) *array) \ { \ if (array->data) return array->data; \ else return array->inline_data; \ } \ AL_ARRAY_DEFINE_FUNCTIONS(N, T, S) \ static inline void al_array_reserve(N, S)(array(N, S) *array, u32 count) \ { \ if (S >= count) { \ return; \ } \ bool copy_inline = array->data == NULL; \ _al_array_reserve_internal(N, S)(array, count * sizeof(T)); \ if (UNLIKELY(copy_inline)) { \ al_memcpy(array->data, array->inline_data, array->count * sizeof(T)); \ } \ } #endif // _AL_ARRAY_TYPED_H