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

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

mercurial