ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
rttrallocator.hpp
Go to the documentation of this file.
1/** ************************************************************************************************
2 * \file
3 * This header file is part of module \alib_monomem of the \aliblong.
4 *
5 * \emoji :copyright: 2013-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_MONOMEM_UTIL_RTTRALLOCATOR
9#define HPP_ALIB_MONOMEM_UTIL_RTTRALLOCATOR
10
11#if ALIB_DEBUG && !defined(HPP_ALIB_LANG_DBGTYPEDEMANGLER)
13#endif
14
15#if !defined(HPP_ALIB_MONOMEM_MONOALLOCATOR)
17#endif
18
19#if !defined(HPP_ALIB_LANG_SIDILIST)
20# include "alib/lang/sidilist.hpp"
21#endif
22
23#if ALIB_DEBUG
24# if ALIB_STRINGS && !defined (HPP_ALIB_STRINGS_LOCALSTRING)
26# endif
27#endif
28
29#if !defined (HPP_ALIB_MONOMEM_MONOMEM)
31#endif
32
33namespace alib { namespace monomem {
34
35/**
36 * Utility types of module \alib_monomem.
37 */
38namespace util {
39
40/** ************************************************************************************************
41 * This struct's name stands for "run-time type recycling allocator".
42 * The struct encapsulates an allocator and recycles (caches) objects whose size and alignment are
43 * only determined and detected at run-time.<br>
44 * This type should \e only be used in combination with struct \alib{monomem;StdContMARecycling}
45 * or in similar (unlikely) situations when the type of recyclable objects is unknown at compile
46 * time.
47 *
48 * It is provided by \alib to support recycling of monotonically allocated memory with container
49 * types provided by the C++ standard library. With those, the internal node types are unspecified.
50 * A typical implementation and use of the containers will always allocate the same object size.
51 * This is detected with the first allocation and from this point in time, future de-allocations
52 * will recycle pieces of memory of exactly this type.
53 *
54 * If no \alib{monomem;MonoAllocator} is given with construction, this recycler uses
55 * <c>std::malloc</c> and <c>std::free</c> for memory allocation and de-allocation.
56 * While such operation mode does not imply all performance benefits of monotonic allocation
57 * scenarios, still the recycling of node objects may avoid many malloc/free operations and
58 * therefore reduce memory fragmentation significantly.<br>
59 * Method #RecycleChunk will not create recyclable objects in that mode, but will duly
60 * use <c>std::free</c> to directly free a chunk of non-object size.
61 **************************************************************************************************/
63{
64 /** The node type of the internal node type used for stacking recyclables. Besides inheriting
65 * the single-list pointer, this type is empty. */
66 struct Node : lang::SidiNodeBase<Node>
67 {};
68
69 /** The monotonic allocator */
71
72 /** List of destructed objects available for recycling. */
74
75 /** The object size of recylables. Will be detected with the first invocation of #Get. */
77
78 /** The required object alignment. Will be detected with the first invocation of #Get. */
80
81 #if ALIB_DEBUG
82 /** The detected object's run-time type information struct.<br>
83 * Available only in debug builds. */
84 const std::type_info* dbgDetectedObjectTypeInfo = nullptr;
85
86 /** Flag on raising an \alib warning. Defaults to \c true and set to \c false when a
87 * corresponding warning was given..<br>
88 * Available only in debug builds. */
90
91 /** Flag on raising an \alib warning. Defaults to \c true and set to \c false when a
92 * corresponding warning was given..<br>
93 * Available only in debug builds. */
95
96 /** Flag on raising an \alib warning. Defaults to \c true and set to \c false when a
97 * corresponding warning was given..<br>
98 * Available only in debug builds. */
100
101 /** Flag on raising an \alib warning. Defaults to \c true and set to \c false when a
102 * corresponding warning was given..<br>
103 * Available only in debug builds. */
105 #endif
106
107 /**
108 * Constructor taking the monotonic allocator.
109 *
110 * If \c nullptr is given, this recycler uses <c>std::malloc</c> and <c>std::free</c> for memory
111 * allocation and de-allocation.
112 *
113 * @param pAllocator The monotonic allocator. If \c nullptr is given, still recycling of node
114 * objects is performed.
115 */
117 : allocator(pAllocator)
118 {
119 DBG_MONOMEM_FILE_DOMAIN("UTIL/RTTA")
120 }
121
122
123 // #############################################################################################
124 // ### Allocation
125 // #############################################################################################
126#if defined(ALIB_DOX)
127 /** ********************************************************************************************
128 * Allocates or recycles memory for the dedicated object type. With the first invocation
129 * of this method, this type is determined object type.
130 * In debug builds, this method will raise an \alib warning in case a different
131 * object type is requested.
132 *
133 * @param size The requested size.
134 * @param alignment The requested alignment
135 * @param dbgTypeInfo The type information of the object to allocate.
136 * Available only in debug builds.
137 * @return The requested memory.
138 **********************************************************************************************/
139 inline
140 char* Get( size_t size, size_t alignment, const type_info& dbgTypeInfo);
141#else
142 char* Get( size_t size, size_t alignment ALIB_DBG(, const std::type_info& dbgTypeInfo) )
143 {
144 ALIB_DBG( (void) dbgTypeInfo; )
145
146 // detect object size
147 if(detectedObjectSize == 0)
148 {
149 detectedObjectSize = size;
150 detectedObjectAlignment = alignment;
151 ALIB_DBG( dbgDetectedObjectTypeInfo = &dbgTypeInfo; )
152 DBG_MONOMEM_INFO("Object type detected : {!Q<>}", dbgTypeInfo )
153 ALIB_ASSERT_ERROR( alignment >= alignof(Node),
154 "MONOMEM/RTTRA", "Struct RTTRAllocator can not be used to recycle types with an alignment "
155 "smaller than ", alignof(Node) )
156 }
157
158 if( size == detectedObjectSize && detectedObjectAlignment == alignment )
159 {
160 if( !stack.isEmpty() )
161 {
162 DBG_MONOMEM_VERBOSE( "Recycling object. Type: {!Q<>}", dbgTypeInfo )
163
164 return reinterpret_cast<char*>( stack.popFront() );
165 }
166 }
167 #if ALIB_DEBUG
168 else
169 {
170 #if ALIB_STRINGS
172 "A different object was requested for allocation!\n"
173 " Previous type : <" << lang::DbgTypeDemangler(*dbgDetectedObjectTypeInfo).Get() << ">\n"
174 " Requested type: <" << lang::DbgTypeDemangler( dbgTypeInfo ).Get() << ">\n" <<
175 "Note: This allocator may not be efficient when used.\n"
176 " If this is a use case using a 'std' library container, this message indicates\n"
177 " that a RTTRAllocator was shared between different container instantiations.\n"
178 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
179 " prevent this concept from working. See ALib manual for further information" )
180 #else
182 "A different object was requested for allocation!\n" )
183 #endif
184
186 DBG_MONOMEM_WARNING( "Allocating a different object type {!Q<>}\n Note: This object can not be recycled.", dbgTypeInfo )
187 return allocator ? allocator->Alloc( size, alignment )
188 : static_cast<char*>(std::malloc( size ));
189 }
190 #endif
191
192 DBG_MONOMEM_VERBOSE( "Allocating object. Type: {!Q<>}", dbgTypeInfo )
193
194 ALIB_ASSERT_ERROR( allocator != nullptr || alignment <= alignof(std::max_align_t),
195 "MONOMEM/RTTRA",
196 "Struct RTTRAllocator can not be used to allocate types with an alignment "
197 "greater than 'alignof(std::max_align_t)'." )
198 return allocator ? allocator->Alloc( size, alignment )
199 : static_cast<char*>(std::malloc( size ));
200 }
201#endif // defined(ALIB_DOX)
202
203#if defined(ALIB_DOX)
204 /** ********************************************************************************************
205 * Allocates memory for a type different to the dedicated, detected object type.
206 * @param size The requested size.
207 * @param alignment The requested alignment
208 * @param dbgTypeInfo The type information of the object to allocate.
209 * Available only in debug builds.
210 * @return The requested memory.
211 **********************************************************************************************/
212 inline
213 char* AllocUnrelated( size_t size, size_t alignment, const type_info& dbgTypeInfo);
214#else
215 char* AllocUnrelated( size_t size, size_t alignment ALIB_DBG(, const std::type_info& dbgTypeInfo))
216 {
217 ALIB_DBG( (void) dbgTypeInfo; )
218 DBG_MONOMEM_VERBOSE( "Allocating other. Type: {!Q<>}", dbgTypeInfo )
219 return allocator ? allocator->Alloc( size, alignment )
220 : static_cast<char*>(std::malloc( size ));
221 }
222#endif // defined(ALIB_DOX)
223
224
225 // #############################################################################################
226 // ### De-allocation
227 // #############################################################################################
228#if defined(ALIB_DOX)
229 /** ********************************************************************************************
230 * Deallocates memory for the dedicated, detected object type.
231 *
232 * In debug builds, this method will raise an \alib warning in case a different
233 * object type is deallocated as had been detected.
234 * Furthermore, a warning is raised in case no previous call to #Get has been performed.
235 *
236 * @param mem The object to deallocate.
237 * @param size The size of the object to deallocate.
238 * @param alignment The alignment of the object to deallocate.
239 * @param dbgTypeInfo The type information of the object to de-allocate.
240 * Available only in debug builds.
241 **********************************************************************************************/
242 inline
243 void Recycle( void* mem, size_t size, size_t alignment, const type_info& dbgTypeInfo );
244#else
245 void Recycle( void* mem, size_t size, size_t alignment ALIB_DBG(, const std::type_info& dbgTypeInfo) )
246 {
247 if( size == detectedObjectSize
248 && alignment == detectedObjectAlignment )
249 {
250 stack.pushFront( reinterpret_cast<Node*>( mem ) );
251
252 DBG_MONOMEM_VERBOSE( "Stacking object. Type: {!Q<>}", dbgTypeInfo )
253 }
254 else
255 {
256 if( allocator == nullptr )
257 std::free( mem );
258 #if ALIB_DEBUG
259 if( detectedObjectSize == 0 )
260 {
261 #if ALIB_STRINGS
263 "De-allocation prior to a first object allocation needed to detect recyclable type!\n"
264 " De-allocated object type: <" << lang::DbgTypeDemangler( dbgTypeInfo ).Get() << ">\n" <<
265 "Note: This allocator may not be efficient when used.\n"
266 " If this is a use case using a 'std' library container, this message indicates\n"
267 " an 'unusual' implementation of such C++ standard library." )
268 #else
270 "De-allocation prior to a first object allocation needed to detect recyclable type!" )
271 (void) dbgTypeInfo;
272 #endif
274 }
275 else
276 {
277 #if ALIB_STRINGS
279 "A different object for was requested for de-allocoation!\n"
280 " Previous type : <" << lang::DbgTypeDemangler(*dbgDetectedObjectTypeInfo).Get() << ">\n"
281 " Requested type: <" << lang::DbgTypeDemangler( dbgTypeInfo ).Get() << ">\n" <<
282 "Note: This allocator may not be efficient when used.\n"
283 " If this is a use case using a 'std' library container, this message indicates\n"
284 " that a RTTRAllocator was shared between different container instantiations.\n"
285 " If this is not the case, than an 'unusual' implementation of such C++ library may\n"
286 " prevent this concept from working. See ALib manual for further information" )
287 #else
289 "A different object for was requested for de-allocoation!" )
290 #endif
292 }
293 #endif
294 }
295 }
296#endif
297
298
299#if defined(ALIB_DOX)
300 /** ********************************************************************************************
301 * Deallocates memory for a type different to the dedicated, detected object type.
302 *
303 * In debug builds, this method will raise an \alib warning no previous call to #Get
304 * has been performed.<br>
305 * Furthermore, a warning is raised in case that the provided memory chunk is too small
306 * to be sliced into at least one recyclable object.
307 *
308 * @param mem The object to deallocate.
309 * @param size The size of the object to deallocate.
310 * @param alignment The alignment of the object to deallocate.
311 * @param dbgTypeInfo The type information of the object to de-allocate.
312 * Available only in debug builds.
313 **********************************************************************************************/
314 inline
315 void RecycleChunk( char* mem, size_t size, size_t alignment, const type_info& dbgTypeInfo );
316#else
317 void RecycleChunk( void* mem, size_t size, size_t alignment ALIB_DBG(, const std::type_info& dbgTypeInfo) )
318 {
319 // in non-memory mode, chunks can not be split.
320 if ( allocator == nullptr )
321 {
322 std::free( mem );
323 return;
324 }
325
326 // if object size not detected, yet, we can not create recyclables.
327 ALIB_DBG( size_t origSize= size; )
328 if( detectedObjectSize == 0)
329 {
330 #if ALIB_STRINGS
332 "De-allocation prior to a first object allocation needed to detect recyclable type!\n"
333 " De-allocated object type: <" << lang::DbgTypeDemangler( dbgTypeInfo ).Get() << ">\n"
334 "Note: If this recycler is used with a 'std' library container, this either\n"
335 " indicates an 'unusual' implementation of such C++ standard library,\n"
336 " or a manual shrink of the capacity without any prior object insertion." )
337 #else
339 "De-allocation prior to a first object allocation needed to detect recyclable type!" )
340 ALIB_DBG( (void) dbgTypeInfo );
341 #endif
343 return;
344 }
345
346 // align beginning of buffer (if necessary)
347 if( detectedObjectAlignment > alignment )
348 std::align( detectedObjectAlignment , // alignment: the desired alignment
349 detectedObjectSize , // size : the size of the storage to be aligned
350 mem , // ptr : pointer to contiguous storage of at least 'space' bytes
351 size ); // space : the size of the buffer in which to operate
352
353 // create recyclables
354 ALIB_DBG( size_t cntStackedObjects= 0; )
355 while(size > detectedObjectSize)
356 {
357 stack.pushFront( reinterpret_cast<Node*>( mem ) );
359 mem = reinterpret_cast<char*>(mem) + detectedObjectSize;
361 size -= detectedObjectSize;
362 ALIB_DBG( ++cntStackedObjects; )
363 }
364
365 #if ALIB_STRINGS
366 ALIB_ASSERT_WARNING( cntStackedObjects > 0, "MONOMEM/RTTRA", NString1K() <<
367 "De-allocated chunk's size is smaller than detected object size.\n"
368 " Deallocated object: Type: <" << lang::DbgTypeDemangler( dbgTypeInfo ).Get() << ">\n"
369 " Size: " << origSize << " bytes, alignment: " << alignment << "\n"
370 " Detected object: Type: <" << lang::DbgTypeDemangler( *dbgDetectedObjectTypeInfo ).Get() << ">\n"
371 " Size: " << detectedObjectSize << " bytes, alignment: " << detectedObjectAlignment << "\n"
372 "Note: If this recycler is used with a <std::unordered_map> or <std::unordered_set>,\n"
373 " this message may be eliminated by reserving a reasonable initial bucket size." )
374 #else
375 ALIB_ASSERT_WARNING( cntStackedObjects > 0, "MONOMEM/RTTRA",
376 "De-allocated chunk's size is smaller than detected object size." )
377 ALIB_DBG( (void) origSize );
378 #endif
379
380 DBG_MONOMEM_INFO( "Stacking {} objects from de-allocated memory of size {} (lost {} bytes). Deallocated type: {!Q<>}.",
381 cntStackedObjects,
382 origSize,
383 origSize - cntStackedObjects * detectedObjectSize,
384 dbgTypeInfo )
385 }
386#endif
387
388}; // RTTRAllocator
389
390}} // namespace alib[::monomem::util]
391
392
393/// Type alias in namespace \b alib.
395
396} // namespace [alib]
397
398
399
400#endif // HPP_ALIB_MONOMEM_UTIL_RTTRALLOCATOR
ALIB_API const char * Get()
ALIB_FORCE_INLINE char * Alloc(size_t size, size_t alignment)
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ALIB_ASSERT_WARNING(cond,...)
Definition alib.hpp:985
#define ALIB_DBG(...)
Definition alib.hpp:457
Definition alib.cpp:57
NLocalString< 1024 > NString1K
Type alias name for TLocalString<nchar,1024> .
const std::type_info * dbgDetectedObjectTypeInfo
char * AllocUnrelated(size_t size, size_t alignment, const type_info &dbgTypeInfo)
RTTRAllocator(MonoAllocator *pAllocator)
char * Get(size_t size, size_t alignment, const type_info &dbgTypeInfo)
void RecycleChunk(char *mem, size_t size, size_t alignment, const type_info &dbgTypeInfo)
void Recycle(void *mem, size_t size, size_t alignment, const type_info &dbgTypeInfo)
lang::SidiListHelper< Node > stack