/* Thing *things; growing_array_init(&things, sizeof(Thing)); growing_array_deinit(&things); Thing new_thing; growing_array_add(&things, &new_thing); // 'thing' is copied Thing *nth_thing = &things[n]; growing_array_reserve_count(&things, 690); growing_array_resize_count(&things, 69); // "Slow", but stuff in the array keeps the same order growing_array_ordered_remove_by_index(&things, i); // Fast, but will not keep stuff ordered growing_array_unordered_remove_by_index(&things, i); growing_array_ordered_remove_by_pointer(&things, nth_thing); growing_array_unordered_remove_by_pointer(&things, nth_thing); Thing thing_prototype; growing_array_ordered_remove_one_by_value(&things, thing_prototype); growing_array_unordered_remove_one_by_value(&things, thing_prototype); growing_array_ordered_remove_all_by_value(&things, thing_prototype); growing_array_unordered_remove_all_by_value(&things, thing_prototype); growing_array_get_valid_count(&things); growing_array_get_allocated_count(&things); */ typedef struct Growing_Array_Header { u32 valid_count; u32 allocated_count; u32 block_size_in_bytes; Allocator allocator; } Growing_Array_Header; void growing_array_init_reserve(void **array, u64 block_size_in_bytes, u64 count_to_reserve, Allocator allocator) { count_to_reserve = get_next_power_of_two(count_to_reserve); u64 bytes_to_allocate = count_to_reserve*block_size_in_bytes + sizeof(Growing_Array_Header); Growing_Array_Header *header = (Growing_Array_Header*)alloc(allocator, bytes_to_allocate); header->allocator = allocator; header->block_size_in_bytes = block_size_in_bytes; header->valid_count = 0; header->allocated_count = count_to_reserve; *array = header+1; } void growing_array_init(void **array, u64 block_size_in_bytes, Allocator allocator) { growing_array_init_reserve(array, block_size_in_bytes, 8, allocator); } void growing_array_deinit(void **array) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; dealloc(header->allocator, header); } void growing_array_reserve(void **array, u64 count_to_reserve) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; if (header->allocated_count >= count_to_reserve) return; u64 old_allocated_bytes = header->allocated_count*header->block_size_in_bytes+sizeof(Growing_Array_Header); count_to_reserve = get_next_power_of_two(count_to_reserve); u64 bytes_to_allocate = count_to_reserve*header->block_size_in_bytes+sizeof(Growing_Array_Header); Growing_Array_Header *new_header = (Growing_Array_Header*)alloc(header->allocator, bytes_to_allocate); memcpy(new_header, header, old_allocated_bytes); *array = new_header+1; new_header->allocated_count = count_to_reserve; dealloc(header->allocator, header); } void* growing_array_add_empty(void **array) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; growing_array_reserve(array, header->valid_count+1); // Pointer might have been invalidated after reserve header = ((Growing_Array_Header*)*array) - 1; void *item = (u8*)*array + header->valid_count*header->block_size_in_bytes; header->valid_count += 1; return item; } void growing_array_add(void **array, void *item) { void *new = growing_array_add_empty(array); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; memcpy(new, item, header->block_size_in_bytes); } void growing_array_resize(void **array, u64 new_count) { growing_array_reserve(array, new_count); Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; header->valid_count = new_count; } void growing_array_pop(void **array) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(header->valid_count > 0, "No items to pop in growing array"); header->valid_count -= 1; } void growing_array_clear(void **array) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; header->valid_count = 0; } void growing_array_ordered_remove_by_index(void **array, u32 index) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(index < header->valid_count, "Growing array index out of range"); if (index == header->valid_count-1) { growing_array_pop(array); return; } u64 byte_index = header->block_size_in_bytes*index; memcpy( (u8*)*array + byte_index, (u8*)*array + byte_index + header->block_size_in_bytes, (header->valid_count-index-1)*header->block_size_in_bytes ); header->valid_count -= 1; } void growing_array_unordered_remove_by_index(void **array, u32 index) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; assert(index < header->valid_count, "Growing array index out of range"); if (index == header->valid_count-1) { growing_array_pop(array); return; } u64 byte_index = header->block_size_in_bytes*index; u64 last_item_index = header->block_size_in_bytes*header->valid_count-header->block_size_in_bytes; memcpy( (u8*)*array + byte_index, (u8*)*array + last_item_index, header->block_size_in_bytes ); header->valid_count -= 1; } s32 growing_array_find_index_from_left_by_pointer(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; for (u32 i = 0; i < header->valid_count; i++) { void *next = (u8*)*array + i*header->block_size_in_bytes; if (next == p) { return i; } } return -1; } s32 growing_array_find_index_from_left_by_value(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; for (u32 i = 0; i < header->valid_count; i++) { void *next = (u8*)*array + i*header->block_size_in_bytes; if (bytes_match(next, p, header->block_size_in_bytes)) { return i; } } return -1; } bool growing_array_ordered_remove_by_pointer(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; s32 i = growing_array_find_index_from_left_by_pointer(array, p); if (i < 0) return false; growing_array_ordered_remove_by_index(array, i); return true; } bool growing_array_unordered_remove_by_pointer(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; s32 i = growing_array_find_index_from_left_by_pointer(array, p); if (i < 0) return false; growing_array_unordered_remove_by_index(array, i); return true; } bool growing_array_ordered_remove_one_by_value(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; s32 i = growing_array_find_index_from_left_by_value(array, p); if (i < 0) return false; growing_array_ordered_remove_by_index(array, i); return true; } bool growing_array_unordered_remove_one_by_value(void **array, void *p) { Growing_Array_Header *header = ((Growing_Array_Header*)*array) - 1; s32 i = growing_array_find_index_from_left_by_value(array, p); if (i < 0) return false; growing_array_unordered_remove_by_index(array, i); return true; } // #Incomplete // s32 growing_array_ordered_remove_one_by_value(void **array, void *p) // s32 growing_array_unordered_remove_one_by_value(void **array, void *p) u32 growing_array_get_valid_count(void *array) { Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; return header->valid_count; } u32 growing_array_get_allocated_count(void *array) { Growing_Array_Header *header = ((Growing_Array_Header*)array) - 1; return header->allocated_count; }