1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/basic_mempool.c Wed Aug 03 17:27:55 2022 +0200 1.3 @@ -0,0 +1,242 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "cx/basic_mempool.h" 1.33 +#include "cx/utils.h" 1.34 +#include <stdint.h> 1.35 +#include <string.h> 1.36 + 1.37 +#define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL 1.38 + 1.39 +/** Internal structure for denoting pooled memory. */ 1.40 +typedef struct { 1.41 + /** The destructor. */ 1.42 + cx_destructor_func destructor; 1.43 + /** 1.44 + * Access to the first byte of the polled memory. 1.45 + */ 1.46 + char c; 1.47 +} cx_basic_mempool_memory; 1.48 + 1.49 +static int cx_basic_mempool_chcap( 1.50 + struct cx_basic_mempool_s *pool, 1.51 + size_t newcap 1.52 +) { 1.53 + if (newcap < pool->ndata) { 1.54 + return 1; 1.55 + } 1.56 + 1.57 + size_t newcapsz; 1.58 + if (cx_szmul(newcap, sizeof(void *), &newcapsz)) { 1.59 + return 1; 1.60 + } 1.61 + 1.62 + void **data = realloc(pool->data, newcapsz); 1.63 + if (data) { 1.64 + pool->data = data; 1.65 + pool->size = newcap; 1.66 + return 0; 1.67 + } else { 1.68 + return 1; 1.69 + } 1.70 +} 1.71 + 1.72 +void *cx_malloc_basic_mempool( 1.73 + void *data, 1.74 + size_t n 1.75 +) { 1.76 + of_chk_(n); 1.77 + struct cx_basic_mempool_s *pool = data; 1.78 + 1.79 + if (pool->ndata >= pool->size) { 1.80 + size_t newcap = pool->size * 2; 1.81 + if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) { 1.82 + return NULL; 1.83 + } 1.84 + } 1.85 + 1.86 + cx_basic_mempool_memory *mem = cxMalloc(pool->allocator, 1.87 + sizeof(cx_destructor_func) + n); 1.88 + if (mem == NULL) { 1.89 + return NULL; 1.90 + } 1.91 + 1.92 + mem->destructor = NULL; 1.93 + pool->data[pool->ndata] = mem; 1.94 + pool->ndata++; 1.95 + 1.96 + return &(mem->c); 1.97 +} 1.98 + 1.99 +void *cx_calloc_basic_mempool( 1.100 + void *data, 1.101 + size_t nelem, 1.102 + size_t elsize 1.103 +) { 1.104 + size_t msz; 1.105 + if (cx_szmul(nelem, elsize, &msz)) { 1.106 + return NULL; 1.107 + } 1.108 + void *ptr = cx_malloc_basic_mempool(data, msz); 1.109 + if (ptr == NULL) { 1.110 + return NULL; 1.111 + } 1.112 + memset(ptr, 0, nelem * elsize); 1.113 + return ptr; 1.114 +} 1.115 + 1.116 +void *cx_realloc_basic_mempool( 1.117 + void *data, 1.118 + void *ptr, 1.119 + size_t n 1.120 +) { 1.121 + of_chk_(n); 1.122 + struct cx_basic_mempool_s *pool = data; 1.123 + 1.124 + char *mem = ((char *) ptr) - sizeof(cx_destructor_func); 1.125 + char *newm = (char *) cxRealloc(pool->allocator, mem, 1.126 + n + sizeof(cx_destructor_func)); 1.127 + if (newm == NULL) { 1.128 + return NULL; 1.129 + } 1.130 + if (mem != newm) { 1.131 + cx_for_n(i, pool->ndata) { 1.132 + if (pool->data[i] == mem) { 1.133 + pool->data[i] = newm; 1.134 + return newm + sizeof(cx_destructor_func); 1.135 + } 1.136 + } 1.137 + abort(); 1.138 + } else { 1.139 + return newm + sizeof(cx_destructor_func); 1.140 + } 1.141 +} 1.142 + 1.143 +void cx_free_basic_mempool( 1.144 + void *data, 1.145 + void *ptr 1.146 +) { 1.147 + struct cx_basic_mempool_s *pool = data; 1.148 + 1.149 + cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *) 1.150 + ((char *) ptr - sizeof(cx_destructor_func)); 1.151 + cx_for_n(i, pool->ndata) { 1.152 + if (mem == pool->data[i]) { 1.153 + if (mem->destructor != NULL) { 1.154 + mem->destructor(&(mem->c)); 1.155 + } 1.156 + cxFree(pool->allocator, mem); 1.157 + size_t last_index = pool->ndata - 1; 1.158 + if (i != last_index) { 1.159 + pool->data[i] = pool->data[last_index]; 1.160 + pool->data[last_index] = NULL; 1.161 + } 1.162 + pool->ndata--; 1.163 + return; 1.164 + } 1.165 + } 1.166 + abort(); 1.167 +} 1.168 + 1.169 +void cx_basic_mempool_destroy(CxMempool *p) { 1.170 + struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p; 1.171 + cx_basic_mempool_memory *mem; 1.172 + cx_for_n(i, pool->ndata) { 1.173 + mem = (cx_basic_mempool_memory *) pool->data[i]; 1.174 + if (mem) { 1.175 + if (mem->destructor) { 1.176 + mem->destructor(&(mem->c)); 1.177 + } 1.178 + cxFree(pool->allocator, mem); 1.179 + } 1.180 + } 1.181 + free(pool->data); 1.182 + free((void *) p->allocator); 1.183 + free(pool); 1.184 +} 1.185 + 1.186 +void cx_basic_mempool_set_destr( 1.187 + __attribute__((__unused__)) CxMempool *pool, 1.188 + void *ptr, 1.189 + cx_destructor_func func 1.190 +) { 1.191 + *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; 1.192 +} 1.193 + 1.194 +static cx_allocator_class cx_basic_mempool_allocator_class = { 1.195 + cx_malloc_basic_mempool, 1.196 + cx_realloc_basic_mempool, 1.197 + cx_calloc_basic_mempool, 1.198 + cx_free_basic_mempool 1.199 +}; 1.200 + 1.201 +static cx_mempool_class cx_basic_mempool_class = { 1.202 + cx_basic_mempool_destroy, 1.203 + cx_basic_mempool_set_destr, 1.204 +}; 1.205 + 1.206 +CxMempool *cxBasicMempoolCreate( 1.207 + size_t capacity, 1.208 + CxAllocator *allocator 1.209 +) { 1.210 + size_t poolsize; 1.211 + if (cx_szmul(capacity, sizeof(void *), &poolsize)) { 1.212 + return NULL; 1.213 + } 1.214 + 1.215 + struct cx_basic_mempool_s *pool = 1.216 + malloc(sizeof(struct cx_basic_mempool_s)); 1.217 + if (pool == NULL) { 1.218 + return NULL; 1.219 + } 1.220 + 1.221 + 1.222 + CxAllocator *provided_allocator = malloc(sizeof(CxAllocator)); 1.223 + if (!provided_allocator) { 1.224 + free(pool); 1.225 + return NULL; 1.226 + } 1.227 + provided_allocator->cl = &cx_basic_mempool_allocator_class; 1.228 + provided_allocator->data = pool; 1.229 + 1.230 + pool->base.cl = &cx_basic_mempool_class; 1.231 + pool->base.allocator = provided_allocator; 1.232 + 1.233 + pool->data = malloc(poolsize); 1.234 + if (pool->data == NULL) { 1.235 + free(provided_allocator); 1.236 + free(pool); 1.237 + return NULL; 1.238 + } 1.239 + 1.240 + pool->ndata = 0; 1.241 + pool->size = capacity; 1.242 + pool->allocator = allocator; 1.243 + 1.244 + return (CxMempool *) pool; 1.245 +}