Vector 0.0.2
Loading...
Searching...
No Matches
vector.c
Go to the documentation of this file.
1
7#include "vector.h"
8#include "memswap.h"
9
10#include <assert.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
20#define ASSERT_OVERFLOW(element_size, capacity, data_size, alloc_size, message) \
21 assert((data_size / element_size == capacity && alloc_size > data_size) && message);
22
24{
25 size_t element_size;
26 size_t capacity;
29 char memory[];
34};
35
36/* *
37* === Forward Declarations === *
38* */
39
43static size_t calculate_alloc_size (const size_t element_size,
44 const size_t capacity,
45 const size_t allocator_size,
46 const size_t ext_header_size);
47
51static void *get_allocator(const vector_t *const vector);
52
58static void *binary_find (const vector_t *const vector,
59 const void *const value,
60 const size_t start,
61 const size_t end,
62 const compare_t cmp,
63 void *const param);
64
70static ssize_t binary_find_index (const vector_t *const vector,
71 const void *const value,
72 const size_t start,
73 const size_t end,
74 const compare_t cmp,
75 void *param);
76
77
78/* *
79* === API Implementation === *
80* */
81
83{
84 assert(opts);
85 assert(opts->element_size);
86
87 const size_t alloc_size = calculate_alloc_size(opts->element_size,
88 opts->initial_cap,
89 opts->alloc_opts.size,
90 opts->ext_header_size);
91
92 vector_t *vector = (vector_t *) vector_alloc(alloc_size, opts->alloc_opts.data);
93 if (!vector)
94 {
95 return NULL;
96 }
97
98 (*vector) = (vector_t) {
100 .capacity = opts->initial_cap,
101 .ext_header_size = opts->ext_header_size,
102 .allocator_size = opts->alloc_opts.size,
103 };
104
105 /* copy allocator struct */
106 memcpy(get_allocator(vector), opts->alloc_opts.data, opts->alloc_opts.size);
107
108 return vector;
109}
110
111
112void vector_destroy(vector_t *const vector)
113{
114 assert(vector);
115 vector_free(vector, vector->memory);
116}
117
118
119vector_t *vector_clone(const vector_t *const vector)
120{
121 assert(vector);
122
123 const size_t alloc_size = calculate_alloc_size(vector->element_size,
124 vector->capacity,
125 vector->allocator_size,
126 vector->ext_header_size);
127
128 // inheriting original vectors allocation method
129 vector_t *clone = (vector_t *) vector_alloc(alloc_size, get_allocator(vector));
130 if (!clone)
131 {
132 return NULL;
133 }
134
135 memcpy(clone, vector, alloc_size);
136
137 return clone;
138}
139
140
141vector_status_t vector_resize(vector_t **const vector, const size_t capacity, const vector_status_t error)
142{
143 assert(vector && *vector);
144
145 const size_t alloc_size = calculate_alloc_size((*vector)->element_size,
146 capacity,
147 (*vector)->allocator_size,
148 (*vector)->ext_header_size);
149
150 vector_t *vec = (vector_t*) vector_realloc(*vector, alloc_size, get_allocator(*vector));
151 if (!vec)
152 {
153 return error;
154 }
155
156 vec->capacity = capacity;
157 *vector = vec;
158 return VECTOR_SUCCESS;
159}
160
161
162void* vector_get_ext_header(const vector_t *const vector)
163{
164 assert(vector);
165 assert((vector->ext_header_size != 0) && "trying to access extended header that wasn't alloc'd");
166 return (void*)vector->memory + vector->allocator_size;
167}
168
169
170size_t vector_ext_header_size(const vector_t *const vector)
171{
172 assert(vector);
173 return vector->ext_header_size;
174}
175
176
177size_t vector_data_offset(const vector_t *const vector)
178{
179 assert(vector);
180 return vector->ext_header_size + vector->allocator_size;
181}
182
183
185{
186 assert(vector);
187 return (alloc_opts_t) {
188 .size = vector->allocator_size,
189 .data = vector->allocator_size ? get_allocator(vector) : NULL,
190 };
191}
192
193
194size_t vector_element_size(const vector_t *const vector)
195{
196 assert(vector);
197 return vector->element_size;
198}
199
200
201size_t vector_capacity(const vector_t *const vector)
202{
203 assert(vector);
204 return vector->capacity;
205}
206
207
208size_t vector_capacity_bytes(const vector_t *const vector)
209{
210 assert(vector);
211 return vector->capacity * vector->element_size;
212}
213
214
215void *vector_linear_find(const vector_t *const vector, const size_t limit, const predicate_t predicate, void *param)
216{
217 assert(vector);
218 assert(predicate);
219
220 assert((limit <= vector->capacity) && "Vector out of capacity bounds!");
221
222 for (size_t i = 0; i < limit; ++i)
223 {
224 void *element = vector_get(vector, i);
225 if (predicate(element, param))
226 {
227 return element;
228 }
229 }
230 return NULL;
231}
232
233
234void *vector_binary_find(const vector_t *const vector,
235 const void *const value,
236 const size_t limit,
237 const compare_t cmp,
238 void *param)
239{
240 assert(vector);
241 assert(value);
242 assert(cmp);
243
244 assert((limit <= vector->capacity) && "Limit out of capacity bounds!");
245 return binary_find(vector, value, 0, limit, cmp, param);
246}
247
248
249ssize_t vector_binary_find_index(const vector_t *const vector,
250 const void *const value,
251 const size_t limit,
252 const compare_t cmp,
253 void *const param)
254{
255 assert(vector);
256 assert(value);
257 assert(cmp);
258
259 assert((limit <= vector->capacity) && "Limit out of capacity bounds!");
260 return binary_find_index(vector, value, 0, limit, cmp, param);
261}
262
263
264char *vector_data(const vector_t *const vector)
265{
266 assert(vector);
267 return (char*) vector->memory + vector_data_offset(vector);
268}
269
270
271void *vector_get(const vector_t *const vector, const size_t index)
272{
273 assert(vector);
274 assert((index < vector->capacity) && "Index out of capacity bounds!");
275
276 return (void*) (vector->memory + vector_data_offset(vector) + index * vector->element_size);
277}
278
279
280void vector_set(vector_t *const vector, const size_t index, const void *const value)
281{
282 assert((index < vector->capacity) && "Index out of capacity bounds!");
283 void *dest = vector_get(vector, index);
284 memcpy(dest, value, vector->element_size);
285}
286
287
288void vector_set_zero(vector_t *const vector, const size_t index)
289{
290 assert((index < vector->capacity) && "Index out of capacity bounds!");
291 void *dest = vector_get(vector, index);
292 memset(dest, 0x00, vector->element_size);
293}
294
295
296void vector_copy(const vector_t *const vector, char *const dest, const size_t offset, const size_t length)
297{
298 assert(dest);
299 assert(vector);
300 assert((offset + length <= vector->capacity) && "`offset + length` exceeds vector's capacity!");
301
302 memcpy(dest, vector_get(vector, offset), length * (vector->element_size));
303}
304
305
306void vector_move(const vector_t *const vector, char *dest, const size_t offset, const size_t length)
307{
308 assert(dest);
309 assert(vector);
310 assert((offset + length <= vector->capacity) && "`offset + length` exceeds vector's capacity!");
311
312 memmove(dest, vector_get(vector, offset), length * (vector->element_size));
313}
314
315
316void vector_part_copy(const vector_t *const vector,
317 char *dest,
318 const size_t offset,
319 const size_t length,
320 const size_t part_offset,
321 const size_t part_length)
322{
323 for (size_t i = offset; i < length; ++i)
324 {
325 char *src = (char *)vector_get(vector, i) + part_offset;
326 memcpy(dest, src, part_length);
327 dest += part_length;
328 }
329}
330
331
332
333
334void vector_spread(vector_t *const vector, const size_t index, const size_t amount)
335{
336 assert(vector);
337 assert(amount > 1);
338 assert((index < vector->capacity) && "Index out of capacity bounds!");
339 assert((index + amount <= vector->capacity) && "`index + amount` exceedes vector's capacity.");
340
341 size_t elements_set = 1;
342
343 /* copy elements exponentially through out the range */
344 for (; (elements_set + elements_set) <= amount; elements_set += elements_set)
345 {
346 void *dest = vector_get(vector, index + elements_set);
347 vector_copy(vector, dest, index, elements_set);
348 }
349 /* copy rest that left */
350 for (; elements_set < amount; ++elements_set)
351 {
352 void *dest = vector_get(vector, index + elements_set);
353 vector_copy(vector, dest, index + elements_set - 1, 1);
354 }
355}
356
357
358void vector_shift(vector_t *const vector, const size_t offset, const size_t length, const ssize_t shift)
359{
360 assert(vector);
361 assert(shift != 0);
362 assert((offset < vector->capacity) && "Offset out of bounds.");
363 assert(((ssize_t)offset + shift >= 0) && "Shifted range underflows allocated buffer");
364 assert((offset + shift + length <= vector->capacity) && "Shifted range exceedes capacity");
365
366 vector_move(vector, vector_get(vector, offset + shift), offset, length);
367}
368
369
370void vector_swap(vector_t *const vector, const size_t index_a, const size_t index_b)
371{
372 assert(vector);
373 assert(index_a != index_b);
374 assert(index_a < vector->capacity && index_b < vector->capacity);
375
376 void *a = vector_get(vector, index_a);
377 void *b = vector_get(vector, index_b);
378 memswap(a, b, vector->element_size);
379}
380
381
382int vector_foreach(const vector_t *const vector, const size_t limit, const foreach_t func, void *const param)
383{
384 assert(vector);
385 assert(limit && limit <= vector->capacity);
386 assert(func);
387
388 for (size_t i = 0; i < limit; ++i)
389 {
390 int status = func(vector_get(vector, i), param);
391 if (status) return status;
392 }
393
394 return 0;
395}
396
397
398int vector_aggregate(const vector_t *const vector, const size_t limit, const aggregate_t func, void *const acc, void *const param)
399{
400 assert(vector);
401 assert(limit && limit <= vector->capacity);
402 assert(func);
403
404 for (size_t i = 0; i < limit; ++i)
405 {
406 int status = func(vector_get(vector, i), acc, param);
407 if (status) return status;
408 }
409
410 return 0;
411}
412
413
414int vector_transform(vector_t *const vector, const size_t limit, const transform_t func, void *const param)
415{
416 assert(vector);
417 assert(limit && limit <= vector->capacity);
418 assert(func);
419
420 return vector_foreach(vector, limit, (foreach_t)func, param);
421}
422
423
424void * __attribute__((weak)) vector_alloc(const size_t alloc_size, void *const param)
425{
426 (void)param;
427 return malloc(alloc_size);
428}
429
430
431void * __attribute__((weak)) vector_realloc(void *ptr, const size_t alloc_size, void *const param)
432{
433 (void)param;
434 return realloc(ptr, alloc_size);
435}
436
437
438void __attribute__((weak)) vector_free(void *ptr, void *const param)
439{
440 (void)param;
441 free(ptr);
442}
443
444
445size_t calc_aligned_size(const size_t size, const size_t alignment)
446{
447 return (size + alignment - 1) / alignment * alignment;
448}
449
450
451ssize_t cmp_lex_asc(const void *value, const void *element, void *param)
452{
453 return memcmp(value, element, (size_t)param);
454}
455
456
457ssize_t cmp_lex_dsc(const void *value, const void *element, void *param)
458{
459 return memcmp(element, value, (size_t)param);
460}
461
462
463/* **
464* === Static Functions === *
465* */
466
467static size_t calculate_alloc_size(const size_t element_size,
468 const size_t capacity,
469 const size_t allocator_size,
470 const size_t ext_header_size)
471{
472 const size_t data_size = element_size * capacity;
473 const size_t alloc_size = sizeof(vector_t) + allocator_size + ext_header_size + data_size;
474 ASSERT_OVERFLOW(element_size, capacity, data_size, alloc_size, "allocation size overflow!");
475 return alloc_size;
476}
477
478
479static void *get_allocator(const vector_t *const vector)
480{
481 // assert((vector->allocator_size) && "No allocator region!");
482 return (char*)vector->memory;
483}
484
485
486static void *binary_find(const vector_t *const vector,
487 const void *const value,
488 const size_t start,
489 const size_t end,
490 const compare_t cmp,
491 void *param)
492{
493 if (start == end)
494 {
495 return NULL;
496 }
497
498 const size_t middle = (start + end) / 2;
499 void *middle_value = vector_get(vector, middle);
500
501 if (0 == cmp(value, middle_value, param))
502 {
503 return middle_value;
504 }
505
506 if (0 < cmp(value, middle_value, param))
507 {
508 return binary_find(vector, value, middle + 1, end, cmp, param);
509 }
510
511 return binary_find(vector, value, start, middle, cmp, param);
512}
513
514
515static ssize_t binary_find_index(const vector_t *const vector,
516 const void *const value,
517 const size_t start,
518 const size_t end,
519 const compare_t cmp,
520 void *param)
521{
522 if (start == end)
523 {
524 return -1;
525 }
526
527 const size_t middle = (start + end) / 2;
528 void *middle_value = vector_get(vector, middle);
529
530 if (0 == cmp(value, middle_value, param))
531 {
532 return middle;
533 }
534
535 if (0 < cmp(value, middle_value, param))
536 {
537 return binary_find_index(vector, value, middle + 1, end, cmp, param);
538 }
539
540 return binary_find_index(vector, value, start, middle, cmp, param);
541}
void * vector_realloc(void *const ptr, size_t alloc_size, void *const param)
Reallocates already allocated memory chunk in order to change allocation size.
void * vector_alloc(const size_t alloc_size, void *const param)
Allocates memory chunk of alloc_size.
void vector_free(void *const ptr, void *const param)
Free allocation that was previously allocated.
int(* foreach_t)(const void *const element, void *const param)
Callback determines an operation for vector_foreach.
Definition vector.h:120
int(* transform_t)(void *const element, void *const param)
Callback determines an operation for vector_transform.
Definition vector.h:145
bool(* predicate_t)(const void *const element, void *const param)
Predicate, tells if traversed element matches user's criteria.
Definition vector.h:97
int(* aggregate_t)(const void *const element, void *const acc, void *const param)
Callback determines an operation for vector_aggregate.
Definition vector.h:133
ssize_t(* compare_t)(const void *const value, const void *const element, void *const param)
Compare, used to define traversal order.
Definition vector.h:108
int vector_transform(vector_t *const vector, const size_t limit, const transform_t func, void *const param)
Perform mutable transformation on each element of the vector.
Definition vector.c:414
int vector_aggregate(const vector_t *const vector, const size_t limit, const aggregate_t func, void *const acc, void *const param)
Perform immutable accamulating action on each element of the vector.
Definition vector.c:398
void vector_shift(vector_t *const vector, const size_t offset, const size_t length, const ssize_t shift)
Shift range of elements.
Definition vector.c:358
void vector_part_copy(const vector_t *const vector, char *dest, const size_t offset, const size_t length, const size_t part_offset, const size_t part_length)
Partial copying.
Definition vector.c:316
void vector_spread(vector_t *const vector, const size_t index, const size_t amount)
Duplicates existing element across range.
Definition vector.c:334
void * vector_get(const vector_t *const vector, const size_t index)
Returns pointer for the element at index.
Definition vector.c:271
int vector_foreach(const vector_t *const vector, const size_t limit, const foreach_t func, void *const param)
Perform immutable action on each element of the vector.
Definition vector.c:382
void vector_move(const vector_t *const vector, char *dest, const size_t offset, const size_t length)
Moves range of the vector elements to another location.
Definition vector.c:306
void vector_set(vector_t *const vector, const size_t index, const void *const value)
Sets element at given index to a value.
Definition vector.c:280
void vector_copy(const vector_t *const vector, char *const dest, const size_t offset, const size_t length)
Copy element range to other location.
Definition vector.c:296
char * vector_data(const vector_t *const vector)
Gives a pointer to a location where elements' data begins.
Definition vector.c:264
void vector_swap(vector_t *const vector, const size_t index_a, const size_t index_b)
Swaps values of elements designated by indicies.
Definition vector.c:370
void vector_set_zero(vector_t *const vector, const size_t index)
Sets element at given index to a zero value.
Definition vector.c:288
size_t vector_data_offset(const vector_t *const vector)
Compute offset from vector_t::memory to first element.
Definition vector.c:177
size_t vector_ext_header_size(const vector_t *const vector)
Retrieves extended header size.
Definition vector.c:170
void * vector_get_ext_header(const vector_t *const vector)
Provides a location where user can put a header for the derived class.
Definition vector.c:162
vector_status_t vector_resize(vector_t **const vector, const size_t capacity, const vector_status_t error)
Performs allocation resize.
Definition vector.c:141
vector_t * vector_clone(const vector_t *const vector)
Duplicates a vector.
Definition vector.c:119
void vector_destroy(vector_t *const vector)
Deallocates vector.
Definition vector.c:112
vector_t * vector_create_(const vector_opts_t *const opts)
Vector contructor.
Definition vector.c:82
size_t vector_capacity_bytes(const vector_t *const vector)
Reports current capacity of the vector in bytes.
Definition vector.c:208
size_t vector_element_size(const vector_t *const vector)
Reports current element size.
Definition vector.c:194
size_t vector_capacity(const vector_t *const vector)
Reports current capacity of the vector.
Definition vector.c:201
alloc_opts_t vector_alloc_opts(const vector_t *const vector)
Access allocator options.
Definition vector.c:184
void * vector_linear_find(const vector_t *const vector, const size_t limit, const predicate_t predicate, void *param)
Simple linear search for unordered data.
Definition vector.c:215
void * vector_binary_find(const vector_t *const vector, const void *const value, const size_t limit, const compare_t cmp, void *param)
Run binary search on the vector.
Definition vector.c:234
ssize_t vector_binary_find_index(const vector_t *const vector, const void *const value, const size_t limit, const compare_t cmp, void *const param)
Run binary search on the vector.
Definition vector.c:249
ssize_t cmp_lex_asc(const void *value, const void *element, void *param)
Performs comparison in lexicographical ascending order.
Definition vector.c:451
size_t calc_aligned_size(const size_t size, const size_t alignment)
Function calculates size of the element while respecting requirement for alignment.
Definition vector.c:445
ssize_t cmp_lex_dsc(const void *value, const void *element, void *param)
Performs comparison in lexicographical descending order.
Definition vector.c:457
Allocator options.
Definition vector.h:35
size_t size
Size of the allocator data.
Definition vector.h:36
void * data
User defined allocator structure.
Definition vector.h:39
Vector options.
Definition vector.h:52
size_t element_size
Size of the underling element type.
Definition vector.h:56
alloc_opts_t alloc_opts
optional allocator
Definition vector.h:53
size_t initial_cap
Amount of elements that will be preallocated.
Definition vector.h:59
size_t ext_header_size
Size of the extention header.
Definition vector.h:54
Vector control structure type.
Definition vector.c:24
size_t allocator_size
Size of the allocator.
Definition vector.c:28
char memory[]
Beginning of the vector's memory region.
Definition vector.c:29
size_t capacity
Current amount of allocated elements.
Definition vector.c:26
size_t ext_header_size
Size of the extention header.
Definition vector.c:27
size_t element_size
Size of the underling element type.
Definition vector.c:25
static ssize_t binary_find_index(const vector_t *const vector, const void *const value, const size_t start, const size_t end, const compare_t cmp, void *param)
Performs binary search on a vectors range.
Definition vector.c:515
static size_t calculate_alloc_size(const size_t element_size, const size_t capacity, const size_t allocator_size, const size_t ext_header_size)
Calculates allocation size for the vector.
Definition vector.c:467
static void * get_allocator(const vector_t *const vector)
Access allocator region of the vector.
Definition vector.c:479
static void * binary_find(const vector_t *const vector, const void *const value, const size_t start, const size_t end, const compare_t cmp, void *const param)
Performs binary search on a vectors range.
Definition vector.c:486
Public interface of the vector.
vector_status_t
Status enum that indicates errors of operations that may fail.
Definition vector.h:68
@ VECTOR_SUCCESS
Definition vector.h:69