src/basic_mempool.c

Wed, 03 Aug 2022 17:27:55 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 03 Aug 2022 17:27:55 +0200
changeset 571
f83583a0bbac
child 572
f0f99dd06d9f
permissions
-rw-r--r--

#201 - add mempool implementation

universe@571 1 /*
universe@571 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@571 3 *
universe@571 4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
universe@571 5 *
universe@571 6 * Redistribution and use in source and binary forms, with or without
universe@571 7 * modification, are permitted provided that the following conditions are met:
universe@571 8 *
universe@571 9 * 1. Redistributions of source code must retain the above copyright
universe@571 10 * notice, this list of conditions and the following disclaimer.
universe@571 11 *
universe@571 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@571 13 * notice, this list of conditions and the following disclaimer in the
universe@571 14 * documentation and/or other materials provided with the distribution.
universe@571 15 *
universe@571 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@571 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@571 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@571 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@571 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@571 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@571 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@571 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@571 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@571 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@571 26 * POSSIBILITY OF SUCH DAMAGE.
universe@571 27 */
universe@571 28
universe@571 29 #include "cx/basic_mempool.h"
universe@571 30 #include "cx/utils.h"
universe@571 31 #include <stdint.h>
universe@571 32 #include <string.h>
universe@571 33
universe@571 34 #define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL
universe@571 35
universe@571 36 /** Internal structure for denoting pooled memory. */
universe@571 37 typedef struct {
universe@571 38 /** The destructor. */
universe@571 39 cx_destructor_func destructor;
universe@571 40 /**
universe@571 41 * Access to the first byte of the polled memory.
universe@571 42 */
universe@571 43 char c;
universe@571 44 } cx_basic_mempool_memory;
universe@571 45
universe@571 46 static int cx_basic_mempool_chcap(
universe@571 47 struct cx_basic_mempool_s *pool,
universe@571 48 size_t newcap
universe@571 49 ) {
universe@571 50 if (newcap < pool->ndata) {
universe@571 51 return 1;
universe@571 52 }
universe@571 53
universe@571 54 size_t newcapsz;
universe@571 55 if (cx_szmul(newcap, sizeof(void *), &newcapsz)) {
universe@571 56 return 1;
universe@571 57 }
universe@571 58
universe@571 59 void **data = realloc(pool->data, newcapsz);
universe@571 60 if (data) {
universe@571 61 pool->data = data;
universe@571 62 pool->size = newcap;
universe@571 63 return 0;
universe@571 64 } else {
universe@571 65 return 1;
universe@571 66 }
universe@571 67 }
universe@571 68
universe@571 69 void *cx_malloc_basic_mempool(
universe@571 70 void *data,
universe@571 71 size_t n
universe@571 72 ) {
universe@571 73 of_chk_(n);
universe@571 74 struct cx_basic_mempool_s *pool = data;
universe@571 75
universe@571 76 if (pool->ndata >= pool->size) {
universe@571 77 size_t newcap = pool->size * 2;
universe@571 78 if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) {
universe@571 79 return NULL;
universe@571 80 }
universe@571 81 }
universe@571 82
universe@571 83 cx_basic_mempool_memory *mem = cxMalloc(pool->allocator,
universe@571 84 sizeof(cx_destructor_func) + n);
universe@571 85 if (mem == NULL) {
universe@571 86 return NULL;
universe@571 87 }
universe@571 88
universe@571 89 mem->destructor = NULL;
universe@571 90 pool->data[pool->ndata] = mem;
universe@571 91 pool->ndata++;
universe@571 92
universe@571 93 return &(mem->c);
universe@571 94 }
universe@571 95
universe@571 96 void *cx_calloc_basic_mempool(
universe@571 97 void *data,
universe@571 98 size_t nelem,
universe@571 99 size_t elsize
universe@571 100 ) {
universe@571 101 size_t msz;
universe@571 102 if (cx_szmul(nelem, elsize, &msz)) {
universe@571 103 return NULL;
universe@571 104 }
universe@571 105 void *ptr = cx_malloc_basic_mempool(data, msz);
universe@571 106 if (ptr == NULL) {
universe@571 107 return NULL;
universe@571 108 }
universe@571 109 memset(ptr, 0, nelem * elsize);
universe@571 110 return ptr;
universe@571 111 }
universe@571 112
universe@571 113 void *cx_realloc_basic_mempool(
universe@571 114 void *data,
universe@571 115 void *ptr,
universe@571 116 size_t n
universe@571 117 ) {
universe@571 118 of_chk_(n);
universe@571 119 struct cx_basic_mempool_s *pool = data;
universe@571 120
universe@571 121 char *mem = ((char *) ptr) - sizeof(cx_destructor_func);
universe@571 122 char *newm = (char *) cxRealloc(pool->allocator, mem,
universe@571 123 n + sizeof(cx_destructor_func));
universe@571 124 if (newm == NULL) {
universe@571 125 return NULL;
universe@571 126 }
universe@571 127 if (mem != newm) {
universe@571 128 cx_for_n(i, pool->ndata) {
universe@571 129 if (pool->data[i] == mem) {
universe@571 130 pool->data[i] = newm;
universe@571 131 return newm + sizeof(cx_destructor_func);
universe@571 132 }
universe@571 133 }
universe@571 134 abort();
universe@571 135 } else {
universe@571 136 return newm + sizeof(cx_destructor_func);
universe@571 137 }
universe@571 138 }
universe@571 139
universe@571 140 void cx_free_basic_mempool(
universe@571 141 void *data,
universe@571 142 void *ptr
universe@571 143 ) {
universe@571 144 struct cx_basic_mempool_s *pool = data;
universe@571 145
universe@571 146 cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *)
universe@571 147 ((char *) ptr - sizeof(cx_destructor_func));
universe@571 148 cx_for_n(i, pool->ndata) {
universe@571 149 if (mem == pool->data[i]) {
universe@571 150 if (mem->destructor != NULL) {
universe@571 151 mem->destructor(&(mem->c));
universe@571 152 }
universe@571 153 cxFree(pool->allocator, mem);
universe@571 154 size_t last_index = pool->ndata - 1;
universe@571 155 if (i != last_index) {
universe@571 156 pool->data[i] = pool->data[last_index];
universe@571 157 pool->data[last_index] = NULL;
universe@571 158 }
universe@571 159 pool->ndata--;
universe@571 160 return;
universe@571 161 }
universe@571 162 }
universe@571 163 abort();
universe@571 164 }
universe@571 165
universe@571 166 void cx_basic_mempool_destroy(CxMempool *p) {
universe@571 167 struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p;
universe@571 168 cx_basic_mempool_memory *mem;
universe@571 169 cx_for_n(i, pool->ndata) {
universe@571 170 mem = (cx_basic_mempool_memory *) pool->data[i];
universe@571 171 if (mem) {
universe@571 172 if (mem->destructor) {
universe@571 173 mem->destructor(&(mem->c));
universe@571 174 }
universe@571 175 cxFree(pool->allocator, mem);
universe@571 176 }
universe@571 177 }
universe@571 178 free(pool->data);
universe@571 179 free((void *) p->allocator);
universe@571 180 free(pool);
universe@571 181 }
universe@571 182
universe@571 183 void cx_basic_mempool_set_destr(
universe@571 184 __attribute__((__unused__)) CxMempool *pool,
universe@571 185 void *ptr,
universe@571 186 cx_destructor_func func
universe@571 187 ) {
universe@571 188 *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
universe@571 189 }
universe@571 190
universe@571 191 static cx_allocator_class cx_basic_mempool_allocator_class = {
universe@571 192 cx_malloc_basic_mempool,
universe@571 193 cx_realloc_basic_mempool,
universe@571 194 cx_calloc_basic_mempool,
universe@571 195 cx_free_basic_mempool
universe@571 196 };
universe@571 197
universe@571 198 static cx_mempool_class cx_basic_mempool_class = {
universe@571 199 cx_basic_mempool_destroy,
universe@571 200 cx_basic_mempool_set_destr,
universe@571 201 };
universe@571 202
universe@571 203 CxMempool *cxBasicMempoolCreate(
universe@571 204 size_t capacity,
universe@571 205 CxAllocator *allocator
universe@571 206 ) {
universe@571 207 size_t poolsize;
universe@571 208 if (cx_szmul(capacity, sizeof(void *), &poolsize)) {
universe@571 209 return NULL;
universe@571 210 }
universe@571 211
universe@571 212 struct cx_basic_mempool_s *pool =
universe@571 213 malloc(sizeof(struct cx_basic_mempool_s));
universe@571 214 if (pool == NULL) {
universe@571 215 return NULL;
universe@571 216 }
universe@571 217
universe@571 218
universe@571 219 CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
universe@571 220 if (!provided_allocator) {
universe@571 221 free(pool);
universe@571 222 return NULL;
universe@571 223 }
universe@571 224 provided_allocator->cl = &cx_basic_mempool_allocator_class;
universe@571 225 provided_allocator->data = pool;
universe@571 226
universe@571 227 pool->base.cl = &cx_basic_mempool_class;
universe@571 228 pool->base.allocator = provided_allocator;
universe@571 229
universe@571 230 pool->data = malloc(poolsize);
universe@571 231 if (pool->data == NULL) {
universe@571 232 free(provided_allocator);
universe@571 233 free(pool);
universe@571 234 return NULL;
universe@571 235 }
universe@571 236
universe@571 237 pool->ndata = 0;
universe@571 238 pool->size = capacity;
universe@571 239 pool->allocator = allocator;
universe@571 240
universe@571 241 return (CxMempool *) pool;
universe@571 242 }

mercurial