217 lines
5.2 KiB
C
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;
|
|
}
|