ALib C++ Library
Library Version: 2402 R1
Documentation generated by doxygen
Loading...
Searching...
No Matches
selfcontained.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_SELF_CONTAINED
9#define HPP_ALIB_MONOMEM_SELF_CONTAINED 1
10
11#if !defined(HPP_ALIB) && !defined(ALIB_DOX)
12# include "alib/alib.hpp"
13#endif
14
15#if !defined (HPP_ALIB_MONOMEM_MONOALLOCATOR)
17#endif
18
19namespace alib { namespace monomem {
20
21/** ************************************************************************************************
22 * This templated class supports the implementation of types whose fields are allocated within
23 * a \alib{monomem;MonoAllocator}. In addition the monotonic allocator itself is also
24 * self-contained. This results in the following:
25 * - The size of an instance of this class is equal to the size of a single C++ pointer.
26 * The only member is a pointer to an object of internal type \alib{monomem::SelfContained;Fields}.
27 * - A single dynamic memory allocation is performed to create a derived instance of the class.
28 * - With method #Allocator, the self-contained \alib{monomem;MonoAllocator} can be used to
29 * allocate further objects.
30 *
31 * \alib uses this type in various areas. A prominent sample is class \alib{lang;Exception}
32 * which is the unique <c>C++ throwable</c> used by the library.<br>
33 * The general use-case for this type is similar to the use-case of class %MonoAllocator, with
34 * the addition that the life-cycle of the allocated objects are bound to the life-cycle of
35 * an instance of the derived type. A well understandable sample for this is found with type
36 * \alib{config;Variable} implemented in module \alib_config.
37 *
38 *
39 * The proposed schematic for using this class is as follows:
40 * 1. A struct or class named for example \b MyTypesFields, that incorporates all fields of the
41 * self-contained class \b MyType is to be declared.<br>
42 * Such declaration might be placed in a sub-namespace called \b detail.
43 * 2. Type \b MyType inherits this class \b SelfContained using \b MyTypesFields as template
44 * parameter.
45 * 3. Constructors of \b MyType invoke the constructor of \b SelfContained providing the chunk
46 * size of the allocator along with the arguments for the construction of \b MyTypesFields.
47 * 5. The copy-constructor of \b MyType should either be deleted (the usual case as self-contained
48 * objects most probably are not copyable) or defined to create another self-contained object
49 * of the derived type.
50 * 6. A move-constructor of \b MyType should be defined that just invokes this struct's move
51 * constructor, forwarding the argument using \c std::move.
52 * 7. Instead of keyword \c this, methods of \b MyType use method #Self to access field members
53 * (which are defined in helper struct \b MyTypesFields).
54 * 8. Methods of the derived type might allocate further objects using the internal monotonic allocator,
55 * which is accessed with method #Allocator.
56 *
57 * A quick sample code of this schematic is given with chapter
58 * \ref alib_monomem_selfcontained_allocator of the Programmer's Manual of this \alibmod.
59 *
60 * It is superfluous to say that instances of derived types should not be created using C++ keyword
61 * <c>new</c> but instead should be created on stack memory or embedded as value members in other
62 * types.
63 *
64 *
65 * Finally this type supports memory resets. For this, a \alib{monomem;MonoAllocator::Snapshot}
66 * is created right after construction. Method #Reset resets the internal monotonic allocator using
67 * this snapshot. Before that, the \p{TContained} object is destructed and afterwards is
68 * "re-constructed" using <em>C++ placement new</em>. For the latter, variadic construction
69 * parameters are accepted by method #Reset.<br>
70 * The memory reserved by #Reset can be increased with method #TakeSnapshot. Furthermore,
71 * the monotonic allocator's pair of methods \b Reset and \b TakeSnapshot are also allowed to be used
72 * to implement more complex (nested) snapshots.
73 *
74 * @tparam TContained Default-constructible type of the stored object.
75 *
76 * \see
77 * Chapter
78 * \ref alib_monomem_selfcontained_allocator of the Programmer's Manual of this \alibmod.<br>
79 * For more complex sample (code) see classes \alib{lang;Exception} and/or
80 * \alib{config;Variable}, which uses the mechanisms provided by this type.
81 **************************************************************************************************/
82template<typename TContained>
84{
85 public:
86 /**
87 * The data members that are allocated in the first chunk of the allocator.
88 */
89 struct Fields
90 {
91 /** The allocator that this class is contained in.*/
93
94 /** Snapshot pointing behind this object in the first allocated chunk. */
96
97 /** The custom fields */
98 TContained custom;
99
100 /**
101 * Constructor.
102 * @tparam TArgs The argument types used for constructing \p{TContained}.
103 * @param firstChunk The first argument to field #allocator.
104 * @param initialChunkSize The second argument to field #allocator.
105 * @param chunkGrowthInPercent Growth faktor in percent (*100), applied to each
106 * allocation of a next chunk size.
107 * Values provided should be greater than 100.<p>
108 * @param args The arguments to construct the instance of
109 * \p{TContained}.
110 */
111 template<typename... TArgs>
113 size_t initialChunkSize, unsigned int chunkGrowthInPercent,
114 TArgs&&... args )
115 : allocator( firstChunk, initialChunkSize, chunkGrowthInPercent )
116 , custom( std::forward<TArgs>(args)... )
117 {}
118 };
119
120 protected:
121 /**
122 * The only member of this class. It points to the start of the 'effective' members,
123 * residing in the first chunk of the mono allocator.
124 */
126
127 public:
128
129 /** ********************************************************************************************
130 * Creates object #fields allocated in the first chunk of the monotonic allocator which is found
131 * in that struct.
132 *
133 * The instance of custom type \p{TContained} which is found in #fields will be constructed
134 * using the given variadic arguments \p{args}.
135 *
136 * @tparam TArgs The argument types used for constructing \p{TContained}.
137 * @param initialChunkSize The initial size of memory chunks used with the monotonic
138 * allocator.
139 * @param chunkGrowthInPercent Optional growth factor in percent (*100), applied to each
140 * allocation of a next chunk size.
141 * Values provided should be greater than 100.
142 * @param args The arguments to construct the instance of \p{TContained}.
143 **********************************************************************************************/
144 template<typename... TArgs>
145 SelfContained( size_t initialChunkSize, unsigned int chunkGrowthInPercent, TArgs&&... args )
146 {
147 ALIB_ASSERT_ERROR( sizeof(Fields) < initialChunkSize - MonoAllocator::MaxUsableSpaceLoss(),
148 "MONOMEM", "Chunk size to small to create self-contained object." )
149 auto firstChunk= MonoAllocator::Chunk::create( initialChunkSize - MonoAllocator::MaxUsableSpaceLoss() );
150
151 fields= reinterpret_cast<Fields*>( firstChunk->alloc( sizeof( Fields), alignof(Fields) ) );
152 new (fields) Fields( firstChunk, initialChunkSize, chunkGrowthInPercent,
153 std::forward<TArgs>(args)... );
154
156 }
157
158 /** ****************************************************************************************
159 * Resets the monotonic allocator that this object is contained in to the snapshot created
160 * right after construction.
161 * The allocated memory chunks will remain allocated and reused. Prior to resetting,
162 * the destructor of the custom object of type \p{TContained} is invoked and after
163 * the reset, in-place construction is performed.
164 *
165 * To preserve further custom objects that might have been initially allocated, method
166 * #TakeSnapshot might be used after the initial allocations (aka after construction of
167 * the derived type). In this case, a derived type should expose an own version of this
168 * method which prior and after the invocation this base implementation, either destroys
169 * and reconstructs own objects or just leaves them intact.
170 *
171 * It is up to the implementation of the derived class if this method should be exposed
172 * or not.
173 *
174 * It is furthermore allowed to use methods \alib{monomem;MonoAllocator::TakeSnapshot}
175 * and \alib{monomem;MonoAllocator::Reset} directly, to allow more flexible,
176 * nested snapshots.
177 *
178 * @tparam TArgs The argument types used for re-constructing \p{TContained}.
179 * @param args The arguments to re-construct the instance of \p{TContained}.
180 ******************************************************************************************/
181 template<typename... TArgs>
182 void Reset( TArgs&&... args )
183 {
185
187
188 new (&fields->custom) TContained( std::forward<TArgs>(args)... );
189 }
190
191
192 /** ********************************************************************************************
193 * Deleted default constructor.
194 **********************************************************************************************/
195 SelfContained() = delete;
196
197 /** ********************************************************************************************
198 * Deleted copy constructor.
199 **********************************************************************************************/
201
202 /** ********************************************************************************************
203 * Move constructor. Sets field #fields of \p{src} to \c nullptr.
204 *
205 * @param move The object to move.
206 **********************************************************************************************/
208 {
209 this->fields= move.fields;
210 move .fields= nullptr;
211 }
212
213 /** ********************************************************************************************
214 * Deleted copy constructor.
215 * @return Nothing (deleted).
216 **********************************************************************************************/
218
219 /** ********************************************************************************************
220 * Move assignment operator. Sets field #fields of \p{src} to \c nullptr.
221 *
222 * @param src The object to move.
223 * @return A reference to this object.
224 **********************************************************************************************/
226 {
227 this->allocator = src.allocator;
228 src.allocator = nullptr;
229 return *this;
230 }
231
232 /** ********************************************************************************************
233 * Destructor.
234 * If #fields is not \c nullptr, the destructors of \p{TContained} and the monotonic allocator are
235 * explicitly invoked.
236 **********************************************************************************************/
238 {
239 if( !fields ) // might happen if moved.
240 return;
241
242 // Destruct the contained objects
245 }
246
247 /** ********************************************************************************************
248 * Returns a non-constant reference to the stored object of type \p{TContained}.
249 * @return A reference to \p{TContained}.
250 **********************************************************************************************/
251 TContained& Self()
252 {
253 return fields->custom;
254 }
255
256 /** ********************************************************************************************
257 * Returns a constant reference to the stored object of type \p{TContained}.
258 * @return A constant reference to \p{TContained}.
259 **********************************************************************************************/
260 const TContained& Self() const
261 {
262 return fields->custom;
263 }
264
265 /** ********************************************************************************************
266 * Returns a non-constant reference to the self-contained allocator object.
267 * @return A reference to the self-contained allocator object.
268 **********************************************************************************************/
270 {
271 return fields->allocator;
272 }
273
274 /** ********************************************************************************************
275 * Returns a constant reference to the self-contained allocator object.
276 * @return A constant reference to the self-contained allocator object.
277 **********************************************************************************************/
279 {
280 return fields->allocator;
281 }
282
283 /** ********************************************************************************************
284 * With the construction of a self-contained object, a \alib{monomem;MonoAllocator::Snapshot}
285 * is taken, used with method #Reset to clear the allocator without disposing the
286 * memory of the self-contained object itself.
287 *
288 * With this method, this snapshot can be modified to use the current fill of the allocator.
289 * Note that it is still allowed to reset the monotonic allocator "manually",
290 * using custom snapshot objects received with \alib{monomem;MonoAllocator::TakeSnapshot}.
291 **********************************************************************************************/
293 {
295 }
296};
297
298}} // namespace [alib::monomem]
299
300#endif // HPP_ALIB_MONOMEM_SELF_CONTAINED
ALIB_API void Reset(const Snapshot &snapshot=Snapshot())
static constexpr size_t MaxUsableSpaceLoss()
SelfContained(size_t initialChunkSize, unsigned int chunkGrowthInPercent, TArgs &&... args)
SelfContained & operator=(SelfContained &)=delete
const MonoAllocator & Allocator() const
SelfContained(SelfContained &&move) noexcept
const TContained & Self() const
SelfContained(SelfContained &)=delete
void Reset(TArgs &&... args)
SelfContained & operator=(SelfContained &&src)
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
static ALIB_FORCE_INLINE void Destruct(T *object)
Definition alib.cpp:57
Fields(MonoAllocator::Chunk *firstChunk, size_t initialChunkSize, unsigned int chunkGrowthInPercent, TArgs &&... args)