Actually add growing array
This commit is contained in:
parent
c7daaac338
commit
04ca22a0ed
2 changed files with 335 additions and 0 deletions
74
oogabooga/examples/growing_array_example.c
Normal file
74
oogabooga/examples/growing_array_example.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
|
||||
typedef struct Circle {
|
||||
Vector2 pos;
|
||||
float radius;
|
||||
} Circle;
|
||||
|
||||
int entry(int argc, char **argv) {
|
||||
|
||||
window.title = STR("Minimal Game Example");
|
||||
window.scaled_width = 1280; // We need to set the scaled size if we want to handle system scaling (DPI)
|
||||
window.scaled_height = 720;
|
||||
window.x = 200;
|
||||
window.y = 90;
|
||||
window.clear_color = hex_to_rgba(0x6495EDff);
|
||||
|
||||
Circle *circles;
|
||||
growing_array_init((void**)&circles, sizeof(Circle), get_heap_allocator());
|
||||
|
||||
const int num_circles = 10000;
|
||||
const float radius_min = 8.0;
|
||||
const float radius_max = 32.0;
|
||||
|
||||
const float hover_radius = 200;
|
||||
|
||||
os_update(); // We set scaled window size, os_update updates the pixel window size values for us
|
||||
|
||||
for (int i = 0; i < num_circles; i++) {
|
||||
Circle c;
|
||||
c.radius = get_random_float32_in_range(radius_min, radius_max);
|
||||
c.pos.x = get_random_float32_in_range(-(f32)window.width/2.0+c.radius, (f32)window.width/2.0-c.radius);
|
||||
c.pos.y = get_random_float32_in_range(-(f32)window.height/2.0+c.radius, (f32)window.height/2.0-c.radius);
|
||||
growing_array_add((void**)&circles, &c);
|
||||
assert(circles[i].radius == c.radius);
|
||||
assert(circles[i].pos.x == c.pos.x);
|
||||
assert(circles[i].pos.y == c.pos.y);
|
||||
}
|
||||
|
||||
float64 last_time = os_get_current_time_in_seconds();
|
||||
while (!window.should_close) {
|
||||
float64 now = os_get_current_time_in_seconds();
|
||||
if ((int)now != (int)last_time) log("%.2f FPS\n%.2fms", 1.0/(now-last_time), (now-last_time)*1000);
|
||||
last_time = now;
|
||||
|
||||
reset_temporary_storage();
|
||||
|
||||
draw_frame.projection = m4_make_orthographic_projection(window.pixel_width * -0.5, window.pixel_width * 0.5, window.pixel_height * -0.5, window.pixel_height * 0.5, -1, 10);
|
||||
|
||||
|
||||
float mx = input_frame.mouse_x - window.width/2;
|
||||
float my = input_frame.mouse_y - window.height/2;
|
||||
|
||||
// We build an array on the fly each frame for all the hovered circles
|
||||
Circle *circles_hovered;
|
||||
growing_array_init_reserve((void**)&circles_hovered, sizeof(Circle), num_circles, get_temporary_allocator());
|
||||
for (int i = 0; i < num_circles; i++) {
|
||||
float distance = v2_length(v2_sub(v2(mx, my), circles[i].pos));
|
||||
if (distance <= hover_radius) {
|
||||
growing_array_add((void**)&circles_hovered, &circles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
for (int i = 0; i < growing_array_get_valid_count(circles_hovered); i++) {
|
||||
Circle c = circles_hovered[i];
|
||||
draw_circle(v2_sub(c.pos, v2(c.radius, c.radius)), v2(c.radius, c.radius), COLOR_GREEN);
|
||||
}
|
||||
|
||||
os_update();
|
||||
gfx_update();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
261
oogabooga/growing_array.c
Normal file
261
oogabooga/growing_array.c
Normal file
|
@ -0,0 +1,261 @@
|
|||
|
||||
/*
|
||||
|
||||
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;
|
||||
}
|
Reference in a new issue