#include "config.h" #include #include #include #include #include #include #include #include #include "catalog.h" #include "i18n.h" #include "logerr.h" #include "math.h" #include "util.h" #include "vector.h" struct Vector { const void **values; size_t capacity; size_t count; const size_t max_capacity; const size_t multiplier; const size_t value_size; }; static const size_t VECTOR_MAX_CAPACITY = SIZE_MAX; static const size_t VECTOR_DEFAULT_CAPACITY = 8; static const size_t GROWTH_MULTIPLIER = 2; int vector_new_with( const size_t capacity, const size_t max_capacity, const size_t multiplier, const size_t value_size, const struct Vector **const out ) { int rc = -1; const struct Vector *ret = NULL; void *values = NULL; assert(capacity > 0); if (capacity > max_capacity) { logerr( _(MSG_ERR_VECTOR_MAX_CAPACITY), max_capacity, strerror(EOVERFLOW) ); rc = EOVERFLOW; goto out; } const size_t array_bytes_size = capacity * value_size; values = malloc(array_bytes_size); if (values == NULL) { logerr("malloc(): %s", strerror(errno)); goto out; } ret = malloc(sizeof(*ret)); if (ret == NULL) { logerr("malloc(): %s", strerror(errno)); goto out; } memcpy((void *)ret, &(struct Vector) { .values = values, .capacity = capacity, .count = 0U, .max_capacity = max_capacity, .multiplier = multiplier, .value_size = value_size, }, sizeof(*ret)); *out = ret; rc = 0; out: if (rc) { if (ret != NULL) { freeit((void *)&ret); } if (values != NULL) { freeit((void *)&values); } } return rc; } int vector_new(const size_t value_size, const struct Vector **const out) { return vector_new_with( VECTOR_DEFAULT_CAPACITY, VECTOR_MAX_CAPACITY, GROWTH_MULTIPLIER, value_size, out ); } void vector_free(const struct Vector **const v) { assert((*v) != NULL); const void **values = (*v)->values; freeit((void *)&values); freeit((void *)v); } size_t vector_capacity(const struct Vector *const v) { return v->capacity; } size_t vector_count(const struct Vector *const v) { return v->count; } static size_t next_capacity(const struct Vector *const v) { size_t ret; if (mul_size(v->capacity, v->multiplier, &ret)) { return v->max_capacity; } return ret; } static int next_size(const struct Vector *const v, const size_t capacity, size_t *const out) { return mul_size(v->value_size, capacity, out); } int vector_nth(const struct Vector *const v, const size_t idx, const void **const out) { int rc = -1; const size_t count = vector_count(v); if (idx >= count) { logerr(_(MSG_ERR_VECTOR_OUT_OF_BOUNDS), idx, count); goto out; } *out = v->values[idx]; rc = 0; out: return rc; } int vector_assign( const struct Vector *const v, const size_t idx, const void *const value ) { int rc = -1; const size_t count = vector_count(v); if (idx >= count) { logerr(_(MSG_ERR_VECTOR_OUT_OF_BOUNDS), idx, count); goto out; } memcpy(&v->values[idx], value, v->value_size); rc = 0; out: return rc; } int vector_push_back(const struct Vector *const v, const void *const value) { int rc = -1; void *new_values = NULL; struct Vector *const v_mut = (struct Vector *const)v; const size_t count = vector_count(v); if (count == v->capacity) { if (count == v->max_capacity) { logerr( _(MSG_ERR_VECTOR_MAX_CAPACITY), v->max_capacity, strerror(EOVERFLOW) ); rc = EOVERFLOW; goto out; } const size_t new_capacity = next_capacity(v); size_t new_size; if (next_size(v, new_capacity, &new_size)) { logerr( _(MSG_ERR_VECTOR_MAX_CAPACITY), v->max_capacity, strerror(EOVERFLOW) ); rc = EOVERFLOW; goto out; } new_values = realloc(v->values, new_size); if (new_values == NULL) { logerr("realloc(): %s", strerror(errno)); goto out; } v_mut->capacity = new_capacity; v_mut->values = new_values; } memcpy(&v->values[v->count], value, v->value_size); v_mut->count++; rc = 0; out: if (rc) { if (new_values != NULL) { freeit((void *)&new_values); } } return rc; } int vector_pop_back(const struct Vector *const v, const void **const out) { int rc = -1; struct Vector *const v_mut = (struct Vector *const)v; const size_t count = vector_count(v); if (count == 0) { logerr(_(MSG_ERR_VECTOR_UNDERFLOW)); goto out; } v_mut->count--; *out = v->values[v->count]; rc = 0; out: return rc; } bool vector_contains(const struct Vector *const v, const void *const value) { for (size_t i = 0; i < vector_count(v); i++) { if (memcmp(&v->values[i], value, v->value_size) == 0) { return true; } } return false; }