/* * 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; }