/src/aom/third_party/vector/vector.c
Line | Count | Source |
1 | | /* |
2 | | The MIT License(MIT) |
3 | | Copyright(c) 2016 Peter Goldsborough |
4 | | |
5 | | Permission is hereby granted, free of charge, to any person obtaining a copy of |
6 | | this software and associated documentation files (the "Software"), to deal in |
7 | | the Software without restriction, including without limitation the rights to |
8 | | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
9 | | the Software, and to permit persons to whom the Software is furnished to do so, |
10 | | subject to the following conditions : |
11 | | |
12 | | The above copyright notice and this permission notice shall be included in all |
13 | | copies or substantial portions of the Software. |
14 | | |
15 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
16 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
17 | | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR |
18 | | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
19 | | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
20 | | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
21 | | */ |
22 | | |
23 | | #define __STDC_WANT_LIB_EXT1__ 1 |
24 | | |
25 | | #include <assert.h> |
26 | | #include <stdlib.h> |
27 | | #include <string.h> |
28 | | |
29 | | #include "third_party/vector/vector.h" |
30 | | |
31 | | /***** PRIVATE *****/ |
32 | 0 | #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
33 | | |
34 | 0 | static bool _vector_should_grow(Vector *vector) { |
35 | 0 | assert(vector->size <= vector->capacity); |
36 | 0 | return vector->size == vector->capacity; |
37 | 0 | } |
38 | | |
39 | | #if 0 |
40 | | static bool _vector_should_shrink(Vector *vector) { |
41 | | assert(vector->size <= vector->capacity); |
42 | | return vector->size == vector->capacity * VECTOR_SHRINK_THRESHOLD; |
43 | | } |
44 | | #endif // 0 |
45 | | |
46 | 0 | static void *_vector_offset(Vector *vector, size_t index) { |
47 | | // return vector->data + (index * vector->element_size); |
48 | 0 | return (unsigned char *)vector->data + (index * vector->element_size); |
49 | 0 | } |
50 | | |
51 | | #if 0 |
52 | | static const void *_vector_const_offset(const Vector *vector, size_t index) { |
53 | | // return vector->data + (index * vector->element_size); |
54 | | return (unsigned char *)vector->data + (index * vector->element_size); |
55 | | } |
56 | | #endif // 0 |
57 | | |
58 | 0 | static void _vector_assign(Vector *vector, size_t index, void *element) { |
59 | | /* Insert the element */ |
60 | 0 | void *offset = _vector_offset(vector, index); |
61 | 0 | memcpy(offset, element, vector->element_size); |
62 | 0 | } |
63 | | |
64 | | #if 0 |
65 | | static int _vector_move_right(Vector *vector, size_t index) { |
66 | | assert(vector->size < vector->capacity); |
67 | | |
68 | | /* The location where to start to move from. */ |
69 | | void *offset = _vector_offset(vector, index); |
70 | | |
71 | | /* How many to move to the right. */ |
72 | | size_t elements_in_bytes = (vector->size - index) * vector->element_size; |
73 | | |
74 | | #ifdef __STDC_LIB_EXT1__ |
75 | | size_t right_capacity_in_bytes = |
76 | | (vector->capacity - (index + 1)) * vector->element_size; |
77 | | |
78 | | /* clang-format off */ |
79 | | int return_code = memmove_s( |
80 | | offset + vector->element_size, |
81 | | right_capacity_in_bytes, |
82 | | offset, |
83 | | elements_in_bytes); |
84 | | |
85 | | /* clang-format on */ |
86 | | |
87 | | return return_code == 0 ? VECTOR_SUCCESS : VECTOR_ERROR; |
88 | | |
89 | | #else |
90 | | // memmove(offset + vector->element_size, offset, elements_in_bytes); |
91 | | memmove((unsigned char *)offset + vector->element_size, offset, |
92 | | elements_in_bytes); |
93 | | return VECTOR_SUCCESS; |
94 | | #endif |
95 | | } |
96 | | |
97 | | static void _vector_move_left(Vector *vector, size_t index) { |
98 | | size_t right_elements_in_bytes; |
99 | | void *offset; |
100 | | |
101 | | /* The offset into the memory */ |
102 | | offset = _vector_offset(vector, index); |
103 | | |
104 | | /* How many to move to the left */ |
105 | | right_elements_in_bytes = (vector->size - index - 1) * vector->element_size; |
106 | | |
107 | | // memmove(offset, offset + vector->element_size, right_elements_in_bytes); |
108 | | memmove(offset, (unsigned char *)offset + vector->element_size, |
109 | | right_elements_in_bytes); |
110 | | } |
111 | | #endif // 0 |
112 | | |
113 | 0 | static int _vector_reallocate(Vector *vector, size_t new_capacity) { |
114 | 0 | size_t new_capacity_in_bytes; |
115 | 0 | void *old; |
116 | 0 | assert(vector != NULL); |
117 | | |
118 | 0 | if (new_capacity < VECTOR_MINIMUM_CAPACITY) { |
119 | 0 | if (vector->capacity > VECTOR_MINIMUM_CAPACITY) { |
120 | 0 | new_capacity = VECTOR_MINIMUM_CAPACITY; |
121 | 0 | } else { |
122 | | /* NO-OP */ |
123 | 0 | return VECTOR_SUCCESS; |
124 | 0 | } |
125 | 0 | } |
126 | | |
127 | 0 | new_capacity_in_bytes = new_capacity * vector->element_size; |
128 | 0 | old = vector->data; |
129 | |
|
130 | 0 | if ((vector->data = malloc(new_capacity_in_bytes)) == NULL) { |
131 | 0 | return VECTOR_ERROR; |
132 | 0 | } |
133 | | |
134 | | #ifdef __STDC_LIB_EXT1__ |
135 | | /* clang-format off */ |
136 | | if (memcpy_s(vector->data, |
137 | | new_capacity_in_bytes, |
138 | | old, |
139 | | aom_vector_byte_size(vector)) != 0) { |
140 | | return VECTOR_ERROR; |
141 | | } |
142 | | /* clang-format on */ |
143 | | #else |
144 | 0 | memcpy(vector->data, old, aom_vector_byte_size(vector)); |
145 | 0 | #endif |
146 | |
|
147 | 0 | vector->capacity = new_capacity; |
148 | |
|
149 | 0 | free(old); |
150 | |
|
151 | 0 | return VECTOR_SUCCESS; |
152 | 0 | } |
153 | | |
154 | 0 | static int _vector_adjust_capacity(Vector *vector) { |
155 | 0 | return _vector_reallocate(vector, |
156 | 0 | MAX(1, vector->size * VECTOR_GROWTH_FACTOR)); |
157 | 0 | } |
158 | | |
159 | | #if 0 |
160 | | static void _vector_swap(size_t *first, size_t *second) { |
161 | | size_t temp = *first; |
162 | | *first = *second; |
163 | | *second = temp; |
164 | | } |
165 | | #endif // 0 |
166 | | |
167 | 0 | int aom_vector_setup(Vector *vector, size_t capacity, size_t element_size) { |
168 | 0 | assert(vector != NULL); |
169 | | |
170 | 0 | if (vector == NULL) return VECTOR_ERROR; |
171 | | |
172 | 0 | vector->size = 0; |
173 | 0 | vector->capacity = MAX(VECTOR_MINIMUM_CAPACITY, capacity); |
174 | 0 | vector->element_size = element_size; |
175 | 0 | vector->data = malloc(vector->capacity * element_size); |
176 | |
|
177 | 0 | return vector->data == NULL ? VECTOR_ERROR : VECTOR_SUCCESS; |
178 | 0 | } |
179 | | |
180 | | #if 0 |
181 | | int aom_vector_copy(Vector *destination, Vector *source) { |
182 | | assert(destination != NULL); |
183 | | assert(source != NULL); |
184 | | assert(aom_vector_is_initialized(source)); |
185 | | assert(!aom_vector_is_initialized(destination)); |
186 | | |
187 | | if (destination == NULL) return VECTOR_ERROR; |
188 | | if (source == NULL) return VECTOR_ERROR; |
189 | | if (aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
190 | | if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
191 | | |
192 | | /* Copy ALL the data */ |
193 | | destination->size = source->size; |
194 | | destination->capacity = source->size * 2; |
195 | | destination->element_size = source->element_size; |
196 | | |
197 | | /* Note that we are not necessarily allocating the same capacity */ |
198 | | destination->data = malloc(destination->capacity * source->element_size); |
199 | | if (destination->data == NULL) return VECTOR_ERROR; |
200 | | |
201 | | memcpy(destination->data, source->data, aom_vector_byte_size(source)); |
202 | | |
203 | | return VECTOR_SUCCESS; |
204 | | } |
205 | | |
206 | | int aom_vector_copy_assign(Vector *destination, Vector *source) { |
207 | | assert(destination != NULL); |
208 | | assert(source != NULL); |
209 | | assert(aom_vector_is_initialized(source)); |
210 | | assert(aom_vector_is_initialized(destination)); |
211 | | |
212 | | if (destination == NULL) return VECTOR_ERROR; |
213 | | if (source == NULL) return VECTOR_ERROR; |
214 | | if (!aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
215 | | if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
216 | | |
217 | | aom_vector_destroy(destination); |
218 | | |
219 | | return aom_vector_copy(destination, source); |
220 | | } |
221 | | |
222 | | int aom_vector_move(Vector *destination, Vector *source) { |
223 | | assert(destination != NULL); |
224 | | assert(source != NULL); |
225 | | |
226 | | if (destination == NULL) return VECTOR_ERROR; |
227 | | if (source == NULL) return VECTOR_ERROR; |
228 | | |
229 | | *destination = *source; |
230 | | source->data = NULL; |
231 | | |
232 | | return VECTOR_SUCCESS; |
233 | | } |
234 | | |
235 | | int aom_vector_move_assign(Vector *destination, Vector *source) { |
236 | | aom_vector_swap(destination, source); |
237 | | return aom_vector_destroy(source); |
238 | | } |
239 | | |
240 | | int aom_vector_swap(Vector *destination, Vector *source) { |
241 | | void *temp; |
242 | | |
243 | | assert(destination != NULL); |
244 | | assert(source != NULL); |
245 | | assert(aom_vector_is_initialized(source)); |
246 | | assert(aom_vector_is_initialized(destination)); |
247 | | |
248 | | if (destination == NULL) return VECTOR_ERROR; |
249 | | if (source == NULL) return VECTOR_ERROR; |
250 | | if (!aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
251 | | if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
252 | | |
253 | | _vector_swap(&destination->size, &source->size); |
254 | | _vector_swap(&destination->capacity, &source->capacity); |
255 | | _vector_swap(&destination->element_size, &source->element_size); |
256 | | |
257 | | temp = destination->data; |
258 | | destination->data = source->data; |
259 | | source->data = temp; |
260 | | |
261 | | return VECTOR_SUCCESS; |
262 | | } |
263 | | #endif // 0 |
264 | | |
265 | 0 | int aom_vector_destroy(Vector *vector) { |
266 | 0 | assert(vector != NULL); |
267 | | |
268 | 0 | if (vector == NULL) return VECTOR_ERROR; |
269 | | |
270 | 0 | free(vector->data); |
271 | 0 | vector->data = NULL; |
272 | |
|
273 | 0 | return VECTOR_SUCCESS; |
274 | 0 | } |
275 | | |
276 | | /* Insertion */ |
277 | 0 | int aom_vector_push_back(Vector *vector, void *element) { |
278 | 0 | assert(vector != NULL); |
279 | 0 | assert(element != NULL); |
280 | | |
281 | 0 | if (_vector_should_grow(vector)) { |
282 | 0 | if (_vector_adjust_capacity(vector) == VECTOR_ERROR) { |
283 | 0 | return VECTOR_ERROR; |
284 | 0 | } |
285 | 0 | } |
286 | | |
287 | 0 | _vector_assign(vector, vector->size, element); |
288 | |
|
289 | 0 | ++vector->size; |
290 | |
|
291 | 0 | return VECTOR_SUCCESS; |
292 | 0 | } |
293 | | |
294 | | #if 0 |
295 | | int aom_vector_push_front(Vector *vector, void *element) { |
296 | | return aom_vector_insert(vector, 0, element); |
297 | | } |
298 | | |
299 | | int aom_vector_insert(Vector *vector, size_t index, void *element) { |
300 | | void *offset; |
301 | | |
302 | | assert(vector != NULL); |
303 | | assert(element != NULL); |
304 | | assert(index <= vector->size); |
305 | | |
306 | | if (vector == NULL) return VECTOR_ERROR; |
307 | | if (element == NULL) return VECTOR_ERROR; |
308 | | if (vector->element_size == 0) return VECTOR_ERROR; |
309 | | if (index > vector->size) return VECTOR_ERROR; |
310 | | |
311 | | if (_vector_should_grow(vector)) { |
312 | | if (_vector_adjust_capacity(vector) == VECTOR_ERROR) { |
313 | | return VECTOR_ERROR; |
314 | | } |
315 | | } |
316 | | |
317 | | /* Move other elements to the right */ |
318 | | if (_vector_move_right(vector, index) == VECTOR_ERROR) { |
319 | | return VECTOR_ERROR; |
320 | | } |
321 | | |
322 | | /* Insert the element */ |
323 | | offset = _vector_offset(vector, index); |
324 | | memcpy(offset, element, vector->element_size); |
325 | | ++vector->size; |
326 | | |
327 | | return VECTOR_SUCCESS; |
328 | | } |
329 | | |
330 | | int aom_vector_assign(Vector *vector, size_t index, void *element) { |
331 | | assert(vector != NULL); |
332 | | assert(element != NULL); |
333 | | assert(index < vector->size); |
334 | | |
335 | | if (vector == NULL) return VECTOR_ERROR; |
336 | | if (element == NULL) return VECTOR_ERROR; |
337 | | if (vector->element_size == 0) return VECTOR_ERROR; |
338 | | if (index >= vector->size) return VECTOR_ERROR; |
339 | | |
340 | | _vector_assign(vector, index, element); |
341 | | |
342 | | return VECTOR_SUCCESS; |
343 | | } |
344 | | |
345 | | /* Deletion */ |
346 | | int aom_vector_pop_back(Vector *vector) { |
347 | | assert(vector != NULL); |
348 | | assert(vector->size > 0); |
349 | | |
350 | | if (vector == NULL) return VECTOR_ERROR; |
351 | | if (vector->element_size == 0) return VECTOR_ERROR; |
352 | | |
353 | | --vector->size; |
354 | | |
355 | | #ifndef VECTOR_NO_SHRINK |
356 | | if (_vector_should_shrink(vector)) { |
357 | | _vector_adjust_capacity(vector); |
358 | | } |
359 | | #endif |
360 | | |
361 | | return VECTOR_SUCCESS; |
362 | | } |
363 | | |
364 | | int aom_vector_pop_front(Vector *vector) { return aom_vector_erase(vector, 0); } |
365 | | |
366 | | int aom_vector_erase(Vector *vector, size_t index) { |
367 | | assert(vector != NULL); |
368 | | assert(index < vector->size); |
369 | | |
370 | | if (vector == NULL) return VECTOR_ERROR; |
371 | | if (vector->element_size == 0) return VECTOR_ERROR; |
372 | | if (index >= vector->size) return VECTOR_ERROR; |
373 | | |
374 | | /* Just overwrite */ |
375 | | _vector_move_left(vector, index); |
376 | | |
377 | | #ifndef VECTOR_NO_SHRINK |
378 | | if (--vector->size == vector->capacity / 4) { |
379 | | _vector_adjust_capacity(vector); |
380 | | } |
381 | | #endif |
382 | | |
383 | | return VECTOR_SUCCESS; |
384 | | } |
385 | | |
386 | | int aom_vector_clear(Vector *vector) { return aom_vector_resize(vector, 0); } |
387 | | |
388 | | /* Lookup */ |
389 | | void *aom_vector_get(Vector *vector, size_t index) { |
390 | | assert(vector != NULL); |
391 | | assert(index < vector->size); |
392 | | |
393 | | if (vector == NULL) return NULL; |
394 | | if (vector->element_size == 0) return NULL; |
395 | | if (index >= vector->size) return NULL; |
396 | | |
397 | | return _vector_offset(vector, index); |
398 | | } |
399 | | |
400 | | const void *aom_vector_const_get(const Vector *vector, size_t index) { |
401 | | assert(vector != NULL); |
402 | | assert(index < vector->size); |
403 | | |
404 | | if (vector == NULL) return NULL; |
405 | | if (vector->element_size == 0) return NULL; |
406 | | if (index >= vector->size) return NULL; |
407 | | |
408 | | return _vector_const_offset(vector, index); |
409 | | } |
410 | | |
411 | | void *aom_vector_front(Vector *vector) { return aom_vector_get(vector, 0); } |
412 | | |
413 | | void *aom_vector_back(Vector *vector) { |
414 | | return aom_vector_get(vector, vector->size - 1); |
415 | | } |
416 | | #endif // 0 |
417 | | |
418 | | /* Information */ |
419 | | |
420 | 0 | bool aom_vector_is_initialized(const Vector *vector) { |
421 | 0 | return vector->data != NULL; |
422 | 0 | } |
423 | | |
424 | 0 | size_t aom_vector_byte_size(const Vector *vector) { |
425 | 0 | return vector->size * vector->element_size; |
426 | 0 | } |
427 | | |
428 | | #if 0 |
429 | | size_t aom_vector_free_space(const Vector *vector) { |
430 | | return vector->capacity - vector->size; |
431 | | } |
432 | | |
433 | | bool aom_vector_is_empty(const Vector *vector) { return vector->size == 0; } |
434 | | |
435 | | /* Memory management */ |
436 | | int aom_vector_resize(Vector *vector, size_t new_size) { |
437 | | if (new_size <= vector->capacity * VECTOR_SHRINK_THRESHOLD) { |
438 | | vector->size = new_size; |
439 | | if (_vector_reallocate(vector, new_size * VECTOR_GROWTH_FACTOR) == -1) { |
440 | | return VECTOR_ERROR; |
441 | | } |
442 | | } else if (new_size > vector->capacity) { |
443 | | if (_vector_reallocate(vector, new_size * VECTOR_GROWTH_FACTOR) == -1) { |
444 | | return VECTOR_ERROR; |
445 | | } |
446 | | } |
447 | | |
448 | | vector->size = new_size; |
449 | | |
450 | | return VECTOR_SUCCESS; |
451 | | } |
452 | | |
453 | | int aom_vector_reserve(Vector *vector, size_t minimum_capacity) { |
454 | | if (minimum_capacity > vector->capacity) { |
455 | | if (_vector_reallocate(vector, minimum_capacity) == VECTOR_ERROR) { |
456 | | return VECTOR_ERROR; |
457 | | } |
458 | | } |
459 | | |
460 | | return VECTOR_SUCCESS; |
461 | | } |
462 | | |
463 | | int aom_vector_shrink_to_fit(Vector *vector) { |
464 | | return _vector_reallocate(vector, vector->size); |
465 | | } |
466 | | #endif // 0 |
467 | | |
468 | | /* Iterators */ |
469 | 0 | Iterator aom_vector_begin(Vector *vector) { return aom_vector_iterator(vector, 0); } |
470 | | |
471 | | #if 0 |
472 | | Iterator aom_vector_end(Vector *vector) { |
473 | | return aom_vector_iterator(vector, vector->size); |
474 | | } |
475 | | #endif // 0 |
476 | | |
477 | 0 | Iterator aom_vector_iterator(Vector *vector, size_t index) { |
478 | 0 | Iterator iterator = { NULL, 0 }; |
479 | |
|
480 | 0 | assert(vector != NULL); |
481 | 0 | assert(index <= vector->size); |
482 | | |
483 | 0 | if (vector == NULL) return iterator; |
484 | 0 | if (index > vector->size) return iterator; |
485 | 0 | if (vector->element_size == 0) return iterator; |
486 | | |
487 | 0 | iterator.pointer = _vector_offset(vector, index); |
488 | 0 | iterator.element_size = vector->element_size; |
489 | |
|
490 | 0 | return iterator; |
491 | 0 | } |
492 | | |
493 | 0 | void *aom_iterator_get(Iterator *iterator) { return iterator->pointer; } |
494 | | |
495 | | #if 0 |
496 | | int aom_iterator_erase(Vector *vector, Iterator *iterator) { |
497 | | size_t index = aom_iterator_index(vector, iterator); |
498 | | |
499 | | if (aom_vector_erase(vector, index) == VECTOR_ERROR) { |
500 | | return VECTOR_ERROR; |
501 | | } |
502 | | |
503 | | *iterator = aom_vector_iterator(vector, index); |
504 | | |
505 | | return VECTOR_SUCCESS; |
506 | | } |
507 | | #endif // 0 |
508 | | |
509 | 0 | void aom_iterator_increment(Iterator *iterator) { |
510 | 0 | assert(iterator != NULL); |
511 | | // iterator->pointer += iterator->element_size; |
512 | 0 | iterator->pointer = |
513 | 0 | (unsigned char *)iterator->pointer + iterator->element_size; |
514 | 0 | } |
515 | | |
516 | | #if 0 |
517 | | void aom_iterator_decrement(Iterator *iterator) { |
518 | | assert(iterator != NULL); |
519 | | // iterator->pointer -= iterator->element_size; |
520 | | iterator->pointer = |
521 | | (unsigned char *)iterator->pointer - iterator->element_size; |
522 | | } |
523 | | |
524 | | void *aom_iterator_next(Iterator *iterator) { |
525 | | void *current = iterator->pointer; |
526 | | aom_iterator_increment(iterator); |
527 | | |
528 | | return current; |
529 | | } |
530 | | |
531 | | void *aom_iterator_previous(Iterator *iterator) { |
532 | | void *current = iterator->pointer; |
533 | | aom_iterator_decrement(iterator); |
534 | | |
535 | | return current; |
536 | | } |
537 | | |
538 | | bool aom_iterator_equals(Iterator *first, Iterator *second) { |
539 | | assert(first->element_size == second->element_size); |
540 | | return first->pointer == second->pointer; |
541 | | } |
542 | | |
543 | | bool aom_iterator_is_before(Iterator *first, Iterator *second) { |
544 | | assert(first->element_size == second->element_size); |
545 | | return first->pointer < second->pointer; |
546 | | } |
547 | | |
548 | | bool aom_iterator_is_after(Iterator *first, Iterator *second) { |
549 | | assert(first->element_size == second->element_size); |
550 | | return first->pointer > second->pointer; |
551 | | } |
552 | | |
553 | | size_t aom_iterator_index(Vector *vector, Iterator *iterator) { |
554 | | assert(vector != NULL); |
555 | | assert(iterator != NULL); |
556 | | // return (iterator->pointer - vector->data) / vector->element_size; |
557 | | return ((unsigned char *)iterator->pointer - (unsigned char *)vector->data) / |
558 | | vector->element_size; |
559 | | } |
560 | | #endif // 0 |