utilitiec/src/dynamicbuffer/dynamicbuffer.c
2024-06-13 15:28:21 +02:00

217 lines
5.2 KiB
C

/*
* This code is part of the strategy game operational-space.
* operational-space comes with ABSOLUTELY NO WARRANTY and is licensed under GPL-2.0.
* Copyright (C) 2024 VegOwOtenks, Sleppo04
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "dynamicbuffer.h"
int DynamicBuffer_Create(dynamic_buffer_t *destination, size_t initial_capacity)
{
return DynamicBuffer_CreateWithAllocator(destination, initial_capacity, NULL);
}
int DynamicBuffer_CreateWithAllocator(dynamic_buffer_t *destination, size_t initial_capacity, allocator_t* allocator)
{
if (destination == NULL) {
return EDESTADDRREQ;
}
// Some malloc() implementations return NULL and other return valid pointers on zero-byte-allocation, I'm not handling this shit
if (initial_capacity == 0) {
return EINVAL;
}
dynamic_buffer_t local;
local.allocator = allocator;
local.capacity = initial_capacity;
local.used = 0;
if (allocator != NULL) {
local.array = allocator->allocate(allocator, initial_capacity);
} else {
local.array = malloc(initial_capacity);
}
if (local.array == NULL) {
return ENOMEM;
}
destination[0] = local;
return EXIT_SUCCESS;
}
int DynamicBuffer_EnsureUnusedCapacity(dynamic_buffer_t* buffer, size_t needed_unused)
{
if (buffer == NULL) {
return EINVAL;
}
size_t unused_space = buffer->capacity - buffer->used;
if (needed_unused < unused_space) {
return EXIT_SUCCESS;
}
size_t needed_capacity = buffer->capacity + needed_unused;
int resize_code = DynamicBuffer_Resize(buffer, needed_capacity);
if (resize_code) {
// ENOMEM
return resize_code;
}
return EXIT_SUCCESS;
}
int DynamicBuffer_EnsureCapacity(dynamic_buffer_t* buffer, size_t minimal_capacity)
{
if (buffer == NULL) {
return EINVAL;
}
if (minimal_capacity < buffer->capacity) {
return EXIT_SUCCESS;
}
int resize_code = DynamicBuffer_Resize(buffer, minimal_capacity);
if (resize_code) {
// ENOMEM
return resize_code;
}
return EXIT_SUCCESS;
}
int DynamicBuffer_Resize(dynamic_buffer_t* buffer, size_t new_capacity)
{
if (buffer == NULL) {
return EINVAL;
}
if (new_capacity == 0) {
return EINVAL;
}
char* new_array;
if (buffer->allocator != NULL) {
new_array = buffer->allocator->reallocate(buffer->allocator, buffer->array, buffer->capacity, new_capacity);
} else {
new_array = realloc(buffer->array, new_capacity);
}
if (new_array == NULL) {
return ENOMEM;
}
buffer->array = new_array;
buffer->capacity = new_capacity;
return EXIT_SUCCESS;
}
int DynamicBuffer_Prune(dynamic_buffer_t* buffer)
{
if (buffer == NULL) {
return ENOMEM;
}
return DynamicBuffer_Resize(buffer, buffer->used);
}
int DynamicBuffer_Reset(dynamic_buffer_t* buffer)
{
if (buffer == NULL) {
return EINVAL;
}
buffer->used = 0;
return EXIT_SUCCESS;
}
int DynamicBuffer_RewindBytes(dynamic_buffer_t* buffer, size_t bytes)
{
if (buffer == NULL) {
return EINVAL;
}
if (buffer->used < bytes) {
return EBOUNDS;
}
buffer->used -= bytes;
return EXIT_SUCCESS;
}
int DynamicBuffer_Store(dynamic_buffer_t* buffer, const void* data, size_t data_size)
{
if (buffer == NULL) {
return EINVAL;
}
if (data == NULL) {
return EINVAL;
}
if (data_size == 0) {
return EXIT_SUCCESS;
}
int ensure_code = DynamicBuffer_EnsureUnusedCapacity(buffer, data_size);
if (ensure_code) {
// ENOMEM
return ensure_code;
}
void* destination = ((char*) buffer->array) + buffer->used;
memcpy(destination, data, data_size);
buffer->used += data_size;
return EXIT_SUCCESS;
}
size_t DynamicBuffer_GetBlockCount(dynamic_buffer_t* buffer, size_t block_size)
{
return buffer->used / block_size;
}
void* DynamicBuffer_ReadAt(dynamic_buffer_t* buffer, size_t offset)
{
if (offset >= buffer->used) {
return NULL;
}
return (void*) (((char*) buffer->array) + offset);
}
void* DynamicBuffer_ReadBlockAt(dynamic_buffer_t* buffer, size_t block_size, size_t index)
{
return DynamicBuffer_ReadAt(buffer, block_size * index);
}
int DynamicBuffer_Destroy(dynamic_buffer_t* buffer)
{
if (buffer == NULL) {
return EINVAL;
}
if (buffer->allocator == NULL) {
free(buffer->array);
} else {
buffer->allocator->free(buffer->allocator, buffer->array, buffer->capacity);
}
buffer->array = NULL;
buffer->capacity = 0;
buffer->used = 0;
return EXIT_SUCCESS;
}