Wed, 28 Jun 2023 20:07:52 +0200
improve mempool implementation
docs/src/features.md | file | annotate | diff | comparison | revisions | |
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 | |
src/mempool.c | file | annotate | diff | comparison | revisions | |
tests/CMakeLists.txt | file | annotate | diff | comparison | revisions | |
tests/test_basic_mempool.cpp | file | annotate | diff | comparison | revisions | |
tests/test_mempool.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/docs/src/features.md Wed Jun 28 19:18:01 2023 +0200 1.2 +++ b/docs/src/features.md Wed Jun 28 20:07:52 2023 +0200 1.3 @@ -30,7 +30,7 @@ 1.4 struct my_allocator_state { 1.5 size_t total; 1.6 size_t avail; 1.7 - char[] mem; 1.8 + char mem[]; 1.9 }; 1.10 1.11 static cx_allocator_class my_allocator_class = { 1.12 @@ -91,10 +91,6 @@ 1.13 1.14 *Header file:* [mempool.h](api/mempool_8h.html) 1.15 1.16 -### Basic Memory Pool 1.17 - 1.18 -*Header file:* [basic_mempool.h](api/basic__mempool_8h.html) 1.19 - 1.20 ## Iterator 1.21 1.22 *Header file:* [iterator.h](api/iterator_8h.html)
2.1 --- a/src/CMakeLists.txt Wed Jun 28 19:18:01 2023 +0200 2.2 +++ b/src/CMakeLists.txt Wed Jun 28 20:07:52 2023 +0200 2.3 @@ -9,7 +9,7 @@ 2.4 map.c 2.5 hash_key.c 2.6 hash_map.c 2.7 - basic_mempool.c 2.8 + mempool.c 2.9 printf.c 2.10 compare.c 2.11 ) 2.12 @@ -28,7 +28,6 @@ 2.13 cx/hash_key.h 2.14 cx/hash_map.h 2.15 cx/mempool.h 2.16 - cx/basic_mempool.h 2.17 cx/printf.h 2.18 cx/compare.h 2.19 )
3.1 --- a/src/basic_mempool.c Wed Jun 28 19:18:01 2023 +0200 3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 3.3 @@ -1,235 +0,0 @@ 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 -#include "cx/basic_mempool.h" 3.33 -#include "cx/utils.h" 3.34 -#include <string.h> 3.35 - 3.36 -#define of_chk_(n) if (SIZE_MAX - sizeof(cx_destructor_func) < (n)) return NULL 3.37 - 3.38 -/** Internal structure for denoting pooled memory. */ 3.39 -typedef struct { 3.40 - /** The destructor. */ 3.41 - cx_destructor_func destructor; 3.42 - /** 3.43 - * Access to the first byte of the polled memory. 3.44 - */ 3.45 - char c; 3.46 -} cx_basic_mempool_memory; 3.47 - 3.48 -static int cx_basic_mempool_chcap( 3.49 - struct cx_basic_mempool_s *pool, 3.50 - size_t newcap 3.51 -) { 3.52 - if (newcap < pool->ndata) { 3.53 - return 1; 3.54 - } 3.55 - 3.56 - size_t newcapsz; 3.57 - if (cx_szmul(newcap, sizeof(void *), &newcapsz)) { 3.58 - return 1; 3.59 - } 3.60 - 3.61 - void **data = realloc(pool->data, newcapsz); 3.62 - if (data) { 3.63 - pool->data = data; 3.64 - pool->size = newcap; 3.65 - return 0; 3.66 - } else { 3.67 - return 1; 3.68 - } 3.69 -} 3.70 - 3.71 -void *cx_malloc_basic_mempool( 3.72 - void *data, 3.73 - size_t n 3.74 -) { 3.75 - of_chk_(n); 3.76 - struct cx_basic_mempool_s *pool = data; 3.77 - 3.78 - if (pool->ndata >= pool->size) { 3.79 - size_t newcap = pool->size * 2; 3.80 - if (newcap < pool->size || cx_basic_mempool_chcap(pool, newcap)) { 3.81 - return NULL; 3.82 - } 3.83 - } 3.84 - 3.85 - cx_basic_mempool_memory *mem = malloc(sizeof(cx_destructor_func) + n); 3.86 - if (mem == NULL) { 3.87 - return NULL; 3.88 - } 3.89 - 3.90 - mem->destructor = NULL; 3.91 - pool->data[pool->ndata] = mem; 3.92 - pool->ndata++; 3.93 - 3.94 - return &(mem->c); 3.95 -} 3.96 - 3.97 -void *cx_calloc_basic_mempool( 3.98 - void *data, 3.99 - size_t nelem, 3.100 - size_t elsize 3.101 -) { 3.102 - size_t msz; 3.103 - if (cx_szmul(nelem, elsize, &msz)) { 3.104 - return NULL; 3.105 - } 3.106 - void *ptr = cx_malloc_basic_mempool(data, msz); 3.107 - if (ptr == NULL) { 3.108 - return NULL; 3.109 - } 3.110 - memset(ptr, 0, nelem * elsize); 3.111 - return ptr; 3.112 -} 3.113 - 3.114 -void *cx_realloc_basic_mempool( 3.115 - void *data, 3.116 - void *ptr, 3.117 - size_t n 3.118 -) { 3.119 - of_chk_(n); 3.120 - struct cx_basic_mempool_s *pool = data; 3.121 - 3.122 - char *mem = ((char *) ptr) - sizeof(cx_destructor_func); 3.123 - char *newm = (char *) realloc(mem, n + sizeof(cx_destructor_func)); 3.124 - if (newm == NULL) { 3.125 - return NULL; 3.126 - } 3.127 - if (mem != newm) { 3.128 - cx_for_n(i, pool->ndata) { 3.129 - if (pool->data[i] == mem) { 3.130 - pool->data[i] = newm; 3.131 - return newm + sizeof(cx_destructor_func); 3.132 - } 3.133 - } 3.134 - abort(); 3.135 - } else { 3.136 - return newm + sizeof(cx_destructor_func); 3.137 - } 3.138 -} 3.139 - 3.140 -void cx_free_basic_mempool( 3.141 - void *data, 3.142 - void *ptr 3.143 -) { 3.144 - struct cx_basic_mempool_s *pool = data; 3.145 - 3.146 - cx_basic_mempool_memory *mem = (cx_basic_mempool_memory *) 3.147 - ((char *) ptr - sizeof(cx_destructor_func)); 3.148 - cx_for_n(i, pool->ndata) { 3.149 - if (mem == pool->data[i]) { 3.150 - if (mem->destructor != NULL) { 3.151 - mem->destructor(&(mem->c)); 3.152 - } 3.153 - free(mem); 3.154 - size_t last_index = pool->ndata - 1; 3.155 - if (i != last_index) { 3.156 - pool->data[i] = pool->data[last_index]; 3.157 - pool->data[last_index] = NULL; 3.158 - } 3.159 - pool->ndata--; 3.160 - return; 3.161 - } 3.162 - } 3.163 - abort(); 3.164 -} 3.165 - 3.166 -void cx_basic_mempool_destroy(CxMempool *p) { 3.167 - struct cx_basic_mempool_s *pool = (struct cx_basic_mempool_s *) p; 3.168 - cx_basic_mempool_memory *mem; 3.169 - cx_for_n(i, pool->ndata) { 3.170 - mem = (cx_basic_mempool_memory *) pool->data[i]; 3.171 - if (mem) { 3.172 - if (mem->destructor) { 3.173 - mem->destructor(&(mem->c)); 3.174 - } 3.175 - free(mem); 3.176 - } 3.177 - } 3.178 - free(pool->data); 3.179 - free((void *) p->allocator); 3.180 - free(pool); 3.181 -} 3.182 - 3.183 -void cx_basic_mempool_set_destr( 3.184 - __attribute__((__unused__)) CxMempool *pool, 3.185 - void *ptr, 3.186 - cx_destructor_func func 3.187 -) { 3.188 - *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; 3.189 -} 3.190 - 3.191 -static cx_allocator_class cx_basic_mempool_allocator_class = { 3.192 - cx_malloc_basic_mempool, 3.193 - cx_realloc_basic_mempool, 3.194 - cx_calloc_basic_mempool, 3.195 - cx_free_basic_mempool 3.196 -}; 3.197 - 3.198 -static cx_mempool_class cx_basic_mempool_class = { 3.199 - cx_basic_mempool_destroy, 3.200 - cx_basic_mempool_set_destr, 3.201 -}; 3.202 - 3.203 -CxMempool *cxBasicMempoolCreate(size_t capacity) { 3.204 - size_t poolsize; 3.205 - if (cx_szmul(capacity, sizeof(void *), &poolsize)) { 3.206 - return NULL; 3.207 - } 3.208 - 3.209 - struct cx_basic_mempool_s *pool = 3.210 - malloc(sizeof(struct cx_basic_mempool_s)); 3.211 - if (pool == NULL) { 3.212 - return NULL; 3.213 - } 3.214 - 3.215 - 3.216 - CxAllocator *provided_allocator = malloc(sizeof(CxAllocator)); 3.217 - if (!provided_allocator) { 3.218 - free(pool); 3.219 - return NULL; 3.220 - } 3.221 - provided_allocator->cl = &cx_basic_mempool_allocator_class; 3.222 - provided_allocator->data = pool; 3.223 - 3.224 - pool->base.cl = &cx_basic_mempool_class; 3.225 - pool->base.allocator = provided_allocator; 3.226 - 3.227 - pool->data = malloc(poolsize); 3.228 - if (pool->data == NULL) { 3.229 - free(provided_allocator); 3.230 - free(pool); 3.231 - return NULL; 3.232 - } 3.233 - 3.234 - pool->ndata = 0; 3.235 - pool->size = capacity; 3.236 - 3.237 - return (CxMempool *) pool; 3.238 -}
4.1 --- a/src/cx/basic_mempool.h Wed Jun 28 19:18:01 2023 +0200 4.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 4.3 @@ -1,76 +0,0 @@ 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 basic_mempool.h 4.33 - * \brief Implementation of a basic memory pool. 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_BASIC_MEMPOOL_H 4.41 -#define UCX_BASIC_MEMPOOL_H 4.42 - 4.43 -#include "mempool.h" 4.44 - 4.45 -#ifdef __cplusplus 4.46 -extern "C" { 4.47 -#endif 4.48 - 4.49 -/** 4.50 - * Basic array-based memory pool. 4.51 - */ 4.52 -struct cx_basic_mempool_s { 4.53 - /** Inherit base structure members. */ 4.54 - CxMempool base; 4.55 - 4.56 - /** List of pointers to pooled memory. */ 4.57 - void **data; 4.58 - 4.59 - /** Number of pooled memory items. */ 4.60 - size_t ndata; 4.61 - 4.62 - /** Memory pool size. */ 4.63 - size_t size; 4.64 -}; 4.65 - 4.66 -/** 4.67 - * Creates a basic array-based memory pool. 4.68 - * 4.69 - * @param capacity the initial capacity of the pool 4.70 - * @return the created memory pool or \c NULL if allocation failed 4.71 - */ 4.72 -__attribute__((__warn_unused_result__)) 4.73 -CxMempool *cxBasicMempoolCreate(size_t capacity); 4.74 - 4.75 -#ifdef __cplusplus 4.76 -} // extern "C" 4.77 -#endif 4.78 - 4.79 -#endif // UCX_BASIC_MEMPOOL_H
5.1 --- a/src/cx/mempool.h Wed Jun 28 19:18:01 2023 +0200 5.2 +++ b/src/cx/mempool.h Wed Jun 28 20:07:52 2023 +0200 5.3 @@ -44,24 +44,31 @@ 5.4 extern "C" { 5.5 #endif 5.6 5.7 -/** 5.8 - * Memory pool class type. 5.9 - */ 5.10 -typedef struct cx_mempool_class_s cx_mempool_class; 5.11 +/** Internal structure for pooled memory. */ 5.12 +struct cx_mempool_memory_s; 5.13 5.14 /** 5.15 * The basic structure of a memory pool. 5.16 * Should be the first member of an actual memory pool implementation. 5.17 */ 5.18 struct cx_mempool_s { 5.19 + /** The provided allocator. */ 5.20 + CxAllocator const *allocator; 5.21 + 5.22 /** 5.23 - * The pool class definition. 5.24 + * A destructor that shall be automatically registered for newly allocated memory. 5.25 + * This destructor MUST NOT free the memory. 5.26 */ 5.27 - cx_mempool_class *cl; 5.28 - /** 5.29 - * The provided allocator. 5.30 - */ 5.31 - CxAllocator const *allocator; 5.32 + cx_destructor_func auto_destr; 5.33 + 5.34 + /** Array of pooled memory. */ 5.35 + struct cx_mempool_memory_s **data; 5.36 + 5.37 + /** Number of pooled memory items. */ 5.38 + size_t size; 5.39 + 5.40 + /** Memory pool capacity. */ 5.41 + size_t capacity; 5.42 }; 5.43 5.44 /** 5.45 @@ -70,22 +77,27 @@ 5.46 typedef struct cx_mempool_s CxMempool; 5.47 5.48 /** 5.49 - * The class definition for a memory pool. 5.50 + * Creates an array-based memory pool with a shared destructor function. 5.51 + * 5.52 + * This destructor MUST NOT free the memory. 5.53 + * 5.54 + * @param capacity the initial capacity of the pool 5.55 + * @param destr the destructor function to use for allocated memory 5.56 + * @return the created memory pool or \c NULL if allocation failed 5.57 */ 5.58 -struct cx_mempool_class_s { 5.59 - /** Member function for destroying the pool. */ 5.60 - __attribute__((__nonnull__)) 5.61 - void (*destroy)(CxMempool *pool); 5.62 +__attribute__((__warn_unused_result__)) 5.63 +CxMempool *cxMempoolCreate(size_t capacity, cx_destructor_func destr); 5.64 5.65 - /** Member function for setting a destructor. */ 5.66 - __attribute__((__nonnull__)) 5.67 - void (*set_destructor)( 5.68 - CxMempool *pool, 5.69 - void *memory, 5.70 - cx_destructor_func fnc 5.71 - ); 5.72 -}; 5.73 - 5.74 +/** 5.75 + * Creates a basic array-based memory pool. 5.76 + * 5.77 + * @param capacity the initial capacity of the pool 5.78 + * @return the created memory pool or \c NULL if allocation failed 5.79 + */ 5.80 +__attribute__((__warn_unused_result__)) 5.81 +static inline CxMempool *cxBasicMempoolCreate(size_t capacity) { 5.82 + return cxMempoolCreate(capacity, NULL); 5.83 +} 5.84 5.85 /** 5.86 * Destroys a memory pool including their contents. 5.87 @@ -93,27 +105,42 @@ 5.88 * @param pool the memory pool to destroy 5.89 */ 5.90 __attribute__((__nonnull__)) 5.91 -static inline void cxMempoolDestroy(CxMempool *pool) { 5.92 - pool->cl->destroy(pool); 5.93 -} 5.94 +void cxMempoolDestroy(CxMempool *pool); 5.95 5.96 /** 5.97 - * Sets a destructor function for an allocated memory object. 5.98 + * Sets the destructor function for a specific allocated memory object. 5.99 * 5.100 - * If the memory is not managed by the pool, the behavior is undefined. 5.101 + * If the memory is not managed by a UCX memory pool, the behavior is undefined. 5.102 + * The destructor MUST NOT free the memory. 5.103 * 5.104 - * @param pool the pool 5.105 - * @param memory the objected allocated in the pool 5.106 + * @param memory the object allocated in the pool 5.107 * @param fnc the destructor function 5.108 */ 5.109 __attribute__((__nonnull__)) 5.110 -static inline void cxMempoolSetDestructor( 5.111 +void cxMempoolSetDestructor( 5.112 + void *memory, 5.113 + cx_destructor_func fnc 5.114 +); 5.115 + 5.116 +/** 5.117 + * Registers foreign memory with this pool. 5.118 + * 5.119 + * The destructor, in contrast to memory allocated by the pool, MUST free the memory. 5.120 + * 5.121 + * A small portion of memory will be allocated to register the information in the pool. 5.122 + * If that allocation fails, this function will return non-zero. 5.123 + * 5.124 + * @param pool the pool 5.125 + * @param memory the object allocated in the pool 5.126 + * @param destr the destructor function 5.127 + * @return zero on success, non-zero on failure 5.128 + */ 5.129 +__attribute__((__nonnull__)) 5.130 +int cxMempoolRegister( 5.131 CxMempool *pool, 5.132 void *memory, 5.133 - cx_destructor_func fnc 5.134 -) { 5.135 - pool->cl->set_destructor(pool, memory, fnc); 5.136 -} 5.137 + cx_destructor_func destr 5.138 +); 5.139 5.140 #ifdef __cplusplus 5.141 } // extern "C"
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/mempool.c Wed Jun 28 20:07:52 2023 +0200 6.3 @@ -0,0 +1,232 @@ 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/mempool.h" 6.33 +#include "cx/utils.h" 6.34 +#include <string.h> 6.35 + 6.36 +struct cx_mempool_memory_s { 6.37 + /** The destructor. */ 6.38 + cx_destructor_func destructor; 6.39 + /** The actual memory. */ 6.40 + char c[]; 6.41 +}; 6.42 + 6.43 +static void *cx_mempool_malloc( 6.44 + void *p, 6.45 + size_t n 6.46 +) { 6.47 + struct cx_mempool_s *pool = p; 6.48 + 6.49 + if (pool->size >= pool->capacity) { 6.50 + size_t newcap = pool->capacity - (pool->capacity % 16) + 16; 6.51 + struct cx_mempool_memory_s **newdata = realloc(pool->data, newcap*sizeof(struct cx_mempool_memory_s*)); 6.52 + if (newdata == NULL) { 6.53 + return NULL; 6.54 + } 6.55 + pool->data = newdata; 6.56 + pool->capacity = newcap; 6.57 + } 6.58 + 6.59 + struct cx_mempool_memory_s *mem = malloc(sizeof(cx_destructor_func) + n); 6.60 + if (mem == NULL) { 6.61 + return NULL; 6.62 + } 6.63 + 6.64 + mem->destructor = pool->auto_destr; 6.65 + pool->data[pool->size] = mem; 6.66 + pool->size++; 6.67 + 6.68 + return mem->c; 6.69 +} 6.70 + 6.71 +static void *cx_mempool_calloc( 6.72 + void *p, 6.73 + size_t nelem, 6.74 + size_t elsize 6.75 +) { 6.76 + size_t msz; 6.77 + if (cx_szmul(nelem, elsize, &msz)) { 6.78 + return NULL; 6.79 + } 6.80 + void *ptr = cx_mempool_malloc(p, msz); 6.81 + if (ptr == NULL) { 6.82 + return NULL; 6.83 + } 6.84 + memset(ptr, 0, nelem * elsize); 6.85 + return ptr; 6.86 +} 6.87 + 6.88 +static void *cx_mempool_realloc( 6.89 + void *p, 6.90 + void *ptr, 6.91 + size_t n 6.92 +) { 6.93 + struct cx_mempool_s *pool = p; 6.94 + 6.95 + struct cx_mempool_memory_s *mem, *newm; 6.96 + mem = (struct cx_mempool_memory_s*)(((char *) ptr) - sizeof(cx_destructor_func)); 6.97 + newm = realloc(mem, n + sizeof(cx_destructor_func)); 6.98 + 6.99 + if (newm == NULL) { 6.100 + return NULL; 6.101 + } 6.102 + if (mem != newm) { 6.103 + cx_for_n(i, pool->size) { 6.104 + if (pool->data[i] == mem) { 6.105 + pool->data[i] = newm; 6.106 + return ((char*)newm) + sizeof(cx_destructor_func); 6.107 + } 6.108 + } 6.109 + abort(); 6.110 + } else { 6.111 + return ptr; 6.112 + } 6.113 +} 6.114 + 6.115 +static void cx_mempool_free( 6.116 + void *p, 6.117 + void *ptr 6.118 +) { 6.119 + struct cx_mempool_s *pool = p; 6.120 + 6.121 + struct cx_mempool_memory_s *mem = (struct cx_mempool_memory_s *) 6.122 + ((char *) ptr - sizeof(cx_destructor_func)); 6.123 + 6.124 + cx_for_n(i, pool->size) { 6.125 + if (mem == pool->data[i]) { 6.126 + if (mem->destructor) { 6.127 + mem->destructor(mem->c); 6.128 + } 6.129 + free(mem); 6.130 + size_t last_index = pool->size - 1; 6.131 + if (i != last_index) { 6.132 + pool->data[i] = pool->data[last_index]; 6.133 + pool->data[last_index] = NULL; 6.134 + } 6.135 + pool->size--; 6.136 + return; 6.137 + } 6.138 + } 6.139 + abort(); 6.140 +} 6.141 + 6.142 +void cxMempoolDestroy(CxMempool *pool) { 6.143 + struct cx_mempool_memory_s *mem; 6.144 + cx_for_n(i, pool->size) { 6.145 + mem = pool->data[i]; 6.146 + if (mem->destructor) { 6.147 + mem->destructor(mem->c); 6.148 + } 6.149 + free(mem); 6.150 + } 6.151 + free(pool->data); 6.152 + free((void*) pool->allocator); 6.153 + free(pool); 6.154 +} 6.155 + 6.156 +void cxMempoolSetDestructor( 6.157 + void *ptr, 6.158 + cx_destructor_func func 6.159 +) { 6.160 + *(cx_destructor_func *) ((char *) ptr - sizeof(cx_destructor_func)) = func; 6.161 +} 6.162 + 6.163 +struct cx_mempool_foreign_mem_s { 6.164 + cx_destructor_func destr; 6.165 + void* mem; 6.166 +}; 6.167 + 6.168 +static void cx_mempool_destr_foreign_mem(void* ptr) { 6.169 + struct cx_mempool_foreign_mem_s *fm = ptr; 6.170 + fm->destr(fm->mem); 6.171 +} 6.172 + 6.173 +int cxMempoolRegister( 6.174 + CxMempool *pool, 6.175 + void *memory, 6.176 + cx_destructor_func destr 6.177 +) { 6.178 + struct cx_mempool_foreign_mem_s *fm = cx_mempool_malloc( 6.179 + pool, 6.180 + sizeof(struct cx_mempool_foreign_mem_s) 6.181 + ); 6.182 + if (fm == NULL) return 1; 6.183 + 6.184 + fm->mem = memory; 6.185 + fm->destr = destr; 6.186 + *(cx_destructor_func *) ((char *) fm - sizeof(cx_destructor_func)) = cx_mempool_destr_foreign_mem; 6.187 + 6.188 + return 0; 6.189 +} 6.190 + 6.191 +static cx_allocator_class cx_mempool_allocator_class = { 6.192 + cx_mempool_malloc, 6.193 + cx_mempool_realloc, 6.194 + cx_mempool_calloc, 6.195 + cx_mempool_free 6.196 +}; 6.197 + 6.198 +CxMempool *cxMempoolCreate( 6.199 + size_t capacity, 6.200 + cx_destructor_func destr 6.201 +) { 6.202 + size_t poolsize; 6.203 + if (cx_szmul(capacity, sizeof(struct cx_mempool_memory_s*), &poolsize)) { 6.204 + return NULL; 6.205 + } 6.206 + 6.207 + struct cx_mempool_s *pool = 6.208 + malloc(sizeof(struct cx_mempool_s)); 6.209 + if (pool == NULL) { 6.210 + return NULL; 6.211 + } 6.212 + 6.213 + CxAllocator *provided_allocator = malloc(sizeof(CxAllocator)); 6.214 + if (provided_allocator == NULL) { 6.215 + free(pool); 6.216 + return NULL; 6.217 + } 6.218 + provided_allocator->cl = &cx_mempool_allocator_class; 6.219 + provided_allocator->data = pool; 6.220 + 6.221 + pool->allocator = provided_allocator; 6.222 + 6.223 + pool->data = malloc(poolsize); 6.224 + if (pool->data == NULL) { 6.225 + free(provided_allocator); 6.226 + free(pool); 6.227 + return NULL; 6.228 + } 6.229 + 6.230 + pool->size = 0; 6.231 + pool->capacity = capacity; 6.232 + pool->auto_destr = destr; 6.233 + 6.234 + return (CxMempool *) pool; 6.235 +}
7.1 --- a/tests/CMakeLists.txt Wed Jun 28 19:18:01 2023 +0200 7.2 +++ b/tests/CMakeLists.txt Wed Jun 28 20:07:52 2023 +0200 7.3 @@ -26,7 +26,7 @@ 7.4 test_hash_key.cpp 7.5 test_map.cpp 7.6 test_map_generics.c 7.7 - test_basic_mempool.cpp 7.8 + test_mempool.cpp 7.9 test_printf.cpp 7.10 selftest.cpp 7.11 util_allocator.cpp
8.1 --- a/tests/test_basic_mempool.cpp Wed Jun 28 19:18:01 2023 +0200 8.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 8.3 @@ -1,154 +0,0 @@ 8.4 -/* 8.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 8.6 - * 8.7 - * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 8.8 - * 8.9 - * Redistribution and use in source and binary forms, with or without 8.10 - * modification, are permitted provided that the following conditions are met: 8.11 - * 8.12 - * 1. Redistributions of source code must retain the above copyright 8.13 - * notice, this list of conditions and the following disclaimer. 8.14 - * 8.15 - * 2. Redistributions in binary form must reproduce the above copyright 8.16 - * notice, this list of conditions and the following disclaimer in the 8.17 - * documentation and/or other materials provided with the distribution. 8.18 - * 8.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 8.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 8.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 8.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 8.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 8.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 8.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 8.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 8.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 8.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 8.29 - * POSSIBILITY OF SUCH DAMAGE. 8.30 - */ 8.31 - 8.32 -#include "cx/basic_mempool.h" 8.33 -#include "util_allocator.h" 8.34 -#include <gtest/gtest.h> 8.35 - 8.36 -class CxBasicMempool : public ::testing::Test { 8.37 -protected: 8.38 - CxMempool *pool = nullptr; 8.39 - 8.40 - void TearDown() override { 8.41 - if (pool != nullptr) { 8.42 - cxMempoolDestroy(pool); 8.43 - } 8.44 - } 8.45 -}; 8.46 - 8.47 -TEST_F(CxBasicMempool, Create) { 8.48 - pool = cxBasicMempoolCreate(16); 8.49 - ASSERT_NE(pool->allocator, nullptr); 8.50 - ASSERT_NE(pool->cl, nullptr); 8.51 - EXPECT_NE(pool->cl->destroy, nullptr); 8.52 - ASSERT_NE(pool->allocator->cl, nullptr); 8.53 - EXPECT_EQ(pool->allocator->data, pool); 8.54 - EXPECT_NE(pool->allocator->cl->malloc, nullptr); 8.55 - EXPECT_NE(pool->allocator->cl->calloc, nullptr); 8.56 - EXPECT_NE(pool->allocator->cl->realloc, nullptr); 8.57 - EXPECT_NE(pool->allocator->cl->free, nullptr); 8.58 - 8.59 - auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool); 8.60 - EXPECT_EQ(basic_pool->size, 16); 8.61 - EXPECT_EQ(basic_pool->ndata, 0); 8.62 - EXPECT_NE(basic_pool->data, nullptr); 8.63 -} 8.64 - 8.65 -TEST_F(CxBasicMempool, malloc) { 8.66 - pool = cxBasicMempoolCreate(4); 8.67 - auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool); 8.68 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.69 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.70 - EXPECT_EQ(basic_pool->ndata, 2); 8.71 - EXPECT_EQ(basic_pool->size, 4); 8.72 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.73 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.74 - EXPECT_EQ(basic_pool->ndata, 4); 8.75 - EXPECT_EQ(basic_pool->size, 4); 8.76 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.77 - EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 8.78 - EXPECT_EQ(basic_pool->ndata, 6); 8.79 - EXPECT_GE(basic_pool->size, 6); 8.80 -} 8.81 - 8.82 -TEST_F(CxBasicMempool, calloc) { 8.83 - pool = cxBasicMempoolCreate(4); 8.84 - 8.85 - auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int)); 8.86 - ASSERT_NE(test, nullptr); 8.87 - EXPECT_EQ(test[0], 0); 8.88 - EXPECT_EQ(test[1], 0); 8.89 -} 8.90 - 8.91 -static unsigned test_destructor_called = 0; 8.92 - 8.93 -static void test_destructor([[maybe_unused]] void *mem) { 8.94 - test_destructor_called++; 8.95 -} 8.96 - 8.97 -TEST_F(CxBasicMempool, destructor) { 8.98 - pool = cxBasicMempoolCreate(4); 8.99 - auto data = cxMalloc(pool->allocator, sizeof(int)); 8.100 - *((int *) data) = 13; 8.101 - cxMempoolSetDestructor(pool, data, test_destructor); 8.102 - EXPECT_EQ(*((int *) data), 13); 8.103 - test_destructor_called = 0; 8.104 - cxFree(pool->allocator, data); 8.105 - EXPECT_EQ(test_destructor_called, 1); 8.106 - data = cxMalloc(pool->allocator, sizeof(int)); 8.107 - cxMempoolSetDestructor(pool, data, test_destructor); 8.108 - cxMempoolDestroy(pool); 8.109 - pool = nullptr; 8.110 - EXPECT_EQ(test_destructor_called, 2); 8.111 -} 8.112 - 8.113 -TEST_F(CxBasicMempool, realloc) { 8.114 - pool = cxBasicMempoolCreate(4); 8.115 - auto data = cxMalloc(pool->allocator, sizeof(int)); 8.116 - *((int *) data) = 13; 8.117 - cxMempoolSetDestructor(pool, data, test_destructor); 8.118 - 8.119 - void *rdata = data; 8.120 - unsigned n = 1; 8.121 - while (rdata == data) { 8.122 - n <<= 1; 8.123 - ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere 8.124 - rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t)); 8.125 - } 8.126 - 8.127 - EXPECT_EQ(*((int *) rdata), 13); 8.128 - // test if destructor is still intact 8.129 - test_destructor_called = 0; 8.130 - cxFree(pool->allocator, rdata); 8.131 - EXPECT_EQ(test_destructor_called, 1); 8.132 -} 8.133 - 8.134 - 8.135 -TEST_F(CxBasicMempool, free) { 8.136 - pool = cxBasicMempoolCreate(4); 8.137 - auto basic_pool = reinterpret_cast<cx_basic_mempool_s *>(pool); 8.138 - 8.139 - void *mem1; 8.140 - void *mem2; 8.141 - 8.142 - mem1 = cxMalloc(pool->allocator, 16); 8.143 - cxFree(pool->allocator, mem1); 8.144 - EXPECT_EQ(basic_pool->ndata, 0); 8.145 - 8.146 - cxMalloc(pool->allocator, 16); 8.147 - cxMalloc(pool->allocator, 16); 8.148 - mem1 = cxMalloc(pool->allocator, 16); 8.149 - cxMalloc(pool->allocator, 16); 8.150 - mem2 = cxMalloc(pool->allocator, 16); 8.151 - 8.152 - EXPECT_EQ(basic_pool->ndata, 5); 8.153 - cxFree(pool->allocator, mem1); 8.154 - EXPECT_EQ(basic_pool->ndata, 4); 8.155 - cxFree(pool->allocator, mem2); 8.156 - EXPECT_EQ(basic_pool->ndata, 3); 8.157 -} 8.158 \ No newline at end of file
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/tests/test_mempool.cpp Wed Jun 28 20:07:52 2023 +0200 9.3 @@ -0,0 +1,153 @@ 9.4 +/* 9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 9.6 + * 9.7 + * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. 9.8 + * 9.9 + * Redistribution and use in source and binary forms, with or without 9.10 + * modification, are permitted provided that the following conditions are met: 9.11 + * 9.12 + * 1. Redistributions of source code must retain the above copyright 9.13 + * notice, this list of conditions and the following disclaimer. 9.14 + * 9.15 + * 2. Redistributions in binary form must reproduce the above copyright 9.16 + * notice, this list of conditions and the following disclaimer in the 9.17 + * documentation and/or other materials provided with the distribution. 9.18 + * 9.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 9.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 9.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 9.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 9.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 9.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 9.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 9.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 9.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 9.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 9.29 + * POSSIBILITY OF SUCH DAMAGE. 9.30 + */ 9.31 + 9.32 +#include "cx/mempool.h" 9.33 +#include "util_allocator.h" 9.34 +#include <gtest/gtest.h> 9.35 + 9.36 +TEST(Mempool, Create) { 9.37 + auto pool = cxBasicMempoolCreate(16); 9.38 + ASSERT_EQ(pool->auto_destr, nullptr); 9.39 + ASSERT_NE(pool->allocator, nullptr); 9.40 + ASSERT_NE(pool->allocator->cl, nullptr); 9.41 + EXPECT_EQ(pool->allocator->data, pool); 9.42 + EXPECT_NE(pool->allocator->cl->malloc, nullptr); 9.43 + EXPECT_NE(pool->allocator->cl->calloc, nullptr); 9.44 + EXPECT_NE(pool->allocator->cl->realloc, nullptr); 9.45 + EXPECT_NE(pool->allocator->cl->free, nullptr); 9.46 + EXPECT_EQ(pool->capacity, 16); 9.47 + EXPECT_EQ(pool->size, 0); 9.48 + EXPECT_NE(pool->data, nullptr); 9.49 + cxMempoolDestroy(pool); 9.50 +} 9.51 + 9.52 +TEST(Mempool, malloc) { 9.53 + auto pool = cxBasicMempoolCreate(4); 9.54 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.55 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.56 + EXPECT_EQ(pool->size, 2); 9.57 + EXPECT_EQ(pool->capacity, 4); 9.58 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.59 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.60 + EXPECT_EQ(pool->size, 4); 9.61 + EXPECT_EQ(pool->capacity, 4); 9.62 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.63 + EXPECT_NE(cxMalloc(pool->allocator, sizeof(int)), nullptr); 9.64 + EXPECT_EQ(pool->size, 6); 9.65 + EXPECT_GE(pool->capacity, 6); 9.66 + cxMempoolDestroy(pool); 9.67 +} 9.68 + 9.69 +TEST(Mempool, calloc) { 9.70 + auto pool = cxBasicMempoolCreate(4); 9.71 + 9.72 + auto test = (int *) cxCalloc(pool->allocator, 2, sizeof(int)); 9.73 + ASSERT_NE(test, nullptr); 9.74 + EXPECT_EQ(test[0], 0); 9.75 + EXPECT_EQ(test[1], 0); 9.76 + cxMempoolDestroy(pool); 9.77 +} 9.78 + 9.79 +static unsigned test_destructor_called; 9.80 + 9.81 +static void test_destructor([[maybe_unused]] void *mem) { 9.82 + test_destructor_called++; 9.83 +} 9.84 + 9.85 +TEST(Mempool, realloc) { 9.86 + auto pool = cxMempoolCreate(4, test_destructor); 9.87 + ASSERT_EQ(pool->auto_destr, test_destructor); 9.88 + auto data = cxMalloc(pool->allocator, sizeof(int)); 9.89 + *((int *) data) = 13; 9.90 + 9.91 + void *rdata = data; 9.92 + unsigned n = 1; 9.93 + while (rdata == data) { 9.94 + n <<= 1; 9.95 + ASSERT_LT(n, 65536); // eventually the memory should be moved elsewhere 9.96 + rdata = cxRealloc(pool->allocator, data, n * sizeof(intptr_t)); 9.97 + } 9.98 + 9.99 + EXPECT_EQ(*((int *) rdata), 13); 9.100 + // test if destructor is still intact 9.101 + test_destructor_called = 0; 9.102 + cxFree(pool->allocator, rdata); 9.103 + EXPECT_EQ(test_destructor_called, 1); 9.104 + cxMempoolDestroy(pool); 9.105 +} 9.106 + 9.107 + 9.108 +TEST(Mempool, free) { 9.109 + auto pool = cxBasicMempoolCreate(4); 9.110 + 9.111 + void *mem1; 9.112 + void *mem2; 9.113 + 9.114 + mem1 = cxMalloc(pool->allocator, 16); 9.115 + cxFree(pool->allocator, mem1); 9.116 + EXPECT_EQ(pool->size, 0); 9.117 + 9.118 + cxMalloc(pool->allocator, 16); 9.119 + cxMalloc(pool->allocator, 16); 9.120 + mem1 = cxMalloc(pool->allocator, 16); 9.121 + cxMalloc(pool->allocator, 16); 9.122 + mem2 = cxMalloc(pool->allocator, 16); 9.123 + 9.124 + EXPECT_EQ(pool->size, 5); 9.125 + cxFree(pool->allocator, mem1); 9.126 + EXPECT_EQ(pool->size, 4); 9.127 + cxFree(pool->allocator, mem2); 9.128 + EXPECT_EQ(pool->size, 3); 9.129 + cxMempoolDestroy(pool); 9.130 +} 9.131 + 9.132 +TEST(Mempool, Destroy) { 9.133 + auto pool = cxBasicMempoolCreate(4); 9.134 + auto data = cxMalloc(pool->allocator, sizeof(int)); 9.135 + *((int *) data) = 13; 9.136 + cxMempoolSetDestructor(data, test_destructor); 9.137 + EXPECT_EQ(*((int *) data), 13); 9.138 + test_destructor_called = 0; 9.139 + cxFree(pool->allocator, data); 9.140 + EXPECT_EQ(test_destructor_called, 1); 9.141 + data = cxMalloc(pool->allocator, sizeof(int)); 9.142 + cxMempoolSetDestructor(data, test_destructor); 9.143 + cxMempoolDestroy(pool); 9.144 + EXPECT_EQ(test_destructor_called, 2); 9.145 +} 9.146 + 9.147 +TEST(Mempool, Register) { 9.148 + auto pool = cxBasicMempoolCreate(4); 9.149 + auto data = cxMalloc(pool->allocator, sizeof(int)); 9.150 + test_destructor_called = 0; 9.151 + cxMempoolSetDestructor(data, test_destructor); 9.152 + int donotfree = 0; 9.153 + cxMempoolRegister(pool, &donotfree, test_destructor); 9.154 + cxMempoolDestroy(pool); 9.155 + EXPECT_EQ(test_destructor_called, 2); 9.156 +}