src/basic_mempool.c

Sun, 21 May 2023 16:22:09 +0200

author
Mike Becker <universe@uap-core.de>
date
Sun, 21 May 2023 16:22:09 +0200
changeset 710
2dd409ed056f
parent 650
77021e06b1a8
permissions
-rw-r--r--

fix const-ness of non-mutating iterator creation for maps

     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 <string.h>
    33 #define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL
    35 /** Internal structure for denoting pooled memory. */
    36 typedef struct {
    37     /** The destructor. */
    38     cx_destructor_func destructor;
    39     /**
    40      * Access to the first byte of the polled memory.
    41      */
    42     char c;
    43 } cx_basic_mempool_memory;
    45 static int cx_basic_mempool_chcap(
    46         struct cx_basic_mempool_s *pool,
    47         size_t newcap
    48 ) {
    49     if (newcap < pool->ndata) {
    50         return 1;
    51     }
    53     size_t newcapsz;
    54     if (cx_szmul(newcap, sizeof(void *), &newcapsz)) {
    55         return 1;
    56     }
    58     void **data = realloc(pool->data, newcapsz);
    59     if (data) {
    60         pool->data = data;
    61         pool->size = newcap;
    62         return 0;
    63     } else {
    64         return 1;
    65     }
    66 }
    68 void *cx_malloc_basic_mempool(
    69         void *data,
    70         size_t n
    71 ) {
    72     of_chk_(n);
    73     struct cx_basic_mempool_s *pool = data;
    75     if (pool->ndata >= pool->size) {
    76         size_t newcap = pool->size * 2;
    77         if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) {
    78             return NULL;
    79         }
    80     }
    82     cx_basic_mempool_memory *mem = malloc(sizeof(cx_destructor_func) + n);
    83     if (mem == NULL) {
    84         return NULL;
    85     }
    87     mem->destructor = NULL;
    88     pool->data[pool->ndata] = mem;
    89     pool->ndata++;
    91     return &(mem->c);
    92 }
    94 void *cx_calloc_basic_mempool(
    95         void *data,
    96         size_t nelem,
    97         size_t elsize
    98 ) {
    99     size_t msz;
   100     if (cx_szmul(nelem, elsize, &msz)) {
   101         return NULL;
   102     }
   103     void *ptr = cx_malloc_basic_mempool(data, msz);
   104     if (ptr == NULL) {
   105         return NULL;
   106     }
   107     memset(ptr, 0, nelem * elsize);
   108     return ptr;
   109 }
   111 void *cx_realloc_basic_mempool(
   112         void *data,
   113         void *ptr,
   114         size_t n
   115 ) {
   116     of_chk_(n);
   117     struct cx_basic_mempool_s *pool = data;
   119     char *mem = ((char *) ptr) - sizeof(cx_destructor_func);
   120     char *newm = (char *) realloc(mem, n + sizeof(cx_destructor_func));
   121     if (newm == NULL) {
   122         return NULL;
   123     }
   124     if (mem != newm) {
   125         cx_for_n(i, pool->ndata) {
   126             if (pool->data[i] == mem) {
   127                 pool->data[i] = newm;
   128                 return newm + sizeof(cx_destructor_func);
   129             }
   130         }
   131         abort();
   132     } else {
   133         return newm + sizeof(cx_destructor_func);
   134     }
   135 }
   137 void cx_free_basic_mempool(
   138         void *data,
   139         void *ptr
   140 ) {
   141     struct cx_basic_mempool_s *pool = data;
   143     cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *)
   144             ((char *) ptr - sizeof(cx_destructor_func));
   145     cx_for_n(i, pool->ndata) {
   146         if (mem == pool->data[i]) {
   147             if (mem->destructor != NULL) {
   148                 mem->destructor(&(mem->c));
   149             }
   150             free(mem);
   151             size_t last_index = pool->ndata - 1;
   152             if (i != last_index) {
   153                 pool->data[i] = pool->data[last_index];
   154                 pool->data[last_index] = NULL;
   155             }
   156             pool->ndata--;
   157             return;
   158         }
   159     }
   160     abort();
   161 }
   163 void cx_basic_mempool_destroy(CxMempool *p) {
   164     struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p;
   165     cx_basic_mempool_memory *mem;
   166     cx_for_n(i, pool->ndata) {
   167         mem = (cx_basic_mempool_memory *) pool->data[i];
   168         if (mem) {
   169             if (mem->destructor) {
   170                 mem->destructor(&(mem->c));
   171             }
   172             free(mem);
   173         }
   174     }
   175     free(pool->data);
   176     free((void *) p->allocator);
   177     free(pool);
   178 }
   180 void cx_basic_mempool_set_destr(
   181         __attribute__((__unused__)) CxMempool *pool,
   182         void *ptr,
   183         cx_destructor_func func
   184 ) {
   185     *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
   186 }
   188 static cx_allocator_class cx_basic_mempool_allocator_class = {
   189         cx_malloc_basic_mempool,
   190         cx_realloc_basic_mempool,
   191         cx_calloc_basic_mempool,
   192         cx_free_basic_mempool
   193 };
   195 static cx_mempool_class cx_basic_mempool_class = {
   196         cx_basic_mempool_destroy,
   197         cx_basic_mempool_set_destr,
   198 };
   200 CxMempool *cxBasicMempoolCreate(size_t capacity) {
   201     size_t poolsize;
   202     if (cx_szmul(capacity, sizeof(void *), &poolsize)) {
   203         return NULL;
   204     }
   206     struct cx_basic_mempool_s *pool =
   207             malloc(sizeof(struct cx_basic_mempool_s));
   208     if (pool == NULL) {
   209         return NULL;
   210     }
   213     CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
   214     if (!provided_allocator) {
   215         free(pool);
   216         return NULL;
   217     }
   218     provided_allocator->cl = &cx_basic_mempool_allocator_class;
   219     provided_allocator->data = pool;
   221     pool->base.cl = &cx_basic_mempool_class;
   222     pool->base.allocator = provided_allocator;
   224     pool->data = malloc(poolsize);
   225     if (pool->data == NULL) {
   226         free(provided_allocator);
   227         free(pool);
   228         return NULL;
   229     }
   231     pool->ndata = 0;
   232     pool->size = capacity;
   234     return (CxMempool *) pool;
   235 }

mercurial