| /* |
| The MIT License(MIT) |
| Copyright(c) 2016 Peter Goldsborough |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy of |
| this software and associated documentation files(the "Software"), to deal in |
| the Software without restriction, including without limitation the rights to |
| use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
| the Software, and to permit persons to whom the Software is furnished to do so, |
| subject to the following conditions : |
| |
| The above copyright notice and this permission notice shall be included in all |
| copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
| FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR |
| COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #define __STDC_WANT_LIB_EXT1__ 1 |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "third_party/vector/vector.h" |
| |
| /***** PRIVATE *****/ |
| #define MAX(a, b) ((a) > (b) ? (a) : (b)) |
| |
| static bool _vector_should_grow(Vector *vector) { |
| assert(vector->size <= vector->capacity); |
| return vector->size == vector->capacity; |
| } |
| |
| static bool _vector_should_shrink(Vector *vector) { |
| assert(vector->size <= vector->capacity); |
| return vector->size == vector->capacity * VECTOR_SHRINK_THRESHOLD; |
| } |
| |
| static void *_vector_offset(Vector *vector, size_t index) { |
| // return vector->data + (index * vector->element_size); |
| return (unsigned char *)vector->data + (index * vector->element_size); |
| } |
| |
| static const void *_vector_const_offset(const Vector *vector, size_t index) { |
| // return vector->data + (index * vector->element_size); |
| return (unsigned char *)vector->data + (index * vector->element_size); |
| } |
| |
| static void _vector_assign(Vector *vector, size_t index, void *element) { |
| /* Insert the element */ |
| void *offset = _vector_offset(vector, index); |
| memcpy(offset, element, vector->element_size); |
| } |
| |
| static int _vector_move_right(Vector *vector, size_t index) { |
| assert(vector->size < vector->capacity); |
| |
| /* The location where to start to move from. */ |
| void *offset = _vector_offset(vector, index); |
| |
| /* How many to move to the right. */ |
| size_t elements_in_bytes = (vector->size - index) * vector->element_size; |
| |
| #ifdef __STDC_LIB_EXT1__ |
| size_t right_capacity_in_bytes = |
| (vector->capacity - (index + 1)) * vector->element_size; |
| |
| /* clang-format off */ |
| int return_code = memmove_s( |
| offset + vector->element_size, |
| right_capacity_in_bytes, |
| offset, |
| elements_in_bytes); |
| |
| /* clang-format on */ |
| |
| return return_code == 0 ? VECTOR_SUCCESS : VECTOR_ERROR; |
| |
| #else |
| // memmove(offset + vector->element_size, offset, elements_in_bytes); |
| memmove((unsigned char *)offset + vector->element_size, offset, |
| elements_in_bytes); |
| return VECTOR_SUCCESS; |
| #endif |
| } |
| |
| static void _vector_move_left(Vector *vector, size_t index) { |
| size_t right_elements_in_bytes; |
| void *offset; |
| |
| /* The offset into the memory */ |
| offset = _vector_offset(vector, index); |
| |
| /* How many to move to the left */ |
| right_elements_in_bytes = (vector->size - index - 1) * vector->element_size; |
| |
| // memmove(offset, offset + vector->element_size, right_elements_in_bytes); |
| memmove(offset, (unsigned char *)offset + vector->element_size, |
| right_elements_in_bytes); |
| } |
| |
| static int _vector_reallocate(Vector *vector, size_t new_capacity) { |
| size_t new_capacity_in_bytes; |
| void *old; |
| assert(vector != NULL); |
| |
| if (new_capacity < VECTOR_MINIMUM_CAPACITY) { |
| if (vector->capacity > VECTOR_MINIMUM_CAPACITY) { |
| new_capacity = VECTOR_MINIMUM_CAPACITY; |
| } else { |
| /* NO-OP */ |
| return VECTOR_SUCCESS; |
| } |
| } |
| |
| new_capacity_in_bytes = new_capacity * vector->element_size; |
| old = vector->data; |
| |
| if ((vector->data = malloc(new_capacity_in_bytes)) == NULL) { |
| return VECTOR_ERROR; |
| } |
| |
| #ifdef __STDC_LIB_EXT1__ |
| /* clang-format off */ |
| if (memcpy_s(vector->data, |
| new_capacity_in_bytes, |
| old, |
| aom_vector_byte_size(vector)) != 0) { |
| return VECTOR_ERROR; |
| } |
| /* clang-format on */ |
| #else |
| memcpy(vector->data, old, aom_vector_byte_size(vector)); |
| #endif |
| |
| vector->capacity = new_capacity; |
| |
| free(old); |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| static int _vector_adjust_capacity(Vector *vector) { |
| return _vector_reallocate(vector, |
| MAX(1, vector->size * VECTOR_GROWTH_FACTOR)); |
| } |
| |
| static void _vector_swap(size_t *first, size_t *second) { |
| size_t temp = *first; |
| *first = *second; |
| *second = temp; |
| } |
| |
| int aom_vector_setup(Vector *vector, size_t capacity, size_t element_size) { |
| assert(vector != NULL); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| |
| vector->size = 0; |
| vector->capacity = MAX(VECTOR_MINIMUM_CAPACITY, capacity); |
| vector->element_size = element_size; |
| vector->data = malloc(vector->capacity * element_size); |
| |
| return vector->data == NULL ? VECTOR_ERROR : VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_copy(Vector *destination, Vector *source) { |
| assert(destination != NULL); |
| assert(source != NULL); |
| assert(aom_vector_is_initialized(source)); |
| assert(!aom_vector_is_initialized(destination)); |
| |
| if (destination == NULL) return VECTOR_ERROR; |
| if (source == NULL) return VECTOR_ERROR; |
| if (aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
| if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
| |
| /* Copy ALL the data */ |
| destination->size = source->size; |
| destination->capacity = source->size * 2; |
| destination->element_size = source->element_size; |
| |
| /* Note that we are not necessarily allocating the same capacity */ |
| destination->data = malloc(destination->capacity * source->element_size); |
| if (destination->data == NULL) return VECTOR_ERROR; |
| |
| memcpy(destination->data, source->data, aom_vector_byte_size(source)); |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_copy_assign(Vector *destination, Vector *source) { |
| assert(destination != NULL); |
| assert(source != NULL); |
| assert(aom_vector_is_initialized(source)); |
| assert(aom_vector_is_initialized(destination)); |
| |
| if (destination == NULL) return VECTOR_ERROR; |
| if (source == NULL) return VECTOR_ERROR; |
| if (!aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
| if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
| |
| aom_vector_destroy(destination); |
| |
| return aom_vector_copy(destination, source); |
| } |
| |
| int aom_vector_move(Vector *destination, Vector *source) { |
| assert(destination != NULL); |
| assert(source != NULL); |
| |
| if (destination == NULL) return VECTOR_ERROR; |
| if (source == NULL) return VECTOR_ERROR; |
| |
| *destination = *source; |
| source->data = NULL; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_move_assign(Vector *destination, Vector *source) { |
| aom_vector_swap(destination, source); |
| return aom_vector_destroy(source); |
| } |
| |
| int aom_vector_swap(Vector *destination, Vector *source) { |
| void *temp; |
| |
| assert(destination != NULL); |
| assert(source != NULL); |
| assert(aom_vector_is_initialized(source)); |
| assert(aom_vector_is_initialized(destination)); |
| |
| if (destination == NULL) return VECTOR_ERROR; |
| if (source == NULL) return VECTOR_ERROR; |
| if (!aom_vector_is_initialized(destination)) return VECTOR_ERROR; |
| if (!aom_vector_is_initialized(source)) return VECTOR_ERROR; |
| |
| _vector_swap(&destination->size, &source->size); |
| _vector_swap(&destination->capacity, &source->capacity); |
| _vector_swap(&destination->element_size, &source->element_size); |
| |
| temp = destination->data; |
| destination->data = source->data; |
| source->data = temp; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_destroy(Vector *vector) { |
| assert(vector != NULL); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| |
| free(vector->data); |
| vector->data = NULL; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| /* Insertion */ |
| int aom_vector_push_back(Vector *vector, void *element) { |
| assert(vector != NULL); |
| assert(element != NULL); |
| |
| if (_vector_should_grow(vector)) { |
| if (_vector_adjust_capacity(vector) == VECTOR_ERROR) { |
| return VECTOR_ERROR; |
| } |
| } |
| |
| _vector_assign(vector, vector->size, element); |
| |
| ++vector->size; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_push_front(Vector *vector, void *element) { |
| return aom_vector_insert(vector, 0, element); |
| } |
| |
| int aom_vector_insert(Vector *vector, size_t index, void *element) { |
| void *offset; |
| |
| assert(vector != NULL); |
| assert(element != NULL); |
| assert(index <= vector->size); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| if (element == NULL) return VECTOR_ERROR; |
| if (vector->element_size == 0) return VECTOR_ERROR; |
| if (index > vector->size) return VECTOR_ERROR; |
| |
| if (_vector_should_grow(vector)) { |
| if (_vector_adjust_capacity(vector) == VECTOR_ERROR) { |
| return VECTOR_ERROR; |
| } |
| } |
| |
| /* Move other elements to the right */ |
| if (_vector_move_right(vector, index) == VECTOR_ERROR) { |
| return VECTOR_ERROR; |
| } |
| |
| /* Insert the element */ |
| offset = _vector_offset(vector, index); |
| memcpy(offset, element, vector->element_size); |
| ++vector->size; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_assign(Vector *vector, size_t index, void *element) { |
| assert(vector != NULL); |
| assert(element != NULL); |
| assert(index < vector->size); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| if (element == NULL) return VECTOR_ERROR; |
| if (vector->element_size == 0) return VECTOR_ERROR; |
| if (index >= vector->size) return VECTOR_ERROR; |
| |
| _vector_assign(vector, index, element); |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| /* Deletion */ |
| int aom_vector_pop_back(Vector *vector) { |
| assert(vector != NULL); |
| assert(vector->size > 0); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| if (vector->element_size == 0) return VECTOR_ERROR; |
| |
| --vector->size; |
| |
| #ifndef VECTOR_NO_SHRINK |
| if (_vector_should_shrink(vector)) { |
| _vector_adjust_capacity(vector); |
| } |
| #endif |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_pop_front(Vector *vector) { return aom_vector_erase(vector, 0); } |
| |
| int aom_vector_erase(Vector *vector, size_t index) { |
| assert(vector != NULL); |
| assert(index < vector->size); |
| |
| if (vector == NULL) return VECTOR_ERROR; |
| if (vector->element_size == 0) return VECTOR_ERROR; |
| if (index >= vector->size) return VECTOR_ERROR; |
| |
| /* Just overwrite */ |
| _vector_move_left(vector, index); |
| |
| #ifndef VECTOR_NO_SHRINK |
| if (--vector->size == vector->capacity / 4) { |
| _vector_adjust_capacity(vector); |
| } |
| #endif |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_clear(Vector *vector) { return aom_vector_resize(vector, 0); } |
| |
| /* Lookup */ |
| void *aom_vector_get(Vector *vector, size_t index) { |
| assert(vector != NULL); |
| assert(index < vector->size); |
| |
| if (vector == NULL) return NULL; |
| if (vector->element_size == 0) return NULL; |
| if (index >= vector->size) return NULL; |
| |
| return _vector_offset(vector, index); |
| } |
| |
| const void *aom_vector_const_get(const Vector *vector, size_t index) { |
| assert(vector != NULL); |
| assert(index < vector->size); |
| |
| if (vector == NULL) return NULL; |
| if (vector->element_size == 0) return NULL; |
| if (index >= vector->size) return NULL; |
| |
| return _vector_const_offset(vector, index); |
| } |
| |
| void *aom_vector_front(Vector *vector) { return aom_vector_get(vector, 0); } |
| |
| void *aom_vector_back(Vector *vector) { |
| return aom_vector_get(vector, vector->size - 1); |
| } |
| |
| /* Information */ |
| |
| bool aom_vector_is_initialized(const Vector *vector) { |
| return vector->data != NULL; |
| } |
| |
| size_t aom_vector_byte_size(const Vector *vector) { |
| return vector->size * vector->element_size; |
| } |
| |
| size_t aom_vector_free_space(const Vector *vector) { |
| return vector->capacity - vector->size; |
| } |
| |
| bool aom_vector_is_empty(const Vector *vector) { return vector->size == 0; } |
| |
| /* Memory management */ |
| int aom_vector_resize(Vector *vector, size_t new_size) { |
| if (new_size <= vector->capacity * VECTOR_SHRINK_THRESHOLD) { |
| vector->size = new_size; |
| if (_vector_reallocate(vector, new_size * VECTOR_GROWTH_FACTOR) == -1) { |
| return VECTOR_ERROR; |
| } |
| } else if (new_size > vector->capacity) { |
| if (_vector_reallocate(vector, new_size * VECTOR_GROWTH_FACTOR) == -1) { |
| return VECTOR_ERROR; |
| } |
| } |
| |
| vector->size = new_size; |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_reserve(Vector *vector, size_t minimum_capacity) { |
| if (minimum_capacity > vector->capacity) { |
| if (_vector_reallocate(vector, minimum_capacity) == VECTOR_ERROR) { |
| return VECTOR_ERROR; |
| } |
| } |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| int aom_vector_shrink_to_fit(Vector *vector) { |
| return _vector_reallocate(vector, vector->size); |
| } |
| |
| /* Iterators */ |
| Iterator aom_vector_begin(Vector *vector) { return aom_vector_iterator(vector, 0); } |
| |
| Iterator aom_vector_end(Vector *vector) { |
| return aom_vector_iterator(vector, vector->size); |
| } |
| |
| Iterator aom_vector_iterator(Vector *vector, size_t index) { |
| Iterator iterator = { NULL, 0 }; |
| |
| assert(vector != NULL); |
| assert(index <= vector->size); |
| |
| if (vector == NULL) return iterator; |
| if (index > vector->size) return iterator; |
| if (vector->element_size == 0) return iterator; |
| |
| iterator.pointer = _vector_offset(vector, index); |
| iterator.element_size = vector->element_size; |
| |
| return iterator; |
| } |
| |
| void *aom_iterator_get(Iterator *iterator) { return iterator->pointer; } |
| |
| int aom_iterator_erase(Vector *vector, Iterator *iterator) { |
| size_t index = aom_iterator_index(vector, iterator); |
| |
| if (aom_vector_erase(vector, index) == VECTOR_ERROR) { |
| return VECTOR_ERROR; |
| } |
| |
| *iterator = aom_vector_iterator(vector, index); |
| |
| return VECTOR_SUCCESS; |
| } |
| |
| void aom_iterator_increment(Iterator *iterator) { |
| assert(iterator != NULL); |
| // iterator->pointer += iterator->element_size; |
| iterator->pointer = |
| (unsigned char *)iterator->pointer + iterator->element_size; |
| } |
| |
| void aom_iterator_decrement(Iterator *iterator) { |
| assert(iterator != NULL); |
| // iterator->pointer -= iterator->element_size; |
| iterator->pointer = |
| (unsigned char *)iterator->pointer - iterator->element_size; |
| } |
| |
| void *aom_iterator_next(Iterator *iterator) { |
| void *current = iterator->pointer; |
| aom_iterator_increment(iterator); |
| |
| return current; |
| } |
| |
| void *aom_iterator_previous(Iterator *iterator) { |
| void *current = iterator->pointer; |
| aom_iterator_decrement(iterator); |
| |
| return current; |
| } |
| |
| bool aom_iterator_equals(Iterator *first, Iterator *second) { |
| assert(first->element_size == second->element_size); |
| return first->pointer == second->pointer; |
| } |
| |
| bool aom_iterator_is_before(Iterator *first, Iterator *second) { |
| assert(first->element_size == second->element_size); |
| return first->pointer < second->pointer; |
| } |
| |
| bool aom_iterator_is_after(Iterator *first, Iterator *second) { |
| assert(first->element_size == second->element_size); |
| return first->pointer > second->pointer; |
| } |
| |
| size_t aom_iterator_index(Vector *vector, Iterator *iterator) { |
| assert(vector != NULL); |
| assert(iterator != NULL); |
| // return (iterator->pointer - vector->data) / vector->element_size; |
| return ((unsigned char *)iterator->pointer - (unsigned char *)vector->data) / |
| vector->element_size; |
| } |