/* * vector.h * * Copyright (C) 2018 Aleksandar Andrejevic * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #ifndef __MONOLITHIUM_VECTOR_H__ #define __MONOLITHIUM_VECTOR_H__ #include "defs.h" #include "list.h" #ifndef VECTOR_REALLOC extern void *realloc(void*, size_t); #define VECTOR_REALLOC(p, s) realloc((p), (s)) #endif typedef struct { void *address; size_t length; } vector_buffer_t; typedef struct { list_entry_t link; vector_buffer_t buf; } vector_buffer_entry_t; typedef struct { size_t position; size_t size; list_entry_t buffer_list; } vector_t; static bool_t vector_insert_buffer(vector_t *vector, size_t position, const vector_buffer_t *buffer) { if (!buffer->length) return TRUE; list_entry_t *ptr = &vector->buffer_list; while (position) { list_entry_t *next = ptr->next; if (next == &vector->buffer_list) return FALSE; vector_buffer_entry_t *entry = CONTAINER_OF(next, vector_buffer_entry_t, link); if (entry->buf.length > position) { vector_buffer_entry_t *remaining = VECTOR_REALLOC(NULL, sizeof(vector_buffer_entry_t)); if (!remaining) return FALSE; remaining->buf.address = (void*)((uintptr_t)entry->buf.address + position); remaining->buf.length = entry->buf.length - position; entry->buf.length = position; list_put_after(next, &remaining->link); } position -= entry->buf.length; ptr = next; } vector_buffer_entry_t *entry = VECTOR_REALLOC(NULL, sizeof(vector_buffer_entry_t)); entry->buf = *buffer; list_put_after(ptr, &entry->link); vector->size += buffer->length; return TRUE; } static inline void vector_clear(vector_t *vector) { vector->position = vector->size = 0; while (vector->buffer_list.next != &vector->buffer_list) { list_entry_t *ptr = vector->buffer_list.next; list_remove(ptr); ptr = VECTOR_REALLOC(ptr, 0); } } static inline bool_t vector_init(vector_t *vector, vector_buffer_t *buffers, size_t num_buffers) { vector->position = vector->size = 0; list_init(&vector->buffer_list); int i; for (i = 0; i < num_buffers; i++) { if (!vector_insert_buffer(vector, vector->size, &buffers[i])) { vector_clear(vector); return FALSE; } } return TRUE; } static inline void vector_read_gather(vector_t *vector, void *data, size_t size) { size_t position = 0; list_entry_t *ptr; for (ptr = vector->buffer_list.next; ptr != &vector->buffer_list && position < vector->position + size; ptr = ptr->next) { vector_buffer_t *buffer = &CONTAINER_OF(ptr, vector_buffer_entry_t, link)->buf; uintptr_t start = position > vector->position ? position : vector->position; uintptr_t end = position + buffer->length < vector->position + size ? position + buffer->length : vector->position + size; if (start < end) { __builtin_memcpy((void*)((uintptr_t)data + start - vector->position), (void*)((uintptr_t)buffer->address + start - position), end - start); } position += buffer->length; } vector->position += size; } static inline void vector_write_scatter(vector_t *vector, const void *data, size_t size) { size_t position = 0; list_entry_t *ptr; for (ptr = vector->buffer_list.next; ptr != &vector->buffer_list && position < vector->position + size; ptr = ptr->next) { vector_buffer_t *buffer = &CONTAINER_OF(ptr, vector_buffer_entry_t, link)->buf; uintptr_t start = position > vector->position ? position : vector->position; uintptr_t end = position + buffer->length < vector->position + size ? position + buffer->length : vector->position + size; if (start < end) { __builtin_memcpy((void*)((uintptr_t)buffer->address + start - position), (void*)((uintptr_t)data + start - vector->position), end - start); } position += buffer->length; } vector->position += size; } static inline void vector_seek(vector_t *vector, size_t position) { vector->position = position < vector->size ? position : vector->size; } #endif