#201 - add mempool implementation

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
parent 570
7edce1b5a798
child 572
f0f99dd06d9f

#201 - add mempool implementation

src/CMakeLists.txt file | annotate | diff | comparison | revisions
src/basic_mempool.c file | annotate | diff | comparison | revisions
src/cx/basic_mempool.h file | annotate | diff | comparison | revisions
src/cx/mempool.h file | annotate | diff | comparison | revisions
test/CMakeLists.txt file | annotate | diff | comparison | revisions
test/test_basic_mempool.cpp file | annotate | diff | comparison | revisions
test/util_allocator.cpp file | annotate | diff | comparison | revisions
test/util_allocator.h file | annotate | diff | comparison | revisions
     1.1 --- a/src/CMakeLists.txt	Wed Aug 03 15:44:46 2022 +0200
     1.2 +++ b/src/CMakeLists.txt	Wed Aug 03 17:27:55 2022 +0200
     1.3 @@ -7,6 +7,7 @@
     1.4          buffer.c
     1.5          hash_key.c
     1.6          hash_map.c
     1.7 +        basic_mempool.c
     1.8  )
     1.9  set(headers
    1.10          cx/common.h
    1.11 @@ -20,6 +21,8 @@
    1.12          cx/map.h
    1.13          cx/hash_key.h
    1.14          cx/hash_map.h
    1.15 +        cx/mempool.h
    1.16 +        cx/basic_mempool.h
    1.17          )
    1.18  
    1.19  add_library(ucx SHARED ${sources})
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/src/basic_mempool.c	Wed Aug 03 17:27:55 2022 +0200
     2.3 @@ -0,0 +1,242 @@
     2.4 +/*
     2.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     2.6 + *
     2.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     2.8 + *
     2.9 + * Redistribution and use in source and binary forms, with or without
    2.10 + * modification, are permitted provided that the following conditions are met:
    2.11 + *
    2.12 + *   1. Redistributions of source code must retain the above copyright
    2.13 + *      notice, this list of conditions and the following disclaimer.
    2.14 + *
    2.15 + *   2. Redistributions in binary form must reproduce the above copyright
    2.16 + *      notice, this list of conditions and the following disclaimer in the
    2.17 + *      documentation and/or other materials provided with the distribution.
    2.18 + *
    2.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    2.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    2.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    2.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    2.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    2.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    2.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    2.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    2.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    2.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    2.29 + * POSSIBILITY OF SUCH DAMAGE.
    2.30 + */
    2.31 +
    2.32 +#include "cx/basic_mempool.h"
    2.33 +#include "cx/utils.h"
    2.34 +#include <stdint.h>
    2.35 +#include <string.h>
    2.36 +
    2.37 +#define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL
    2.38 +
    2.39 +/** Internal structure for denoting pooled memory. */
    2.40 +typedef struct {
    2.41 +    /** The destructor. */
    2.42 +    cx_destructor_func destructor;
    2.43 +    /**
    2.44 +     * Access to the first byte of the polled memory.
    2.45 +     */
    2.46 +    char c;
    2.47 +} cx_basic_mempool_memory;
    2.48 +
    2.49 +static int cx_basic_mempool_chcap(
    2.50 +        struct cx_basic_mempool_s *pool,
    2.51 +        size_t newcap
    2.52 +) {
    2.53 +    if (newcap < pool->ndata) {
    2.54 +        return 1;
    2.55 +    }
    2.56 +
    2.57 +    size_t newcapsz;
    2.58 +    if (cx_szmul(newcap, sizeof(void *), &newcapsz)) {
    2.59 +        return 1;
    2.60 +    }
    2.61 +
    2.62 +    void **data = realloc(pool->data, newcapsz);
    2.63 +    if (data) {
    2.64 +        pool->data = data;
    2.65 +        pool->size = newcap;
    2.66 +        return 0;
    2.67 +    } else {
    2.68 +        return 1;
    2.69 +    }
    2.70 +}
    2.71 +
    2.72 +void *cx_malloc_basic_mempool(
    2.73 +        void *data,
    2.74 +        size_t n
    2.75 +) {
    2.76 +    of_chk_(n);
    2.77 +    struct cx_basic_mempool_s *pool = data;
    2.78 +
    2.79 +    if (pool->ndata >= pool->size) {
    2.80 +        size_t newcap = pool->size * 2;
    2.81 +        if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) {
    2.82 +            return NULL;
    2.83 +        }
    2.84 +    }
    2.85 +
    2.86 +    cx_basic_mempool_memory *mem = cxMalloc(pool->allocator,
    2.87 +                                            sizeof(cx_destructor_func) + n);
    2.88 +    if (mem == NULL) {
    2.89 +        return NULL;
    2.90 +    }
    2.91 +
    2.92 +    mem->destructor = NULL;
    2.93 +    pool->data[pool->ndata] = mem;
    2.94 +    pool->ndata++;
    2.95 +
    2.96 +    return &(mem->c);
    2.97 +}
    2.98 +
    2.99 +void *cx_calloc_basic_mempool(
   2.100 +        void *data,
   2.101 +        size_t nelem,
   2.102 +        size_t elsize
   2.103 +) {
   2.104 +    size_t msz;
   2.105 +    if (cx_szmul(nelem, elsize, &msz)) {
   2.106 +        return NULL;
   2.107 +    }
   2.108 +    void *ptr = cx_malloc_basic_mempool(data, msz);
   2.109 +    if (ptr == NULL) {
   2.110 +        return NULL;
   2.111 +    }
   2.112 +    memset(ptr, 0, nelem * elsize);
   2.113 +    return ptr;
   2.114 +}
   2.115 +
   2.116 +void *cx_realloc_basic_mempool(
   2.117 +        void *data,
   2.118 +        void *ptr,
   2.119 +        size_t n
   2.120 +) {
   2.121 +    of_chk_(n);
   2.122 +    struct cx_basic_mempool_s *pool = data;
   2.123 +
   2.124 +    char *mem = ((char *) ptr) - sizeof(cx_destructor_func);
   2.125 +    char *newm = (char *) cxRealloc(pool->allocator, mem,
   2.126 +                                    n + sizeof(cx_destructor_func));
   2.127 +    if (newm == NULL) {
   2.128 +        return NULL;
   2.129 +    }
   2.130 +    if (mem != newm) {
   2.131 +        cx_for_n(i, pool->ndata) {
   2.132 +            if (pool->data[i] == mem) {
   2.133 +                pool->data[i] = newm;
   2.134 +                return newm + sizeof(cx_destructor_func);
   2.135 +            }
   2.136 +        }
   2.137 +        abort();
   2.138 +    } else {
   2.139 +        return newm + sizeof(cx_destructor_func);
   2.140 +    }
   2.141 +}
   2.142 +
   2.143 +void cx_free_basic_mempool(
   2.144 +        void *data,
   2.145 +        void *ptr
   2.146 +) {
   2.147 +    struct cx_basic_mempool_s *pool = data;
   2.148 +
   2.149 +    cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *)
   2.150 +            ((char *) ptr - sizeof(cx_destructor_func));
   2.151 +    cx_for_n(i, pool->ndata) {
   2.152 +        if (mem == pool->data[i]) {
   2.153 +            if (mem->destructor != NULL) {
   2.154 +                mem->destructor(&(mem->c));
   2.155 +            }
   2.156 +            cxFree(pool->allocator, mem);
   2.157 +            size_t last_index = pool->ndata - 1;
   2.158 +            if (i != last_index) {
   2.159 +                pool->data[i] = pool->data[last_index];
   2.160 +                pool->data[last_index] = NULL;
   2.161 +            }
   2.162 +            pool->ndata--;
   2.163 +            return;
   2.164 +        }
   2.165 +    }
   2.166 +    abort();
   2.167 +}
   2.168 +
   2.169 +void cx_basic_mempool_destroy(CxMempool *p) {
   2.170 +    struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p;
   2.171 +    cx_basic_mempool_memory *mem;
   2.172 +    cx_for_n(i, pool->ndata) {
   2.173 +        mem = (cx_basic_mempool_memory *) pool->data[i];
   2.174 +        if (mem) {
   2.175 +            if (mem->destructor) {
   2.176 +                mem->destructor(&(mem->c));
   2.177 +            }
   2.178 +            cxFree(pool->allocator, mem);
   2.179 +        }
   2.180 +    }
   2.181 +    free(pool->data);
   2.182 +    free((void *) p->allocator);
   2.183 +    free(pool);
   2.184 +}
   2.185 +
   2.186 +void cx_basic_mempool_set_destr(
   2.187 +        __attribute__((__unused__)) CxMempool *pool,
   2.188 +        void *ptr,
   2.189 +        cx_destructor_func func
   2.190 +) {
   2.191 +    *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func;
   2.192 +}
   2.193 +
   2.194 +static cx_allocator_class cx_basic_mempool_allocator_class = {
   2.195 +        cx_malloc_basic_mempool,
   2.196 +        cx_realloc_basic_mempool,
   2.197 +        cx_calloc_basic_mempool,
   2.198 +        cx_free_basic_mempool
   2.199 +};
   2.200 +
   2.201 +static cx_mempool_class cx_basic_mempool_class = {
   2.202 +        cx_basic_mempool_destroy,
   2.203 +        cx_basic_mempool_set_destr,
   2.204 +};
   2.205 +
   2.206 +CxMempool *cxBasicMempoolCreate(
   2.207 +        size_t capacity,
   2.208 +        CxAllocator *allocator
   2.209 +) {
   2.210 +    size_t poolsize;
   2.211 +    if (cx_szmul(capacity, sizeof(void *), &poolsize)) {
   2.212 +        return NULL;
   2.213 +    }
   2.214 +
   2.215 +    struct cx_basic_mempool_s *pool =
   2.216 +            malloc(sizeof(struct cx_basic_mempool_s));
   2.217 +    if (pool == NULL) {
   2.218 +        return NULL;
   2.219 +    }
   2.220 +
   2.221 +
   2.222 +    CxAllocator *provided_allocator = malloc(sizeof(CxAllocator));
   2.223 +    if (!provided_allocator) {
   2.224 +        free(pool);
   2.225 +        return NULL;
   2.226 +    }
   2.227 +    provided_allocator->cl = &cx_basic_mempool_allocator_class;
   2.228 +    provided_allocator->data = pool;
   2.229 +
   2.230 +    pool->base.cl = &cx_basic_mempool_class;
   2.231 +    pool->base.allocator = provided_allocator;
   2.232 +
   2.233 +    pool->data = malloc(poolsize);
   2.234 +    if (pool->data == NULL) {
   2.235 +        free(provided_allocator);
   2.236 +        free(pool);
   2.237 +        return NULL;
   2.238 +    }
   2.239 +
   2.240 +    pool->ndata = 0;
   2.241 +    pool->size = capacity;
   2.242 +    pool->allocator = allocator;
   2.243 +
   2.244 +    return (CxMempool *) pool;
   2.245 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/src/cx/basic_mempool.h	Wed Aug 03 17:27:55 2022 +0200
     3.3 @@ -0,0 +1,97 @@
     3.4 +/*
     3.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3.6 + *
     3.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     3.8 + *
     3.9 + * Redistribution and use in source and binary forms, with or without
    3.10 + * modification, are permitted provided that the following conditions are met:
    3.11 + *
    3.12 + *   1. Redistributions of source code must retain the above copyright
    3.13 + *      notice, this list of conditions and the following disclaimer.
    3.14 + *
    3.15 + *   2. Redistributions in binary form must reproduce the above copyright
    3.16 + *      notice, this list of conditions and the following disclaimer in the
    3.17 + *      documentation and/or other materials provided with the distribution.
    3.18 + *
    3.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    3.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    3.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    3.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    3.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    3.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    3.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    3.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    3.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    3.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    3.29 + * POSSIBILITY OF SUCH DAMAGE.
    3.30 + */
    3.31 +/**
    3.32 + * \file basic_mempool.h
    3.33 + * \brief Implementation of a basic memory pool.
    3.34 + * \author Mike Becker
    3.35 + * \author Olaf Wintermann
    3.36 + * \version 3.0
    3.37 + * \copyright 2-Clause BSD License
    3.38 + */
    3.39 +
    3.40 +#ifndef UCX_BASIC_MEMPOOL_H
    3.41 +#define UCX_BASIC_MEMPOOL_H
    3.42 +
    3.43 +#include "mempool.h"
    3.44 +
    3.45 +#ifdef __cplusplus
    3.46 +extern "C" {
    3.47 +#endif
    3.48 +
    3.49 +/**
    3.50 + * Basic array-based memory pool.
    3.51 + */
    3.52 +struct cx_basic_mempool_s {
    3.53 +    /** Inherit base structure members. */
    3.54 +    CxMempool base;
    3.55 +
    3.56 +    /** The underlying allocator. */
    3.57 +    CxAllocator *allocator;
    3.58 +
    3.59 +    /** List of pointers to pooled memory. */
    3.60 +    void **data;
    3.61 +
    3.62 +    /** Number of pooled memory items. */
    3.63 +    size_t ndata;
    3.64 +
    3.65 +    /** Memory pool size. */
    3.66 +    size_t size;
    3.67 +};
    3.68 +
    3.69 +/**
    3.70 + * Creates a basic array-based memory pool.
    3.71 + *
    3.72 + * @param capacity the initial capacity of the pool
    3.73 + * @param allocator the underlying allocator
    3.74 + * @return the created memory pool or \c NULL if allocation failed
    3.75 + */
    3.76 +__attribute__((__warn_unused_result__))
    3.77 +CxMempool *cxBasicMempoolCreate(
    3.78 +        size_t capacity,
    3.79 +        CxAllocator *allocator
    3.80 +);
    3.81 +
    3.82 +
    3.83 +/**
    3.84 + * Creates a basic array-based memory pool.
    3.85 + *
    3.86 + * The pool will use the default standard library allocator.
    3.87 + *
    3.88 + * @param capacity the initial capacity of the pool
    3.89 + * @return the created memory pool or \c NULL if allocation failed
    3.90 + */
    3.91 +__attribute__((__warn_unused_result__))
    3.92 +static inline CxMempool *cxBasicMempoolCreateSimple(size_t capacity) {
    3.93 +    return cxBasicMempoolCreate(capacity, cxDefaultAllocator);
    3.94 +}
    3.95 +
    3.96 +#ifdef __cplusplus
    3.97 +} // extern "C"
    3.98 +#endif
    3.99 +
   3.100 +#endif // UCX_BASIC_MEMPOOL_H
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/cx/mempool.h	Wed Aug 03 17:27:55 2022 +0200
     4.3 @@ -0,0 +1,121 @@
     4.4 +/*
     4.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     4.6 + *
     4.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     4.8 + *
     4.9 + * Redistribution and use in source and binary forms, with or without
    4.10 + * modification, are permitted provided that the following conditions are met:
    4.11 + *
    4.12 + *   1. Redistributions of source code must retain the above copyright
    4.13 + *      notice, this list of conditions and the following disclaimer.
    4.14 + *
    4.15 + *   2. Redistributions in binary form must reproduce the above copyright
    4.16 + *      notice, this list of conditions and the following disclaimer in the
    4.17 + *      documentation and/or other materials provided with the distribution.
    4.18 + *
    4.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    4.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    4.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    4.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    4.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    4.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    4.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    4.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    4.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    4.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    4.29 + * POSSIBILITY OF SUCH DAMAGE.
    4.30 + */
    4.31 +/**
    4.32 + * \file mempool.h
    4.33 + * \brief Interface for memory pool implementations.
    4.34 + * \author Mike Becker
    4.35 + * \author Olaf Wintermann
    4.36 + * \version 3.0
    4.37 + * \copyright 2-Clause BSD License
    4.38 + */
    4.39 +
    4.40 +#ifndef UCX_MEMPOOL_H
    4.41 +#define UCX_MEMPOOL_H
    4.42 +
    4.43 +#include "allocator.h"
    4.44 +
    4.45 +#ifdef __cplusplus
    4.46 +extern "C" {
    4.47 +#endif
    4.48 +
    4.49 +/**
    4.50 + * Memory pool class type.
    4.51 + */
    4.52 +typedef struct cx_mempool_class_s cx_mempool_class;
    4.53 +
    4.54 +/**
    4.55 + * The basic structure of a memory pool.
    4.56 + * Should be the first member of an actual memory pool implementation.
    4.57 + */
    4.58 +struct cx_mempool_s {
    4.59 +    /**
    4.60 +     * The pool class definition.
    4.61 +     */
    4.62 +    cx_mempool_class *cl;
    4.63 +    /**
    4.64 +     * The provided allocator.
    4.65 +     */
    4.66 +    CxAllocator const *allocator;
    4.67 +};
    4.68 +
    4.69 +/**
    4.70 + * Common type for all memory pool implementations.
    4.71 + */
    4.72 +typedef struct cx_mempool_s CxMempool;
    4.73 +
    4.74 +/**
    4.75 + * The class definition for a memory pool.
    4.76 + */
    4.77 +struct cx_mempool_class_s {
    4.78 +    /** Member function for destroying the pool. */
    4.79 +    __attribute__((__nonnull__))
    4.80 +    void (*destroy)(CxMempool *pool);
    4.81 +
    4.82 +    /** Member function for setting a destructor. */
    4.83 +    __attribute__((__nonnull__))
    4.84 +    void (*set_destructor)(
    4.85 +            CxMempool *pool,
    4.86 +            void *memory,
    4.87 +            cx_destructor_func fnc
    4.88 +    );
    4.89 +};
    4.90 +
    4.91 +
    4.92 +/**
    4.93 + * Destroys a memory pool including their contents.
    4.94 + *
    4.95 + * @param pool the memory pool to destroy
    4.96 + */
    4.97 +__attribute__((__nonnull__))
    4.98 +static inline void cxMempoolDestroy(CxMempool *pool) {
    4.99 +    pool->cl->destroy(pool);
   4.100 +}
   4.101 +
   4.102 +/**
   4.103 + * Sets a destructor function for an allocated memory object.
   4.104 + *
   4.105 + * If the memory is not managed by the pool, the behavior is undefined.
   4.106 + *
   4.107 + * @param pool the pool
   4.108 + * @param memory the objected allocated in the pool
   4.109 + * @param fnc the destructor function
   4.110 + */
   4.111 +__attribute__((__nonnull__))
   4.112 +static inline void cxMempoolSetDestructor(
   4.113 +        CxMempool *pool,
   4.114 +        void *memory,
   4.115 +        cx_destructor_func fnc
   4.116 +) {
   4.117 +    pool->cl->set_destructor(pool, memory, fnc);
   4.118 +}
   4.119 +
   4.120 +#ifdef __cplusplus
   4.121 +} // extern "C"
   4.122 +#endif
   4.123 +
   4.124 +#endif // UCX_MEMPOOL_H
     5.1 --- a/test/CMakeLists.txt	Wed Aug 03 15:44:46 2022 +0200
     5.2 +++ b/test/CMakeLists.txt	Wed Aug 03 17:27:55 2022 +0200
     5.3 @@ -19,6 +19,7 @@
     5.4          test_list.cpp
     5.5          test_tree.cpp
     5.6          test_map.cpp
     5.7 +        test_basic_mempool.cpp
     5.8          selftest.cpp
     5.9          util_allocator.cpp
    5.10          )
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/test/test_basic_mempool.cpp	Wed Aug 03 17:27:55 2022 +0200
     6.3 @@ -0,0 +1,162 @@
     6.4 +/*
     6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     6.6 + *
     6.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
     6.8 + *
     6.9 + * Redistribution and use in source and binary forms, with or without
    6.10 + * modification, are permitted provided that the following conditions are met:
    6.11 + *
    6.12 + *   1. Redistributions of source code must retain the above copyright
    6.13 + *      notice, this list of conditions and the following disclaimer.
    6.14 + *
    6.15 + *   2. Redistributions in binary form must reproduce the above copyright
    6.16 + *      notice, this list of conditions and the following disclaimer in the
    6.17 + *      documentation and/or other materials provided with the distribution.
    6.18 + *
    6.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    6.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    6.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    6.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    6.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    6.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    6.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    6.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    6.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    6.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    6.29 + * POSSIBILITY OF SUCH DAMAGE.
    6.30 + */
    6.31 +
    6.32 +#include "cx/basic_mempool.h"
    6.33 +#include "util_allocator.h"
    6.34 +#include <gtest/gtest.h>
    6.35 +
    6.36 +class CxBasicMempool : public ::testing::Test {
    6.37 +protected:
    6.38 +    CxTestingAllocator testingAllocator;
    6.39 +    CxMempool *pool = nullptr;
    6.40 +
    6.41 +    void TearDown() override {
    6.42 +        if (pool != nullptr) {
    6.43 +            cxMempoolDestroy(pool);
    6.44 +        }
    6.45 +        EXPECT_TRUE(testingAllocator.verify());
    6.46 +    }
    6.47 +};
    6.48 +
    6.49 +TEST_F(CxBasicMempool, Create) {
    6.50 +    pool = cxBasicMempoolCreateSimple(16);
    6.51 +    ASSERT_NE(pool->allocator, nullptr);
    6.52 +    ASSERT_NE(pool->cl, nullptr);
    6.53 +    EXPECT_NE(pool->cl->destroy, nullptr);
    6.54 +    ASSERT_NE(pool->allocator->cl, nullptr);
    6.55 +    EXPECT_EQ(pool->allocator->data, pool);
    6.56 +    EXPECT_NE(pool->allocator->cl->malloc, nullptr);
    6.57 +    EXPECT_NE(pool->allocator->cl->calloc, nullptr);
    6.58 +    EXPECT_NE(pool->allocator->cl->realloc, nullptr);
    6.59 +    EXPECT_NE(pool->allocator->cl->free, nullptr);
    6.60 +
    6.61 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
    6.62 +    EXPECT_EQ(basic_pool->allocator, cxDefaultAllocator);
    6.63 +    EXPECT_EQ(basic_pool->size, 16);
    6.64 +    EXPECT_EQ(basic_pool->ndata, 0);
    6.65 +    EXPECT_NE(basic_pool->data, nullptr);
    6.66 +}
    6.67 +
    6.68 +TEST_F(CxBasicMempool, malloc) {
    6.69 +    pool = cxBasicMempoolCreate(4, &testingAllocator);
    6.70 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
    6.71 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.72 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.73 +    EXPECT_EQ(testingAllocator.alloc_total, 2);
    6.74 +    EXPECT_EQ(basic_pool->ndata, 2);
    6.75 +    EXPECT_EQ(basic_pool->size, 4);
    6.76 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.77 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.78 +    EXPECT_EQ(testingAllocator.alloc_total, 4);
    6.79 +    EXPECT_EQ(basic_pool->ndata, 4);
    6.80 +    EXPECT_EQ(basic_pool->size, 4);
    6.81 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.82 +    EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr);
    6.83 +    EXPECT_EQ(testingAllocator.alloc_total, 6);
    6.84 +    EXPECT_EQ(basic_pool->ndata, 6);
    6.85 +    EXPECT_GE(basic_pool->size, 6);
    6.86 +    EXPECT_TRUE(testingAllocator.used());
    6.87 +}
    6.88 +
    6.89 +TEST_F(CxBasicMempool, calloc) {
    6.90 +    pool = cxBasicMempoolCreate(4, &testingAllocator);
    6.91 +
    6.92 +    auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int));
    6.93 +    ASSERT_NE(test, nullptr);
    6.94 +    EXPECT_EQ(test[0], 0);
    6.95 +    EXPECT_EQ(test[1], 0);
    6.96 +    EXPECT_TRUE(testingAllocator.used());
    6.97 +}
    6.98 +
    6.99 +static unsigned test_destructor_called = 0;
   6.100 +
   6.101 +static void test_destructor([[maybe_unused]] void *mem) {
   6.102 +    test_destructor_called++;
   6.103 +}
   6.104 +
   6.105 +TEST_F(CxBasicMempool, destructor) {
   6.106 +    pool = cxBasicMempoolCreate(4, &testingAllocator);
   6.107 +    auto data = cxMalloc(pool->allocator, sizeof(int));
   6.108 +    *((int *) data) = 13;
   6.109 +    cxMempoolSetDestructor(pool, data, test_destructor);
   6.110 +    EXPECT_EQ(*((int *) data), 13);
   6.111 +    test_destructor_called = 0;
   6.112 +    cxFree(pool->allocator, data);
   6.113 +    EXPECT_EQ(test_destructor_called, 1);
   6.114 +    data = cxMalloc(pool->allocator, sizeof(int));
   6.115 +    cxMempoolSetDestructor(pool, data, test_destructor);
   6.116 +    cxMempoolDestroy(pool);
   6.117 +    pool = nullptr;
   6.118 +    EXPECT_EQ(test_destructor_called, 2);
   6.119 +}
   6.120 +
   6.121 +TEST_F(CxBasicMempool, realloc) {
   6.122 +    pool = cxBasicMempoolCreate(4, &testingAllocator);
   6.123 +    auto data = cxMalloc(pool->allocator, sizeof(int));
   6.124 +    *((int *) data) = 13;
   6.125 +    cxMempoolSetDestructor(pool, data, test_destructor);
   6.126 +
   6.127 +    void *rdata = data;
   6.128 +    unsigned n = 1;
   6.129 +    while (rdata == data) {
   6.130 +        n <<= 1;
   6.131 +        ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere
   6.132 +        rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t));
   6.133 +    }
   6.134 +
   6.135 +    EXPECT_EQ(*((int *) rdata), 13);
   6.136 +    // test if destructor is still intact
   6.137 +    test_destructor_called = 0;
   6.138 +    cxFree(pool->allocator, rdata);
   6.139 +    EXPECT_EQ(test_destructor_called, 1);
   6.140 +}
   6.141 +
   6.142 +
   6.143 +TEST_F(CxBasicMempool, free) {
   6.144 +    pool = cxBasicMempoolCreate(4, &testingAllocator);
   6.145 +    auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool);
   6.146 +
   6.147 +    void *mem1;
   6.148 +    void *mem2;
   6.149 +
   6.150 +    mem1 = cxMalloc(pool->allocator, 16);
   6.151 +    cxFree(pool->allocator, mem1);
   6.152 +    EXPECT_EQ(basic_pool->ndata, 0);
   6.153 +
   6.154 +    cxMalloc(pool->allocator, 16);
   6.155 +    cxMalloc(pool->allocator, 16);
   6.156 +    mem1 = cxMalloc(pool->allocator, 16);
   6.157 +    cxMalloc(pool->allocator, 16);
   6.158 +    mem2 = cxMalloc(pool->allocator, 16);
   6.159 +
   6.160 +    EXPECT_EQ(basic_pool->ndata, 5);
   6.161 +    cxFree(pool->allocator, mem1);
   6.162 +    EXPECT_EQ(basic_pool->ndata, 4);
   6.163 +    cxFree(pool->allocator, mem2);
   6.164 +    EXPECT_EQ(basic_pool->ndata, 3);
   6.165 +}
   6.166 \ No newline at end of file
     7.1 --- a/test/util_allocator.cpp	Wed Aug 03 15:44:46 2022 +0200
     7.2 +++ b/test/util_allocator.cpp	Wed Aug 03 17:27:55 2022 +0200
     7.3 @@ -95,6 +95,10 @@
     7.4      data = this;
     7.5  }
     7.6  
     7.7 +bool CxTestingAllocator::used() const {
     7.8 +    return alloc_total > 0;
     7.9 +}
    7.10 +
    7.11  bool CxTestingAllocator::verify() const {
    7.12      return tracked.empty() && alloc_failed == 0 && free_failed == 0 && alloc_total == free_total;
    7.13  }
     8.1 --- a/test/util_allocator.h	Wed Aug 03 15:44:46 2022 +0200
     8.2 +++ b/test/util_allocator.h	Wed Aug 03 17:27:55 2022 +0200
     8.3 @@ -64,11 +64,18 @@
     8.4      CxTestingAllocator();
     8.5  
     8.6      /**
     8.7 +     * Verifies that this allocator has been used.
     8.8 +     *
     8.9 +     * @return true if any allocation was attempted using this allocator
    8.10 +     */
    8.11 +    [[nodiscard]] bool used() const;
    8.12 +
    8.13 +    /**
    8.14       * Verifies that all allocated memory blocks are freed and no free occurred twice.
    8.15       *
    8.16       * @return true iff all tracked allocations / deallocations were valid
    8.17       */
    8.18 -    bool verify() const;
    8.19 +    [[nodiscard]] bool verify() const;
    8.20  };
    8.21  
    8.22  #endif /* UCX_UTIL_ALLOCATOR_H */

mercurial