Wed, 03 Aug 2022 17:27:55 +0200
#201 - add mempool implementation
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 */