typedef struct
{
void *_buffer; // Actual data
size_t _size; // Number of elements
size_t _capacity; // Allocated number of elements
size_t _elementSize; // Element size
} array_t;
array_t *array_create(size_t elementSize)
{
array_t *array = malloc(sizeof(array_t));
array->_elementSize = elementSize;
array->_size = 0;
array->_capacity = 5; // start out with 5 elements. Tweak if desired. This just makes the life easier since there is always a buffer and we don't have to care about cases where it's NULL
array->_buffer = malloc(array->_capacity * array->_elementSize);
return array;
}
void array_delete(array_t *array)
{
free(array->_buffer);
free(array);
}
void __array_assert_size(array_t *array, size_t required) // Makes sure that the array fits
{
size_t toCopy = array->_size;
if(toCopy > size)
toCopy = size;
if(required > array->_capacity)
{
size_t nextCapacity = array->_capacity * 1.5; // Gives a nice grow curve. Alternatively doubling also works, gets messy with large arrays though
if(nextCapacity < required)
nextCapacity = required;
void *buffer = malloc(nextCapacity * array->_elementSize); // TODO: Handle errors
memcpy(buffer, array->_buffer, toCopy * array->_elementSize);
free(array->_buffer);
array->_buffer = buffer;
array->_capacity = nextCapacity;
}
else
{
size_t nextCapacity = array->_capacity >> 1;
if(nextCapacity >= required && nextCapacity > 5) // Keep at least space for 5 elements
{
void *buffer = malloc(nextCapacity * array->_elementSize); // TODO: Handle errors
memcpy(buffer, array->_buffer, toCopy * array->_elementSize);
free(array->_buffer);
array->_buffer = buffer;
array->_capacity = nextCapacity;
}
}
}
void array_copyin_data(array_t *array, void *data, size_t elements)
{
__array_assert_size(array, array->_size + elements);
memcpy(((char *)array->_buffer) + array->_size * array->_elementSize, data, elements * array->_elementSize);
array->_size += elements;
}
void array_copyout_data(array_t *array, void *data, size_t start, size_t elements)
{
if(start + elements >= array->_size)
{
printf("Trying to access elements [%d, %d) in array with only %d elements", start, start + elements, array->_size);
return;
}
memcpy((data, (char *)array->_buffer) + start * array->_elementSize, elements * array->_elementSize);
}
// Alternatively, you can also work with single elements at a time... Something like this:
void array_add_object(array_t *array, void *object)
{
__array_assert_size(array, array->_size + 1);
memcpy(((char *)array->_buffer) + array->_size * array->_elementSize, data, array->_elementSize);
array->_size ++;
}