diff --git a/util/vector.c b/util/vector.c new file mode 100644 index 0000000..93085b9 --- /dev/null +++ b/util/vector.c @@ -0,0 +1,91 @@ + +#include "vector.h" + +#include "../memory/memory.h" +#include "string.h" + + +vector_Vector *vector_Create(uintptr_t objectSize) { + vector_Vector *vec = kMalloc(sizeof(vector_Vector)); + vec->objectSize = objectSize; + vec->size = 0; + vec->data = 0; + + vec->data = kMalloc(objectSize); + vec->cap = objectSize; + + return vec; +} + +// Resizes the underlying buffer to a new capacity +static inline void __vector_Rebuffer(vector_Vector *vec, uintptr_t newcap) { + void *newbuf = kMalloc(newcap); + memcpy(newbuf, vec->data, vec->size); + kFree(vec->data); + vec->data = newbuf; + vec->cap = newcap; +} + +void vector_Destroy(vector_Vector *vec) { + kFree(vec->data); + kFree(vec); +} + +void *vector_Push(vector_Vector *vec, const void *data) { + vector_Append(vec, data, 1); + return vec->data + vec->size - vec->objectSize; +} + +void vector_Append(vector_Vector *vec, const void *data, uintptr_t n) { + uintptr_t oldsize = vec->size, addsize = vec->objectSize * n; + vector_Resize(vec, oldsize + addsize); + + if (data) + memcpy(vec->data + oldsize, data, addsize); + else + memset(vec->data + oldsize, 0, addsize); +} + +void vector_Resize(vector_Vector *vec, uintptr_t size) { + uintptr_t newsize = vec->size + size * vec->objectSize; + if (newsize > vec->cap) { + // grow the buffer exponentially + uint64_t newcap = vec->cap; + while (newcap < newsize) + newcap *= 2; + __vector_Rebuffer(vec, newcap); + } + vec->size = newsize; +} + +uintptr_t vector_Size(vector_Vector *vec) { + return vec->size / vec->objectSize; +} + +void vector_Clear(vector_Vector *vec) { + vec->size = 0; +} + +void vector_ShrinkBuffer(vector_Vector *vec) { + if (vec->size != vec->cap) + __vector_Rebuffer(vec, vec->size); +} + +uintptr_t vector_Capacity(vector_Vector *vec) { + return vec->cap / vec->objectSize; +} + +void vector_Reserve(vector_Vector *vec, uintptr_t cap) { + uintptr_t newcap = vec->objectSize * cap; + if (newcap > vec->cap) + __vector_Rebuffer(vec, newcap); +} + +void *vector_At(vector_Vector *vec, uintptr_t i) { + return vec->data + vec->objectSize * i; +} + +// Data returns the data buffer. +void *vector_Data(vector_Vector *vec) { + return vec->data; +} diff --git a/util/vector.h b/util/vector.h new file mode 100644 index 0000000..a0c2e35 --- /dev/null +++ b/util/vector.h @@ -0,0 +1,65 @@ +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// Vector is an automatic-resizing array. +typedef struct { + void * data; // actual data buffer + uintptr_t size, cap; // size of the data and buffer, in bytes + uintptr_t objectSize; // size of the object +} vector_Vector; + +// Create allocates a new vector. +vector_Vector *vector_Create(uintptr_t objectSize); + +// Destroy properly frees all data related to the structure, and itself. +void vector_Destroy(vector_Vector *vec); + +// Push pushes an object at the back of the vector. +// +// If data is NULL, the data is zeroed. +// +// Returns a pointer to data. +void *vector_Push(vector_Vector *vec, const void *data); + +// Append pushes multiple objects at the back of the buffer. +// +// If data is NULL, the data is zeroed. +void vector_Append(vector_Vector *vec, const void *data, uintptr_t n); + +// Resize resizes the vector to a new number of elements. +void vector_Resize(vector_Vector *vec, uintptr_t size); + +// Size returns the number of objects in a vector. +uintptr_t vector_Size(vector_Vector *vec); + +// Clear clears a vector, without resizing the buffer. +void vector_Clear(vector_Vector *vec); + +// ShrinkBuffer shrinks the internal buffer to exactly the size of the elements. +void vector_ShrinkBuffer(vector_Vector *vec); + +// Capacity returns the size of the internal buffer. +uintptr_t vector_Capacity(vector_Vector *vec); + +// Reserve reallocates the size of the buffer to CAP objects, +// if the current buffer is smaller. +void vector_Reserve(vector_Vector *vec, uintptr_t cap); + +// At returns the i-th object of the vector. +// +// No boundary test is performed. +void *vector_At(vector_Vector *vec, uintptr_t i); + +// Data returns the data buffer. +void *vector_Data(vector_Vector *vec); + + +#ifdef __cplusplus +} +#endif