#define ARRAY_GROW_FORMULA(x) (2*(x) + 8) GB_STATIC_ASSERT(ARRAY_GROW_FORMULA(0) > 0); #if 1 template struct Array { gbAllocator allocator; T * data; isize count; isize capacity; T &operator[](isize index) { #if !defined(NO_ARRAY_BOUNDS_CHECK) GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); #endif return data[index]; } T const &operator[](isize index) const { #if !defined(NO_ARRAY_BOUNDS_CHECK) GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); #endif return data[index]; } }; template void array_init (Array *array, gbAllocator const &a); template void array_init (Array *array, gbAllocator const &a, isize count); template void array_init (Array *array, gbAllocator const &a, isize count, isize capacity); template Array array_make (gbAllocator const &a); template Array array_make (gbAllocator const &a, isize count); template Array array_make (gbAllocator const &a, isize count, isize capacity); template Array array_make_from_ptr (T *data, isize count, isize capacity); template void array_free (Array *array); template void array_add (Array *array, T const &t); template T * array_add_and_get (Array *array); template void array_add_elems (Array *array, T const *elems, isize elem_count); template T array_pop (Array *array); template void array_clear (Array *array); template void array_reserve (Array *array, isize capacity); template void array_resize (Array *array, isize count); template void array_set_capacity (Array *array, isize capacity); template Array array_slice (Array const &array, isize lo, isize hi); template Array array_clone (gbAllocator const &a, Array const &array); template void array_ordered_remove (Array *array, isize index); template void array_unordered_remove(Array *array, isize index); template void array_copy(Array *array, Array const &data, isize offset); template void array_copy(Array *array, Array const &data, isize offset, isize count); template T *array_end_ptr(Array *array); template struct Slice { T *data; isize count; T &operator[](isize index) { #if !defined(NO_ARRAY_BOUNDS_CHECK) GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); #endif return data[index]; } T const &operator[](isize index) const { #if !defined(NO_ARRAY_BOUNDS_CHECK) GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count); #endif return data[index]; } }; template Slice slice_from_array(Array const &a); template Slice slice_make(gbAllocator const &allocator, isize count) { Slice s = {}; s.data = gb_alloc_array(allocator, T, count); s.count = count; return s; } template Slice slice_from_array(Array const &a) { return {a.data, a.count}; } template Slice slice_array(Array const &array, isize lo, isize hi) { GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count); Slice out = {}; isize len = hi-lo; if (len > 0) { out.data = array.data+lo; out.count = len; } return out; } template Slice slice_clone(gbAllocator const &allocator, Slice const &a) { T *data = cast(T *)gb_alloc_copy_align(allocator, a.data, a.count*gb_size_of(T), gb_align_of(T)); return {data, a.count}; } template Slice slice_clone_from_array(gbAllocator const &allocator, Array const &a) { auto c = array_clone(allocator, a); return {c.data, c.count}; } template void slice_copy(Slice *slice, Slice const &data) { isize n = gb_min(slice->count, data.count); gb_memmove(slice->data, data.data, gb_size_of(T)*n); } template void slice_copy(Slice *slice, Slice const &data, isize offset) { isize n = gb_clamp(slice->count-offset, 0, data.count); gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n); } template void slice_copy(Slice *slice, Slice const &data, isize offset, isize count) { isize n = gb_clamp(slice->count-offset, 0, gb_min(data.count, count)); gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n); } template void slice_ordered_remove(Slice *array, isize index) { GB_ASSERT(0 <= index && index < array->count); isize bytes = gb_size_of(T) * (array->count-(index+1)); gb_memmove(array->data+index, array->data+index+1, bytes); array->count -= 1; } template void slice_unordered_remove(Slice *array, isize index) { GB_ASSERT(0 <= index && index < array->count); isize n = array->count-1; if (index != n) { gb_memmove(array->data+index, array->data+n, gb_size_of(T)); } array->count -= 1; } template void array_copy(Array *array, Array const &data, isize offset) { gb_memmove(array->data+offset, data.data, gb_size_of(T)*data.count); } template void array_copy(Array *array, Array const &data, isize offset, isize count) { gb_memmove(array->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count)); } template T *array_end_ptr(Array *array) { if (array->count > 0) { return &array->data[array->count-1]; } return nullptr; } template gb_inline void array_init(Array *array, gbAllocator const &a) { isize cap = ARRAY_GROW_FORMULA(0); array_init(array, a, 0, cap); } template gb_inline void array_init(Array *array, gbAllocator const &a, isize count) { array_init(array, a, count, count); } template gb_inline void array_init(Array *array, gbAllocator const &a, isize count, isize capacity) { array->allocator = a; array->data = nullptr; if (capacity > 0) { array->data = gb_alloc_array(a, T, capacity); } array->count = count; array->capacity = capacity; } template gb_inline Array array_make_from_ptr(T *data, isize count, isize capacity) { Array a = {0}; a.data = data; a.count = count; a.capacity = capacity; return a; } template gb_inline Array array_make(gbAllocator const &a) { isize capacity = ARRAY_GROW_FORMULA(0); Array array = {}; array.allocator = a; array.data = gb_alloc_array(a, T, capacity); array.count = 0; array.capacity = capacity; return array; } template gb_inline Array array_make(gbAllocator const &a, isize count) { Array array = {}; array.allocator = a; array.data = gb_alloc_array(a, T, count); array.count = count; array.capacity = count; return array; } template gb_inline Array array_make(gbAllocator const &a, isize count, isize capacity) { Array array = {}; array.allocator = a; array.data = gb_alloc_array(a, T, capacity); array.count = count; array.capacity = capacity; return array; } template gb_inline void array_free(Array *array) { if (array->allocator.proc != nullptr) { gb_free(array->allocator, array->data); } array->count = 0; array->capacity = 0; } template void array__grow(Array *array, isize min_capacity) { isize new_capacity = ARRAY_GROW_FORMULA(array->capacity); if (new_capacity < min_capacity) { new_capacity = min_capacity; } array_set_capacity(array, new_capacity); } template void array_add(Array *array, T const &t) { if (array->capacity < array->count+1) { array__grow(array, 0); } array->data[array->count] = t; array->count++; } template T *array_add_and_get(Array *array) { if (array->count < array->capacity) { return &array->data[array->count++]; } if (array->capacity < array->count+1) { array__grow(array, 0); } return &array->data[array->count++]; } template void array_add_elems(Array *array, T const *elems, isize elem_count) { GB_ASSERT(elem_count >= 0); if (array->capacity < array->count+elem_count) { array__grow(array, array->count+elem_count); } gb_memmove(array->data + array->count, elems, elem_count * gb_size_of(T)); array->count += elem_count; } template gb_inline T array_pop(Array *array) { GB_ASSERT(array->count > 0); array->count--; return array->data[array->count]; } template void array_clear(Array *array) { array->count = 0; } template void array_reserve(Array *array, isize capacity) { if (array->capacity < capacity) { array_set_capacity(array, capacity); } } template void array_resize(Array *array, isize count) { if (array->capacity < count) { array__grow(array, count); } array->count = count; } template void array_set_capacity(Array *array, isize capacity) { if (capacity == array->capacity) { return; } if (capacity < array->count) { array_resize(array, capacity); } T *new_data = nullptr; #if 0 // NOTE(bill): try gb_resize_align first, and then fallback to alloc+memmove+free isize old_size = array->capacity * gb_size_of(T); isize new_size = capacity * gb_size_of(T); new_data = cast(T *)gb_resize_align(array->allocator, array->data, old_size, new_size, gb_align_of(T)); #endif if (new_data == nullptr) { if (capacity > 0) { new_data = gb_alloc_array(array->allocator, T, capacity); GB_ASSERT(new_data != nullptr); gb_memmove(new_data, array->data, gb_size_of(T) * array->capacity); } gb_free(array->allocator, array->data); } array->data = new_data; array->capacity = capacity; } template gb_inline Array array_slice(Array const &array, isize lo, isize hi) { GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count); Array out = {}; isize len = hi-lo; if (len > 0) { out.data = array.data+lo; out.count = len; out.capacity = len; } return out; } template Array array_clone(gbAllocator const &allocator, Array const &array) { auto clone = array_make(allocator, array.count, array.count); array_copy(&clone, array, 0); return clone; } template void array_ordered_remove(Array *array, isize index) { GB_ASSERT(0 <= index && index < array->count); isize bytes = gb_size_of(T) * (array->count-(index+1)); gb_memmove(array->data+index, array->data+index+1, bytes); array->count -= 1; } template void array_unordered_remove(Array *array, isize index) { GB_ASSERT(0 <= index && index < array->count); isize n = array->count-1; if (index != n) { gb_memmove(array->data+index, array->data+n, gb_size_of(T)); } array_pop(array); } #endif #if 0 #define Array(Type_) struct { \ gbAllocator const &allocator; \ Type_ * e; \ isize count; \ isize capacity; \ } typedef Array(void) ArrayVoid; #define array_init_reserve(x_, allocator_, init_capacity_) do { \ void **e = cast(void **)&((x_)->e); \ GB_ASSERT((x_) != nullptr); \ (x_)->allocator = (allocator_); \ (x_)->count = 0; \ (x_)->capacity = (init_capacity_); \ *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_capacity_)); \ } while (0) #define array_init_count(x_, allocator_, init_count_) do { \ void **e = cast(void **)&((x_)->e); \ GB_ASSERT((x_) != nullptr); \ (x_)->allocator = (allocator_); \ (x_)->count = (init_count_); \ (x_)->capacity = (init_count_); \ *e = gb_alloc((allocator_), gb_size_of(*(x_)->e)*(init_count_)); \ } while (0) #define array_init(x_, allocator_) do { array_init_reserve(x_, allocator_, ARRAY_GROW_FORMULA(0)); } while (0) #define array_free(x_) do { gb_free((x_)->allocator, (x_)->e); } while (0) #define array_set_capacity(x_, capacity_) do { array__set_capacity((x_), (capacity_), gb_size_of(*(x_)->e)); } while (0) #define array_grow(x_, min_capacity_) do { \ isize new_capacity = ARRAY_GROW_FORMULA((x_)->capacity); \ if (new_capacity < (min_capacity_)) { \ new_capacity = (min_capacity_); \ } \ array_set_capacity(x_, new_capacity); \ } while (0) #define array_add(x_, item_) do { \ if ((x_)->capacity < (x_)->count+1) { \ array_grow(x_, 0); \ } \ (x_)->e[(x_)->count++] = item_; \ } while (0) #define array_pop(x_) do { GB_ASSERT((x_)->count > 0); (x_)->count--; } while (0) #define array_clear(x_) do { (x_)->count = 0; } while (0) #define array_resize(x_, new_count_) do { \ if ((x_)->capacity < (new_count_)) { \ array_grow((x_), (new_count_)); \ } \ (x_)->count = (new_count_); \ } while (0) #define array_reserve(x_, new_capacity_) do { \ if ((x_)->capacity < (new_capacity_)) { \ array_set_capacity((x_), (new_capacity_)); \ } \ } while (0) void array__set_capacity(void *ptr, isize capacity, isize element_size) { ArrayVoid *x = cast(ArrayVoid *)ptr; GB_ASSERT(ptr != nullptr); GB_ASSERT(element_size > 0); if (capacity == x->capacity) { return; } if (capacity < x->count) { if (x->capacity < capacity) { isize new_capacity = ARRAY_GROW_FORMULA(x->capacity); if (new_capacity < capacity) { new_capacity = capacity; } array__set_capacity(ptr, new_capacity, element_size); } x->count = capacity; } x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity); x->capacity = capacity; } #endif