kiba-engine
array.c
1 #include <kiba/containers/array.h>
2 
3 #include <kiba/core/memory.h>
4 
5 static inline void *_array_pointer_at_offset(void *arr, usize offset) {
6  array_header *header = _array_get_header(arr);
7  return (u8 *) (arr) + (offset * header->element_size);
8 }
9 
10 void *_array_create(usize initial_capacity, usize element_size, usize element_alignment, allocator *alloc) {
11  KB_ASSERT(alloc != KB_NULL, "allocator to use must be a valid pointer");
12  KB_ASSERT(initial_capacity != 0, "initial capacity must not be 0");
14  initial_capacity * element_size + sizeof(array_header),
15  KB_MAX(element_alignment, 8));
16  if (res != KB_NULL) {
17  res->size = 0;
18  res->capacity = initial_capacity;
19  res->element_size = element_size;
20  res->alloc = alloc;
21  ++res;
22  }
23  return res;
24 }
25 
26 void array_destroy(void *arr_ptr) {
27  void **arr = arr_ptr;
28  KB_ASSERT(arr != KB_NULL, "array must have initialized state");
29  if (*arr != KB_NULL) {
30  array_header *header = _array_get_header(*arr);
31  allocator_free(header->alloc, header);
32  *arr = KB_NULL;
33  }
34 }
35 
36 b8 array_reserve(void *arr_ptr, usize new_capacity) {
37  void **arr = arr_ptr;
38  array_header *header = _array_get_header(*arr);
39  if (new_capacity > header->capacity) {
40  array_header *new_arr =
41  allocator_reallocate(header->alloc, header, new_capacity * header->element_size + sizeof(array_header));
42  if (new_arr == KB_NULL) {
43  return false;
44  }
45  new_arr->capacity = new_capacity;
46  ++new_arr;
47  *arr = new_arr;
48  }
49  return true;
50 }
51 
52 b8 array_resize(void *arr_ptr, usize new_size) {
53  void **arr = arr_ptr;
54  array_header *header = _array_get_header(*arr);
55  if (new_size > header->capacity) {
56  if (!array_reserve(arr, new_size)) {
57  return false;
58  }
59  header = _array_get_header(*arr);
60  }
61  if (new_size > header->size) {
62  memory_zero((u8 *) *arr + header->size * header->element_size,
63  (new_size - header->size) * header->element_size);
64  }
65  header->size = new_size;
66  return true;
67 }
68 
69 void *array_clone(const void *arr, allocator *alloc) {
70  // TODO shoud the new array have the same capacity or just the necessary space
71  void *new_arr = _array_create(array_size(arr), array_element_size(arr), 1, alloc);
72  if (new_arr != KB_NULL) {
73  memory_copy(new_arr, arr, array_size(arr) * array_element_size(arr));
74  }
75  return new_arr;
76 }
77 
78 b8 array_push_checked(void *arr_ptr, void *element) {
79  void **arr = arr_ptr;
80  KB_ASSERT(arr != KB_NULL && *arr != KB_NULL, "array must have initialized state");
81  KB_ASSERT(element != KB_NULL, "pointer to element must be valid");
82  array_header *header = _array_get_header(*arr);
83  KB_ASSERT(header->size <= header->capacity,
84  "array capacity must not have been exceeded beforehand size: {usize} vs capacity: {usize}",
85  header->size,
86  header->capacity);
87  if (header->size == header->capacity) {
88  if (!array_reserve(arr, header->capacity * 2)) {
89  return false;
90  }
91  header = _array_get_header(*arr);
92  }
93  memory_copy(_array_pointer_at_offset(*arr, header->size++), element, header->element_size);
94  return true;
95 }
96 
97 b8 array_pop_checked(void *arr_ptr, void *element) {
98  void **arr = arr_ptr;
99  KB_ASSERT(arr != KB_NULL && *arr != KB_NULL, "array must have initialized state");
100  array_header *header = _array_get_header(*arr);
101  if (header->size == 0) {
102  return false;
103  }
104  --header->size;
105  if (element != KB_NULL) {
106  memory_copy(element, _array_pointer_at_offset(*arr, header->size), header->element_size);
107  }
108  return true;
109 }
110 
111 b8 array_insert(void *arr_ptr, usize index, void *element) {
112  void **arr = arr_ptr;
113  KB_ASSERT(arr != KB_NULL && *arr != KB_NULL, "array must have initialized state");
114  KB_ASSERT(element != KB_NULL, "pointer to read data from must not be nullptr");
115  array_header *header = _array_get_header(*arr);
116  if (index > header->size) {
117  KB_WARN("index out of range: index {usize} requested but array size only {usize}", index, header->size);
118  return false;
119  }
120  if (!array_push_checked(arr, element)) {
121  return false;
122  }
123  // move elements one index further starting from the back
124  usize move_count = header->size - index;
125  for (usize i = 0; i < move_count; ++i) {
126  memory_copy(_array_pointer_at_offset(*arr, header->size - 1 - i),
127  _array_pointer_at_offset(*arr, header->size - 2 - i),
128  header->element_size);
129  }
130  memory_copy(_array_pointer_at_offset(*arr, index), element, header->element_size);
131  return true;
132 }
133 
134 b8 array_remove(void *arr_ptr, usize index, void *element) {
135  void **arr = arr_ptr;
136  KB_ASSERT(arr != KB_NULL && *arr != KB_NULL, "array must have initialized state");
137  array_header *header = _array_get_header(*arr);
138  if (index >= header->size) {
139  KB_WARN("index out of range in array: index {usize} requested but array size only {usize}",
140  index,
141  header->size);
142  return false;
143  }
144  usize move_count = header->size - index;
145  if (element != KB_NULL) {
146  memory_copy(element, _array_pointer_at_offset(*arr, index), header->element_size);
147  }
148  if (move_count > 0) {
149  memory_copy(_array_pointer_at_offset(*arr, index),
150  _array_pointer_at_offset(*arr, index + 1),
151  move_count * header->element_size);
152  }
153  --header->size;
154  return true;
155 }
void * allocator_allocate_aligned(allocator *alloc, usize size, usize alignment)
Allocate aligned memory.
Definition: allocator.c:94
void * allocator_reallocate(allocator *alloc, void *original, usize new_size)
Reallocate memory to unaligned block.
Definition: allocator.c:107
void allocator_free(allocator *alloc, void *mem)
Give back memory to the allocator.
Definition: allocator.c:134
void * memory_copy(void *dst, const void *src, usize size)
Copy memory.
Definition: memory.c:83
void * memory_zero(void *mem, usize size)
Zero out memory.
Definition: memory.c:79
Lightweight layer between platform and other engine components to enable tracing/monitoring.
#define KB_MAX(x, y)
Ternary to get the maximum of two numbers.
Definition: defines.h:43
#define KB_NULL
Value of an invalid ptr (nullptr).
Definition: defines.h:18
#define KB_ASSERT(expr,...)
Perform runtime assertion and log failures.
Definition: log.h:133
#define KB_WARN(...)
Log entry with warn log level.
Definition: log.h:161
Central allocator structure.
Definition: allocator.h:87