1 // -*- C++ -*- 2 /** @file */ 3 #pragma once 4 5 6 #include <cstdio> 7 #include <cstddef> 8 #include <vector> 9 #include "common.hpp" 10 11 namespace arm_cmsis_dsp { 12 13 /** \addtogroup MEMORY Memory allocator 14 * \ingroup DSPPP 15 * @{ 16 */ 17 18 /* 19 20 Buffer allocator 21 22 Can be used to build memory allocators foe vector 23 and matrix. 24 25 For instance, it is usedin the Memory pool allocator 26 27 */ 28 29 /** \defgroup MEMBUF Memory buffer allocator 30 * \ingroup MEMORY 31 * Allocators for allocating memory buffers 32 */ 33 34 /** \defgroup MEMVEC Vector / matrix buffer allocator 35 * \ingroup MEMORY 36 * Allocators for allocating vector / matrix buffers 37 */ 38 39 /** \defgroup MEMTOOL Miscellaneous utilities for memory 40 * \ingroup MEMORY 41 * Miscellaneous utilities for implementing memory allocators 42 */ 43 44 /** 45 * @ingroup MEMBUF 46 * @brief Malloc memory allocator 47 * 48 */ 49 struct default_user_allocator_malloc_free 50 { 51 /** 52 * @brief Allocate a buffer 53 * 54 * @param[in] bytes The bytes 55 * 56 * @return A pointer to the allocated buffer 57 */ mallocarm_cmsis_dsp::default_user_allocator_malloc_free58 static char * malloc(const std::size_t bytes) 59 { 60 #if !defined(MEMORY_ALLOCATION_DEBUG) 61 return reinterpret_cast<char *>(std::malloc(bytes)); 62 #else 63 char *ret=reinterpret_cast<char *>(std::malloc(bytes)); 64 if (ret==nullptr) 65 { 66 std::cout << "out of memory for " << bytes << " bytes\r\n"; 67 } 68 return(ret); 69 #endif 70 } 71 72 /** 73 * @brief Free a buffer 74 * 75 * @param block The buffer to free 76 */ freearm_cmsis_dsp::default_user_allocator_malloc_free77 static void free(char * const block) 78 { 79 #if defined(MEMORY_ALLOCATION_DEBUG) 80 if (block==nullptr) 81 { 82 std::cout << "free null ptr \r\n"; 83 } 84 #endif 85 std::free(block); 86 } 87 }; 88 89 /** 90 * @ingroup MEMBUF 91 * @brief Aligned memory allocation 92 * 93 * @param[in] alignment The alignment of the buffer 94 * @param[in] size The size of the buffer 95 * 96 * @return A pointer to the new buffer 97 */ aligned_malloc(std::size_t alignment,std::size_t size)98inline void* aligned_malloc(std::size_t alignment, std::size_t size) 99 { 100 void *ptr=std::malloc(size+alignment+sizeof(void*)); 101 void *aligned = 102 reinterpret_cast<char*>( 103 (reinterpret_cast<std::size_t>(ptr)+sizeof(void*)+alignment) & ~(alignment-1) 104 ); 105 106 *(static_cast<void**>(aligned) - 1) = ptr; 107 return(aligned); 108 } 109 110 /** 111 * @ingroup MEMBUF 112 * @brief Free an aligned buffer 113 * 114 * @param ptr The pointer 115 */ 116 inline void aligned_free(void * ptr)117aligned_free(void* ptr) 118 { 119 if (ptr) { 120 std::free(*(static_cast<void**>(ptr) - 1)); 121 } 122 }; 123 124 /** 125 * @ingroup MEMBUF 126 * @brief Memory allocation for aligned buffers 127 * 128 */ 129 struct user_allocator_aligned_malloc 130 { 131 typedef std::size_t size_type; 132 typedef std::ptrdiff_t difference_type; 133 134 /** 135 * @brief Allocate a new buffer 136 * 137 * @param[in] bytes The bytes 138 * 139 * @return Pointer to the new buffer 140 */ mallocarm_cmsis_dsp::user_allocator_aligned_malloc141 static char * malloc(const size_type bytes) 142 { 143 #if !defined(MEMORY_ALLOCATION_DEBUG) 144 return reinterpret_cast<char *>(aligned_malloc(MEMORY_POOL_ALIGNMENT, bytes)); 145 #else 146 char *ret = reinterpret_cast<char *>(aligned_malloc(MEMORY_POOL_ALIGNMENT, bytes)); 147 if (ret==nullptr) 148 { 149 std::cout << "out of memory for " << bytes << " bytes\r\n"; 150 } 151 return(ret); 152 #endif 153 } 154 155 /** 156 * @brief Free a buffer 157 * 158 * @param block Pointer to the buffer 159 */ freearm_cmsis_dsp::user_allocator_aligned_malloc160 static void free(char * const block) 161 { 162 #if defined(MEMORY_ALLOCATION_DEBUG) 163 if (block==nullptr) 164 { 165 std::cout << "free null ptr \r\n"; 166 } 167 #endif 168 aligned_free(block); 169 } 170 }; 171 172 /* 173 174 Memory allocator for vector and matrix. 175 176 */ 177 178 // Default allocator 179 // Other allocator must be provided by user of the library 180 181 /** 182 * @ingroup MEMVEC 183 * @brief Default memory allocator for vectors and matrixes 184 * 185 * @tparam L Size known at build time in bytes 186 */ 187 template<int L> 188 struct malloc_allocator { 189 /** 190 * @brief Allocate a buffer with size known at runtime 191 * 192 * @param[in] sz The size 193 * 194 * @return Pointer to the buffer 195 */ allocatearm_cmsis_dsp::malloc_allocator196 static char* allocate ( vector_length_t sz) noexcept{ 197 char *res; 198 res=reinterpret_cast<char*>(std::malloc(sz)); 199 #if defined(MEMORY_ALLOCATION_DEBUG) 200 if (res==nullptr) 201 { 202 std::cout << "out of memory for " << sz << " bytes\r\n"; 203 } 204 #endif 205 return(res); 206 } 207 208 /** 209 * @brief Allocate a buffer with size known at build time 210 * 211 * @return Pointer to the buffer 212 */ allocatearm_cmsis_dsp::malloc_allocator213 static char* allocate ( ) noexcept{ 214 char *res; 215 res=reinterpret_cast<char*>(std::malloc(L)); 216 #if defined(MEMORY_ALLOCATION_DEBUG) 217 if (res==nullptr) 218 { 219 std::cout << "out of memory for " << L << " bytes\r\n"; 220 } 221 #endif 222 return(res); 223 } 224 225 /** 226 * @brief Destroys the given pointer. 227 * 228 * @param ptr The pointer 229 */ destroyarm_cmsis_dsp::malloc_allocator230 static void destroy ( char* ptr ) noexcept { 231 #if defined(MEMORY_ALLOCATION_DEBUG) 232 if (ptr==nullptr) 233 { 234 std::cout << "free null ptr \r\n"; 235 } 236 #endif 237 std::free(ptr); 238 } 239 240 }; 241 242 243 /* 244 245 Memory pool 246 247 Memory pool is using a buffer 248 allocator (aligned or normal malloc) 249 250 A memory pool can be used to by a memory allocator for 251 vectors and matrixes. 252 253 254 */ 255 256 struct ListElem; 257 258 /** 259 * @ingroup MEMTOOL 260 * @brief Simple list of elements 261 * 262 */ 263 struct ListElem { 264 ListElem *next; 265 }; 266 267 /** 268 * @ingroup MEMTOOL 269 * @brief This class describes a memory pool that can be used to build 270 * a memory allocator for vectors and matrixes 271 * 272 * @tparam BUF_SIZE Size of a buffer known at build time 273 * @tparam UserAllocator Memory allocator to allocate the memory buffer 274 */ 275 template<int BUF_SIZE,typename UserAllocator = default_user_allocator_malloc_free> 276 class MemoryPool { 277 public: 278 /** 279 * @brief Create a new memory pool 280 * 281 * @param[in] nbBufs The number of buffers to pre-allocate 282 */ MemoryPool(const uint16_t nbBufs)283 explicit MemoryPool(const uint16_t nbBufs) 284 { 285 buffer_list.reserve(nbBufs); 286 buffer_list.assign(nbBufs,nullptr); 287 for(auto p=buffer_list.begin();p != buffer_list.end(); ++p) 288 { 289 *p = UserAllocator::malloc(BUF_SIZE < sizeof(ListElem) ? sizeof(ListElem) : BUF_SIZE); 290 } 291 reset(); 292 }; 293 294 /** 295 * @brief Destroys the object. 296 */ ~MemoryPool()297 ~MemoryPool() 298 { 299 for(auto p=buffer_list.begin();p != buffer_list.end(); ++p) 300 { 301 UserAllocator::free(*p); 302 } 303 } 304 305 MemoryPool(const MemoryPool& other) = delete; 306 307 MemoryPool(MemoryPool&& other) = delete; 308 309 310 MemoryPool& operator=(const MemoryPool& other) = delete; 311 312 MemoryPool& operator=(MemoryPool&& other) = delete; 313 314 /** 315 * @brief Gets the new free buffer. 316 * 317 * @return The new buffer. 318 */ get_new_buffer()319 char* get_new_buffer() noexcept 320 { 321 /* No error handling. 322 The sizing of the pool must have been done, for 323 instance, with a statistic allocator. 324 Allocation is thus assumed to succeed */ 325 char* res = reinterpret_cast<char*>(free); 326 free = free->next; 327 #if defined(MEMORY_ALLOCATION_DEBUG) 328 if (res == nullptr) 329 { 330 std::cout << "memory pool alloc error " << BUF_SIZE << " bytes\r\n"; 331 } 332 #endif 333 return(res); 334 } 335 336 /** 337 * @brief Release the buffer so that it can be reused 338 * 339 * @param buf The buffer 340 */ recycle_buffer(char * buf)341 void recycle_buffer(char* buf) noexcept 342 { 343 ListElem *l = reinterpret_cast<ListElem*>(buf); 344 #if defined(MEMORY_ALLOCATION_DEBUG) 345 if (l == nullptr) 346 { 347 std::cout << "memory pool free error " << BUF_SIZE << " bytes\r\n"; 348 } 349 #endif 350 l->next = free; 351 free = l; 352 } 353 354 /** 355 * @brief Release all the buffers so that they can be reused 356 */ reset()357 void reset() noexcept 358 { 359 const int nbBufs = buffer_list.size(); 360 for(int i=0;i<nbBufs-1;i++) 361 { 362 ListElem *l=reinterpret_cast<ListElem*>(buffer_list[i]); 363 l->next = reinterpret_cast<ListElem*>(buffer_list[i+1]); 364 } 365 ListElem *l=reinterpret_cast<ListElem*>(buffer_list[nbBufs-1]); 366 l->next = nullptr; 367 free = reinterpret_cast<ListElem*>(buffer_list[0]); 368 } 369 370 371 372 protected: 373 ListElem *free; 374 std::vector<char*> buffer_list; 375 }; 376 377 378 /*! @} */ 379 380 }