541 lines
15 KiB
C
541 lines
15 KiB
C
/*
|
|
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;
|
|
}
|