#include "config.h" #include #include #include #include #include #include #include #include "logerr.h" #include "catalog.h" #include "i18n.h" #include "vector.h" struct Vector { void **values; size_t capacity; size_t back_count; size_t front_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, struct Vector **const out ) { int rc = -1; struct Vector v = { .values = NULL, .capacity = capacity, .back_count = 0U, .front_count = 0U, .max_capacity = max_capacity, .multiplier = multiplier, .value_size = value_size, }; struct Vector *restrict vref = 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; v.values = malloc(array_bytes_size); if (v.values == NULL) { logerr("malloc(%ld): %s\n", array_bytes_size, strerror(errno)); goto out; } vref = malloc(sizeof(*vref)); if (vref == NULL) { logerr("malloc(%ld): %s\n", sizeof(vref), strerror(errno)); goto out; } memcpy(vref, &v, sizeof(v)); *out = vref; rc = 0; out: if (rc) { if (vref != NULL) { free(vref); } if (v.values != NULL) { free(v.values); } } return rc; } int vector_new(const size_t value_size, 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); free(v->values); free((void *)v); } size_t vector_count(const struct Vector *const v) { const size_t count = v->back_count + v->front_count; assert(count <= v->capacity); return count; } 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]; // FIXME rc = 0; out: return rc; } static size_t next_capacity(const struct Vector *const v) { if (v->capacity > v->max_capacity / v->multiplier) { return v->max_capacity; } else { return v->capacity * v->multiplier; } } int vector_push_back(struct Vector *const v, void *const value) { int rc = -1; void *new_values = NULL; 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); const size_t new_size = new_capacity * v->value_size; new_values = realloc(v->values, new_size); if (new_values == NULL) { logerr( "realloc(v->values, %ld): %s\n", new_size, strerror(errno) ); goto out; } v->capacity = new_capacity; v->values = new_values; } v->values[v->back_count] = value; v->back_count++; rc = 0; out: if (rc) { if (new_values != NULL) { free(new_values); } } return rc; } int vector_push_front(struct Vector *const v, void *const value) { int rc = -1; void *new_values = NULL; 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) ); } const size_t new_capacity = next_capacity(v); const size_t new_size = new_capacity * v->value_size; new_values = realloc(v->values, new_size); if (new_values == NULL) { logerr( "realloc(v->values, %ld): %s\n", new_size, strerror(errno) ); goto out; } v->capacity = new_capacity; // FIXME: copy, but leaving things at the beginning } v->values[v->front_count] = value; v->front_count++; rc = 0; out: if (rc) { if (new_values != NULL) { free(new_values); } } return rc; } int vector_pop_back(struct Vector *const v, const void **const out) { int rc = -1; const size_t count = vector_count(v); if (count == 0) { logerr(_(MSG_ERR_VECTOR_UNDERFLOW)); goto out; } *out = v->values[v->back_count - 1]; // FIXME: can become negative! v->back_count--; rc = 0; out: return rc; } int vector_pop_front(struct Vector *const v, const void **const out) { int rc = -1; const size_t count = vector_count(v); if (count == 0) { logerr(_(MSG_ERR_VECTOR_UNDERFLOW)); goto out; } *out = v->values[v->front_count - 1]; // FIXME: can become negative! v->front_count--; rc = 0; out: return rc; }