ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
sharedmonoval.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_SHARED_MONO_PTR
9#define HPP_ALIB_MONOMEM_SHARED_MONO_PTR 1
10#pragma once
11#if !defined(DOXYGEN)
12# include "alib/alib.hpp"
13#endif
14ALIB_ASSERT_MODULE(MONOMEM)
15#if ALIB_THREADS
16# include "alib/time/ticks.hpp"
17#endif
18
21#include <atomic>
22
23
24namespace alib { namespace monomem {
25
26//==================================================================================================
27/// This templated class is a utility type for \alib{monomem;TMonoAllocator} and supports the
28/// following mechanics:
29/// - It creates a first \alib{monomem;detail::Buffer;buffer} usable by a \b MonoAllocator.
30/// - A custom type defined by template parameter \p{T} is placed at the beginning of
31/// that buffer.
32/// - Along with the custom type, the \b MonoAllocator that receives this first buffer is likewise
33/// emplaced in the buffer.
34/// - Finally, an atomic usage counter is placed as a third member inside that buffer.
35/// - Only one pointer into this first buffer is stored with this type.
36/// - This type overloads #operator->() and #operator*() to access the members of the custom type.
37/// - The concept of an "automatic pointer", similar to <c>std::shared_ptr</c> is
38/// implemented with this type.
39/// - The default-constructor of this type just sets the internal pointer to \c nullptr.
40///
41/// All of the above results in the following:
42/// - The size of an instance of this class is equal to the size of a single C++ pointer.
43/// The only member is a pointer to an object of internal type
44/// \alib{monomem::TSharedMonoVal;FieldMembers}.
45/// - A single dynamic memory allocation is performed to create an instance of the class, which
46/// holds all data and allows further monotonic allocations.
47/// - Values of this type are \e nulled, when default constructed.
48/// - Values of this type can be shared (copied as value), which increases the use counter.
49/// - Values of this type can be moved, which keeps the use counter as is.
50/// - Values of this type can be emptied by assigning \c nullptr or invoking #SetNulled.
51/// - At the moment that the last copy gets out of scope, is deleted or \e nulled,
52/// the contained object is destructed, and all monotonic memory is freed.
53/// - The allocator can be received with #GetAllocator and used by the contained type.
54/// A derived type may volunteer to publish the allocator as well to be used by any
55/// entity that gets access to a copy of the automatic pointer.
56/// - Member access is performed with the overloaded <c>operator->()</c>.
57/// Alternatively (and sometimes needed) other provided operators and methods like #Get may
58/// be used.
59///
60/// In contrast to the container types \alib{containers;SharedVal} and \alib{containers;SharedPtr},
61/// this type is <b>most commonly used as a base class</b> of types that should to be fully
62/// self-contained (like the types listed below).
63///
64/// \see
65/// - A step by step sample that can be used to bootstrap custom usages is presented in chapter
66/// \ref alib_contmono_smv of the Programmer's Manual of this \alibmod.
67/// - The following types found across \alib may be reviewed for understanding this type's usage
68/// and its potential use cases:
69/// - Class \alib{config;TSharedConfiguration},
70/// - Class \alib{files;TSharedFTree}, and
71/// - Class \alib{lang;Exception}.
72/// - Chapter \ref alib_contmono_smv_locking of the Programmer's Manual of module
73/// \alib_monomem_nl.
74///
75/// @tparam T The custom type that is embedded along with the \b MonoAllocator.
76/// @tparam TAllocator The \ref alib_contmono_chaining "chained allocator" that is used by the
77/// monotonous allocator that this type creates inside its first buffer.<br>
78/// Usually, type \alib{lang;HeapAllocator} is to be given here.
79/// @tparam TLock The type of \ref alib_threads_locks "ALib lock" to embed besides \p{T}.
80/// With the provision of <c>void</c>, the integration of a lock is
81/// suppressed.<br>
82/// See chapter \ref alib_contmono_smv_locking of the Programmer's Manual of
83/// module \alib_monomem_nl for further details.
84//==================================================================================================
85template<typename T, typename TAllocator, typename TLock>
87{
88 protected:
89 /// Same as \alib{monomem::TSharedMonoVal;FieldMembersWithLock} but missing the lock.
90 /// This type is chosen if template parameter \p{TLock} equals <c>void</c>.<br>
91 /// The internals of this type are not further documented.
93 {
94 #if !DOXYGEN
97 std::atomic<unsigned int> refCount;
98 FieldMembersNoLock( TAllocator& pAllocator,
99 detail::Buffer* firstBuffer,
100 size_t initialBufferSize,
101 unsigned int bufferGrowthInPercent )
102 : allocator( pAllocator, firstBuffer, initialBufferSize, bufferGrowthInPercent )
103 , refCount(1) {}
104 template< typename TEnableIf= TAllocator,
105 ATMP_IF(std::is_default_constructible<TEnableIf>::value)>
107 size_t initialBufferSize,
108 unsigned int bufferGrowthInPercent )
109 : allocator( ALIB_DBG("ShardMonoVal",) firstBuffer, initialBufferSize, bufferGrowthInPercent )
110 , refCount(1) {}
111 #endif
112 }; // struct FieldMembersNoLock;
113
114 /// The combined struct of members that are allocated in the first buffer of the
115 /// monotonic allocator.
117 {
118 /// The space for the custom member. The instance will be constructed using placement-new.
120
121 /// The allocator that this class is contained in.
123
124 /// The reference counter used to implement the <c>std::shared_ptr</c> behavior.
125 std::atomic<unsigned int> refCount;
126
127 /// The embedded lock.
128 TLock lock;
129
130 /// Constructor.
131 /// Creates the allocator and initializes #refCount. The #custom contents will be
132 /// constructed by an obligatory, separated call to #ConstructT.
133 /// @param pAllocator The chained allocator of the monotonic allocator.
134 /// @param firstBuffer The first argument to field #allocator.
135 /// @param initialBufferSize The second argument to field #allocator.
136 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
137 /// with each next buffer allocation.
138 /// Values provided should be greater than 100.<p>
139 FieldMembersWithLock( TAllocator& pAllocator,
140 detail::Buffer* firstBuffer,
141 size_t initialBufferSize,
142 unsigned int bufferGrowthInPercent )
143 : allocator( pAllocator, firstBuffer, initialBufferSize, bufferGrowthInPercent )
144 , refCount(1) {}
145
146 /// Alternative constructor missing the allocator instance.
147 /// This is used only with allocators that are default constructible
148 /// (like \alib{lang;HeapAllocator} is).
149 /// @param firstBuffer The first argument to field #allocator.
150 /// @param initialBufferSize The second argument to field #allocator.
151 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer
152 /// size with each next buffer allocation.
153 /// Values provided should be greater than 100.<p>
154 template< typename TEnableIf= TAllocator,
155 ATMP_IF(std::is_default_constructible<TEnableIf>::value)>
157 size_t initialBufferSize,
158 unsigned int bufferGrowthInPercent )
159 : allocator( ALIB_DBG("ShardMonoVal",)
160 firstBuffer, initialBufferSize, bufferGrowthInPercent )
161 , refCount(1) {}
162 }; // struct FieldMembersWithLock;
163
164 #if !DOXYGEN
165 #if ALIB_DEBUG && !DOXYGEN
166 void dbgassert() const { ALIB_ASSERT_ERROR(members,"MONOMEM","Empty shared instance") }
167 #else
168 void dbgassert() const {}
169 #endif
170 #endif
171
172 /// The type of field members to include.
173 /// Dependent on the template parameter \p{TLock}, either
174 /// \alib{monomem::TSharedMonoVal;FieldMembersNoLock} or
175 /// \alib{monomem::TSharedMonoVal;FieldMembersWithLock} is chosen.
177
178 /// The object that is placed in the allocator's first buffer.
179 /// Contains \p{T}, the allocator itself, and a reference counter.
181
182 //==============================================================================================
183 //=== The self-contained implementation of this type
184 //==============================================================================================
185 public:
186 /// Exposes the monotonic allocator used. Equals to <c>TMonoAllocator<TAllocator></c>.
188
189 /// Exposes the stored type specified with template parameter \p{T}.
190 using StoredType = T;
191
192 /// Exposes the lock type specified with template parameter \p{TLock}.
193 using LockType = TLock;
194
195 /// Constructs an initial buffer of given size and creates the mono allocator within.
196 ///
197 /// \attention
198 /// The instance of custom type \p{T} will \b not be constructed with
199 /// any constructor of this type.
200 /// Instead, an explicit call to #ConstructT has to be made after construction!
201 ///
202 /// @param allocator The (chained) allocator used to create the initial buffer
203 /// and passed to the monotonous allocator that is created.
204 /// @param initialBufferSizeInKB The initial size of memory buffers used with the monotonic
205 /// allocator in kB (1024 bytes)
206 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
207 /// with each next buffer allocation.
208 /// Should be set to \c 200, to double the size with each
209 /// allocation.
210 TSharedMonoVal( TAllocator& allocator,
211 size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent )
212 {
213 auto size= initialBufferSizeInKB * 1024;
214 void* mem= allocator.allocate( size, alignof(detail::Buffer) );
215 auto* buffer= new (mem) detail::Buffer( size );
216
217 members= reinterpret_cast<FieldMembers*>( buffer->allocate( sizeof( FieldMembers),
218 alignof(FieldMembers) ) );
219 ALIB_ASSERT_ERROR(members,"MONOMEM","Initial buffer size to small to hold shared value.")
220 new (members) FieldMembers( allocator, buffer, size, bufferGrowthInPercent );
221 }
222
223 /// Constructor missing the allocator instance.
224 /// To be used only with allocators that are default constructible
225 /// (like \alib{lang;HeapAllocator} is).
226 ///
227 /// \attention
228 /// The instance of custom type \p{T} will \b not be constructed with
229 /// any constructor of this type.
230 /// Instead, an explicit call to #ConstructT has to be made after construction!
231 ///
232 /// @param initialBufferSizeInKB The initial size of memory buffers used with the monotonic
233 /// allocator in kB (1024 bytes)
234 /// @param bufferGrowthInPercent Optional growth factor in percent, applied to the buffer size
235 /// with each next buffer allocation.
236 /// Should be set to \c 200, to double the size with each
237 /// allocation.
238 TSharedMonoVal( size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent )
239 {
240 auto size= initialBufferSizeInKB * 1024;
241 void* mem= TAllocator().allocate( size, alignof(detail::Buffer) );
242 auto* buffer= new (mem) detail::Buffer( size );
243 members= reinterpret_cast<FieldMembers*>( buffer->allocate( sizeof (FieldMembers),
244 alignof(FieldMembers) ) );
245 ALIB_ASSERT_ERROR(members,"MONOMEM","Initial buffer size to small to hold shared value.")
246 new (members) FieldMembers( buffer, size, bufferGrowthInPercent );
247 }
248
249 /// Destructor. If this is the last copy, the destructors of \p{T} and of the
250 /// \b MonoAllocator are invoked.
252 {
253 ALIB_STATIC_ASSERT( Locks_not_supported_when_module_ALibThreads_is_exlcuded,
254 ALIB_THREADS || ATMP_EQ(void, TLock),
255 "Template parameter TLock of class TSharedMonoVal must be <void> if module ALib Threads is "
256 "not included in the ALib Distribution." )
257
258 if (members && members->refCount.fetch_sub(1) == 1)
259 {
260 members->custom.Destruct(); // Destruct the contained object first,
261 lang::Destruct( members->allocator); // then the allocator.
262 }
263 }
264
265 /// Resets the monotonic allocator that this object is contained in to the snapshot created
266 /// right after construction.
267 /// The allocated memory buffers will remain allocated and reused. Before resetting,
268 /// the destructor of the custom object \p{T} is invoked, and after
269 /// the reset, in-place construction is performed.
270 ///
271 /// All shared instances remain valid (while, of-course, their content is likewise reset).
272 ///
273 /// It is up to the implementation of the derived class if this method should be exposed
274 /// or not. It is also up to the implementation of the derived class if the internal allocator
275 /// should be exposed for 3rd-party usage or not.
276 ///
277 /// @tparam TArgs The argument types used for re-constructing \p{T}.
278 /// @param args The arguments to re-construct the instance of \p{T}.
279 template<typename... TArgs>
280 void Reset( TArgs&&... args )
281 {
282 // Destruct custom object first
283 members->custom.Destruct();
284
285 // reset allocator to behind members
286 members->allocator.Reset( sizeof(FieldMembers), alignof(FieldMembers) );
287
288 // construct custom object again
289 new (&members->custom) T( std::forward<TArgs>(args)... );
290 }
291
292 /// Constructs the custom members.
293 /// This method <b>has to be called</b> right after this instance was created with a
294 /// non-nulled state.<br>
295 /// Usually, this is done in the constructor of a dedicated derived type.
296 ///
297 /// \note
298 /// The construction of the contained type is intentionally deferred to the (therefore
299 /// mandatory) call of this method.
300 /// The reason is that this way, the monotonic allocator is accessible with the method #
301 /// GetAllocator() and valid and thus can be used here.
302 /// @tparam TArgs The argument types used for constructing \p{T}.
303 /// @param args The arguments to construct the instance of \p{T}.
304 template<typename... TArgs>
305 void ConstructT( TArgs&&... args ) { members->custom.Construct(std::forward<TArgs>(args)... ); }
306
307 /// @return The size of the memory that is allocated for the \p{T} as well as for
308 /// the reference counter and the allocator member.
309 /// (To whom it may concern.)
310 static constexpr size_t SizeOfAllocation() { return sizeof(FieldMembers); }
311
312 /// @return The monotonic allocator that this object has created and embedded itself in.
313 /// It may be used for custom allocations and especially may be passed to the
314 /// constructor of \p{T} with the method #ConstructT for further use.
315 AllocatorType& GetAllocator() noexcept { dbgassert(); return members->allocator; }
316
317 /// Returns a non-constant reference to the stored object of type \p{T}.<br>
318 /// This can be used as an alias to <c>(**this)</c>.
319 /// @return A reference to \p{T}.
320 T& Self() noexcept { dbgassert(); return *members->custom; }
321
322 /// Returns a constant reference to the stored object of type \p{T}.<br>
323 /// This can be used as an alias to <c>(**this)</c>.
324 /// @return A constant reference to \p{T}.
325 const T& Self() const noexcept { dbgassert(); return *members->custom; }
326
327 /// Overloaded operator to access members of custom type \p{T}
328 /// @return A pointer to \p{T}.
329 T* operator->() noexcept { dbgassert(); return members->custom.Get(); }
330
331 /// Overloaded operator to access members of custom type \p{T}
332 /// @return A constant pointer to \p{T}.
333 const T* operator->() const noexcept { dbgassert(); return members->custom.Get(); }
334
335 /// Overloaded operator to access members of custom type \p{T}
336 /// @return A pointer to \p{T}.
337 T& operator*() noexcept { dbgassert(); return *members->custom; }
338
339 /// Overloaded operator to access members of custom type \p{T}
340 /// @return A constant pointer to \p{T}.
341 const T& operator*() const noexcept { dbgassert(); return *members->custom; }
342
343
344 //==============================================================================================
345 //=== The automatic pointer implementation of this type
346 //==============================================================================================
347 /// Default Constructor. Leaves this object \e nulled.
348 TSharedMonoVal() noexcept : members(nullptr) {}
349
350 /// Constructs an empty instance from \c std::nullptr.
351 /// This constructor is necessary to allow assignment of \c std::nullptr to values of this type,
352 /// which clears the automatic pointer.
353 /// \note As the common way to use this class is to derive an own type, this own type should
354 /// have this same constructor. Only then, the assignment of \c std::nullptr is possible.
355 TSharedMonoVal(std::nullptr_t) noexcept : members(nullptr) {}
356
357 /// Copy Constructor. Increases the reference counter of the shared pointer (in case given
358 /// \p{other} is not nulled).
359 /// @param other The object to copy.
360 TSharedMonoVal(const TSharedMonoVal& other) noexcept
361 : members(other.members) { if(members) ++(members->refCount); }
362
363
364 /// Move Constructor. Does not increase the reference counter, instead nulls the \p{other}.
365 /// @param other The object to copy.
367 : members(other.members) { other.members= nullptr; }
368
369 /// Copy Assignment Operator. Cares for self-assignment and assignment of a shared pointer with
370 /// the same content.
371 /// Otherwise, the reference counter of the current object is decreased, disposed if
372 /// necessary, and then the object in \p{other} is copied to this object.
373 /// @param other The object to copy into this one.
374 /// @return A reference to \c this.
376 {
377 // handle self assignment and assignment with same contents
378 if (this == &other || this->members == other.members)
379 return *this;
380
381 // decrement the old reference count and delete the old data if needed
382 if (members && members->refCount.fetch_sub(1) == 1)
383 {
384 members->custom.Destruct(); // Destruct the contained object first,
385 lang::Destruct( members->allocator); // then the allocator.
386 }
387
388 // copy the new data
389 if((members= other.members) != nullptr)
390 ++(members->refCount);
391
392 return *this;
393 }
394
395 /// Move Assignment Operator. Cares for self-assignment.
396 /// Otherwise, the object in \p{other} is copied to this.
397 /// @param other The object to move into this one.
398 /// @return A reference to \c this.
400 {
401 // handle self assignment
402 if (this == &other)
403 return *this;
404
405 // decrement the old reference count and delete the old data if needed
406 if (members && members != other.members && members->refCount.fetch_sub(1) == 1)
407 {
408 members->custom.Destruct(); // Destruct the contained object first,
409 lang::Destruct( members->allocator); // then the allocator.
410 }
411
412 // move members
413 members= other.members;
414 other.members= nullptr;
415 return *this;
416 }
417
418 /// Returns the number of shared usages.
419 /// In a multithreaded environment, the value returned is approximate.
420 /// @return \c The number of shared usages.
421 /// If this instance was default-constructed, moved, method #SetNulled was called,
422 /// or \c nullptr was assigned, then \c 0 is returned.
423 unsigned int UseCount() const noexcept
424 { return members != nullptr ? members->refCount.load() : 0; }
425
426 /// Returns \c true if the #UseCount is \c 1.
427 /// @return \c true if this instance is set but not shared.
428 bool Unique() const noexcept
429 { return members && members->refCount.load() == 1; }
430
431 /// Sets this object to \e nulled state, as if default constructed or \c nullptr was assigned.
432 /// If no shared copy exists, all data is destructed and memory is freed.<br>
433 /// As an alternative to this method, \c nullptr can be assigned.
434 void SetNulled() noexcept { lang::Destruct(*this); members= nullptr; }
435
436 /// Returns \c true if this is an empty instance.
437 /// @return \c true if #UseCount is \c 0, \c false otherwise.
438 bool IsNulled() const noexcept { return members == nullptr; }
439
440 /// Assignment of <c>nullptr</c>. Same as #SetNulled.
441 void operator=(std::nullptr_t) { lang::Destruct(*this); members= nullptr; }
442
443 /// Comparison with <c>nullptr</c>.
444 /// @return \c true if #UseCount is greater than \c 0.
445 bool operator==(std::nullptr_t) const noexcept { return members == nullptr; }
446
447 /// Comparison with <c>nullptr</c>.
448 /// @return \c false if #UseCount is greater than \c 0.
449 bool operator!=(std::nullptr_t) const noexcept { return members != nullptr; }
450
451 /// Returns a non-constant pointer to the stored object of type \p{T}.
452 /// @return A pointer to \p{T}.
453 T* Get() noexcept { dbgassert(); return members->custom.Get(); }
454
455 /// Returns a constant reference to the stored object of type \p{T}.
456 /// @return A constant reference to \p{T}.
457 const T* Get() const noexcept { dbgassert(); return members->custom.Get(); }
458
459 /// @return \c true if this instance is not \e nulled, \c false otherwise.
460 operator bool() const noexcept { return members != nullptr; }
461
462
463 //==============================================================================================
464 //=== The threads::XYZLock implementation of this type
465 //==============================================================================================
466 #if DOXYGEN
467 /// Returns the embedded \p{TLock}.
468 /// This method is available only if the template parameter \p{TLock} is not equal to
469 /// <c>void</c>.
470 /// @return A reference to the embedded lock.
471 TLock& GetLock() const noexcept;
472
473 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
474 /// This method participates in the overload resolution only if \p{TLock} provides an
475 /// equivalent method.
476 /// @param ci Caller information. Available only with debug-builds.
477 inline void Acquire( const CallerInfo& ci ) const noexcept;
478
479 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
480 /// This method participates in the overload resolution only if \p{TLock} provides an
481 /// equivalent method.
482 /// @param ci Caller information. Available only with debug-builds.
483 /// @return \c true if the lock was not acquired by a different thread and thus, this call
484 /// was successful. \c false otherwise.
485 [[nodiscard]]
486 bool TryAcquire( const CallerInfo& ci ) const noexcept;
487
488 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
489 /// This method participates in the overload resolution only if \p{TLock} provides an
490 /// equivalent method.
491 /// @param ci Caller information. Available only with debug-builds.
492 void Release(const CallerInfo& ci) const noexcept;
493
494 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
495 /// This method participates in the overload resolution only if \p{TLock} provides an
496 /// equivalent method.
497 /// @param ci Caller information. Available only with debug-builds.
498 void AcquireRecursive( const CallerInfo& ci ) const noexcept;
499
500 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
501 /// This method participates in the overload resolution only if \p{TLock} provides an
502 /// equivalent method.
503 /// @param ci Caller information. Available only with debug-builds.
504 void ReleaseRecursive(const CallerInfo& ci) const noexcept;
505
506 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
507 /// This method participates in the overload resolution only if \p{TLock} provides an
508 /// equivalent method.
509 /// @param ci Caller information. Available only with debug-builds.
510 void AcquireShared( const CallerInfo& ci ) const noexcept;
511
512 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
513 /// This method participates in the overload resolution only if \p{TLock} provides an
514 /// equivalent method.
515 /// @param ci Caller information. Available only with debug-builds.
516 /// @return \c true if the lock was not acquired by a different thread and thus, this call
517 /// was successful. \c false otherwise.
518 [[nodiscard]]
519 bool TryAcquireShared( const CallerInfo& ci ) const noexcept;
520
521 /// Calls this \b Acquire on the embedded instance specified with template parameter \p{TLock}.
522 /// This method participates in the overload resolution only if \p{TLock} provides an
523 /// equivalent method.
524 /// @param ci Caller information. Available only with debug-builds.
525 void ReleaseShared(const CallerInfo& ci) const noexcept;
526
527 /// Calls this \b TryAcquireTimed on the embedded instance specified with template parameter
528 /// \p{TLock}.
529 /// This method participates in the overload resolution only if \p{TLock} provides an
530 /// equivalent method.
531 /// @param waitDuration The point in time, when this method stops waiting.
532 /// @param ci Caller information. Available only with debug-builds.
533 /// @return \c true if the lock was not acquired by a different thread and thus, this call
534 /// was successful. \c false otherwise.
535 [[nodiscard]]
536 bool TryAcquireTimed( const Ticks::Duration& waitDuration, const CallerInfo& ci )
537 const noexcept;
538
539 /// Calls this \b TryAcquireTimed on the embedded instance specified with template parameter
540 /// \p{TLock}.
541 /// This method participates in the overload resolution only if \p{TLock} provides an
542 /// equivalent method.
543 /// @param waitDuration The point in time, when this method stops waiting.
544 /// @param ci Caller information. Available only with debug-builds.
545 /// @return \c true if the lock was not acquired by a different thread and thus, this call
546 /// was successful. \c false otherwise.
547 [[nodiscard]]
548 bool TryAcquireTimed( const Ticks::Duration::TDuration& waitDuration,
549 const CallerInfo& ci ) const noexcept;
550
551 /// Calls this \b TryAcquireTimed on the embedded instance specified with template parameter
552 /// \p{TLock}.
553 /// This method participates in the overload resolution only if \p{TLock} provides an
554 /// equivalent method.
555 /// @param pointInTime The point in time, when this method stops waiting.
556 /// @param ci Caller information. Available only with debug-builds.
557 /// @return \c true if the lock was not acquired by a different thread and thus, this call
558 /// was successful. \c false otherwise.
559 bool TryAcquireTimed( const Ticks& pointInTime, const CallerInfo& ci ) const noexcept;
560
561 /// Calls this \b TryAcquireTimed on the embedded instance specified with template parameter
562 /// \p{TLock}.
563 /// This method participates in the overload resolution only if \p{TLock} provides an
564 /// equivalent method.
565 /// @param pointInTime The point in time, when this method stops waiting.
566 /// @param ci Caller information. Available only with debug-builds.
567 /// @return \c true if the lock was not acquired by a different thread and thus, this call
568 /// was successful. \c false otherwise.
569 [[nodiscard]]
570 bool TryAcquireTimed( const Ticks::TTimePoint& pointInTime,
571 const CallerInfo& ci ) const noexcept;
572
573 /// Calls this \b TryAcquireSharedTimed on the embedded instance specified with template
574 /// parameter \p{TLock}.
575 /// This method participates in the overload resolution only if \p{TLock} provides an
576 /// equivalent method.
577 /// @param waitDuration The point in time, when this method stops waiting.
578 /// @param ci Caller information. Available only with debug-builds.
579 /// @return \c true if the lock was not acquired by a different thread and thus, this call
580 /// was successful. \c false otherwise.
581 [[nodiscard]]
582 bool TryAcquireSharedTimed( const Ticks::Duration& waitDuration,
583 const CallerInfo& ci ) const noexcept;
584
585 /// Calls this \b TryAcquireSharedTimed on the embedded instance specified with template
586 /// parameter \p{TLock}.
587 /// This method participates in the overload resolution only if \p{TLock} provides an
588 /// equivalent method.
589 /// @param waitDuration The point in time, when this method stops waiting.
590 /// @param ci Caller information. Available only with debug-builds.
591 /// @return \c true if the lock was not acquired by a different thread and thus, this call
592 /// was successful. \c false otherwise.
593 [[nodiscard]]
594 bool TryAcquireSharedTimed( const Ticks::Duration::TDuration& waitDuration,
595 const CallerInfo& ci ) const noexcept;
596
597 /// Calls this \b TryAcquireSharedTimed on the embedded instance specified with template
598 /// parameter \p{TLock}.
599 /// This method participates in the overload resolution only if \p{TLock} provides an
600 /// equivalent method.
601 /// @param pointInTime The point in time, when this method stops waiting.
602 /// @param ci Caller information. Available only with debug-builds.
603 /// @return \c true if the lock was not acquired by a different thread and thus, this call
604 /// was successful. \c false otherwise.
605 [[nodiscard]]
606 bool TryAcquireSharedTimed( const Ticks& pointInTime,
607 const CallerInfo& ci ) const noexcept;
608
609 /// Calls this \b TryAcquireSharedTimed on the embedded instance specified with template
610 /// parameter \p{TLock}.
611 /// This method participates in the overload resolution only if \p{TLock} provides an
612 /// equivalent method.
613 /// @param pointInTime The point in time, when this method stops waiting.
614 /// @param ci Caller information. Available only with debug-builds.
615 /// @return \c true if the lock was not acquired by a different thread and thus, this call
616 /// was successful. \c false otherwise.
617 [[nodiscard]]
618 bool TryAcquireSharedTimed( const Ticks::TTimePoint& pointInTime,
619 const CallerInfo& ci ) const noexcept;
620
621
622 #elif ALIB_THREADS
623 #define ATPASS ALIB_STATIC_ASSERT(ForbiddenTemplateParameterGiven, ATMP_EQ(TIf,TLock), "Template parameter of this method is deduced by the compiler and must not be given!");
624 template<typename TIf= TLock, ATMP_T_IF( int, !ATMP_EQ(TIf,void ))= 0>
625 TIf& GetLock() const noexcept { ATPASS dbgassert(); return members->lock; }
626
627 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, Acquire,ALIB_DBG(CallerInfo())) )
628 Acquire(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.Acquire (ALIB_DBG(ci)); }
629
630 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquire,ALIB_DBG(CallerInfo())) )
631 TryAcquire(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquire (ALIB_DBG(ci)); }
632
633 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, Release,ALIB_DBG(CallerInfo())) )
634 Release(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.Release (ALIB_DBG(ci)); }
635
636 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, AcquireRecursive,ALIB_DBG(CallerInfo())) )
637 AcquireRecursive(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.AcquireRecursive (ALIB_DBG(ci)); }
638
639 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, ReleaseRecursive,ALIB_DBG(CallerInfo())) )
640 ReleaseRecursive(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.ReleaseRecursive (ALIB_DBG(ci)); }
641
642 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, AcquireShared,ALIB_DBG(CallerInfo())) )
643 AcquireShared(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.AcquireShared (ALIB_DBG(ci)); }
644
645 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireShared,ALIB_DBG(CallerInfo())) )
646 TryAcquireShared(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireShared (ALIB_DBG(ci)); }
647
648 template<typename TIf= TLock> ATMP_VOID_IF( ATMP_HAS_METHOD(TIf, ReleaseShared,ALIB_DBG(CallerInfo())) )
649 ReleaseShared(ALIB_DBG(const CallerInfo& ci)) const noexcept { ATPASS dbgassert(); members->lock.ReleaseShared (ALIB_DBG(ci)); }
650
651 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireTimed, Ticks::Duration() ALIB_DBG(,CallerInfo())) )
652 TryAcquireTimed( const Ticks::Duration& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireTimed( t ALIB_DBG(,ci)); }
653
654 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireTimed, Ticks::Duration().Export() ALIB_DBG(,CallerInfo())) )
655 TryAcquireTimed( const Ticks::Duration::TDuration t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireTimed( t ALIB_DBG(,ci)); }
656
657 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireTimed, Ticks() ALIB_DBG(,CallerInfo())) )
658 TryAcquireTimed( const Ticks& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireTimed( t ALIB_DBG(,ci)); }
659
660 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireTimed, Ticks().Export() ALIB_DBG(,CallerInfo())) )
661 TryAcquireTimed( const Ticks::TTimePoint& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireTimed( t ALIB_DBG(,ci)); }
662
663 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireSharedTimed, Ticks::Duration() ALIB_DBG(,CallerInfo())) )
664 TryAcquireSharedTimed( const Ticks::Duration& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireSharedTimed( t ALIB_DBG(,ci)); }
665
666 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireSharedTimed, Ticks::Duration().Export() ALIB_DBG(,CallerInfo())) )
667 TryAcquireSharedTimed( const Ticks::Duration::TDuration t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireSharedTimed( t ALIB_DBG(,ci)); }
668
669 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireSharedTimed, Ticks() ALIB_DBG(,CallerInfo())) )
670 TryAcquireSharedTimed( const Ticks& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireSharedTimed( t ALIB_DBG(,ci)); }
671
672 template<typename TIf= TLock> ATMP_BOOL_IF( ATMP_HAS_METHOD(TIf, TryAcquireSharedTimed, Ticks().Export() ALIB_DBG(,CallerInfo())) )
673 TryAcquireSharedTimed( const Ticks::TTimePoint& t ALIB_DBG(,const CallerInfo& ci) ) const noexcept { ATPASS dbgassert(); return members->lock.TryAcquireSharedTimed( t ALIB_DBG(,ci)); }
674
675 #undef ATPASS
676 #endif
677
678};
679
680} // namespace alib[::monomem]
681
682
683DOX_MARKER([DOX_MANUAL_ALIASES_SHAREDMONOVAL])
684/// Type alias in namespace \b alib.
685template<typename T, typename TAllocator= lang::HeapAllocator, typename TLock= void>
687DOX_MARKER([DOX_MANUAL_ALIASES_SHAREDMONOVAL])
688
689} // namespace [alib]
690
691#endif // HPP_ALIB_MONOMEM_SHARED_MONO_PTR
692
bool TryAcquireTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci) const noexcept
AllocatorType & GetAllocator() noexcept
bool TryAcquireShared(const CallerInfo &ci) const noexcept
void ReleaseRecursive(const CallerInfo &ci) const noexcept
TSharedMonoVal & operator=(const TSharedMonoVal &other) noexcept
TSharedMonoVal & operator=(TSharedMonoVal &&other) noexcept
void Acquire(const CallerInfo &ci) const noexcept
TLock & GetLock() const noexcept
bool Unique() const noexcept
TSharedMonoVal(size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent)
static constexpr size_t SizeOfAllocation()
void AcquireShared(const CallerInfo &ci) const noexcept
T StoredType
Exposes the stored type specified with template parameter T.
void operator=(std::nullptr_t)
Assignment of nullptr. Same as SetNulled.
const T & operator*() const noexcept
void Release(const CallerInfo &ci) const noexcept
bool operator==(std::nullptr_t) const noexcept
bool TryAcquire(const CallerInfo &ci) const noexcept
const T * operator->() const noexcept
bool IsNulled() const noexcept
TLock LockType
Exposes the lock type specified with template parameter TLock.
TSharedMonoVal(TSharedMonoVal &&other) noexcept
unsigned int UseCount() const noexcept
TSharedMonoVal(TAllocator &allocator, size_t initialBufferSizeInKB, unsigned int bufferGrowthInPercent)
TSharedMonoVal(std::nullptr_t) noexcept
bool operator!=(std::nullptr_t) const noexcept
ATMP_IF_T_F(ATMP_EQ(void, TLock), FieldMembersNoLock, FieldMembersWithLock) FieldMembers
TSharedMonoVal(const TSharedMonoVal &other) noexcept
void ConstructT(TArgs &&... args)
void Reset(TArgs &&... args)
const T * Get() const noexcept
TSharedMonoVal() noexcept
Default Constructor. Leaves this object nulled.
void ReleaseShared(const CallerInfo &ci) const noexcept
void AcquireRecursive(const CallerInfo &ci) const noexcept
bool TryAcquireSharedTimed(const Ticks::Duration &waitDuration, const CallerInfo &ci) const noexcept
const T & Self() const noexcept
#define ATMP_IF_T_F( Cond, T, F)
Definition tmp.hpp:50
#define ALIB_ASSERT_MODULE(modulename)
Definition alib.hpp:223
#define ATMP_BOOL_IF(Cond)
Definition tmp.hpp:48
#define ATMP_IF(Cond)
Definition tmp.hpp:56
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:47
#define ALIB_STATIC_ASSERT(CondVariable, Cond, Message)
Definition alib.hpp:990
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:27
#define ATMP_HAS_METHOD(T, Method,...)
Definition tmp.hpp:51
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:1271
#define ALIB_DBG(...)
Definition alib.hpp:390
#define ALIB_THREADS
Definition alib.hpp:213
static ALIB_FORCE_INLINE void Destruct(T &object)
Definition alib.cpp:69
time::Ticks Ticks
Type alias in namespace alib.
Definition ticks.hpp:115
lang::CallerInfo CallerInfo
Type alias in namespace alib.
Definition alib.hpp:1143
FieldMembersWithLock(TAllocator &pAllocator, detail::Buffer *firstBuffer, size_t initialBufferSize, unsigned int bufferGrowthInPercent)
std::atomic< unsigned int > refCount
The reference counter used to implement the std::shared_ptr behavior.
lang::Placeholder< T > custom
The space for the custom member. The instance will be constructed using placement-new.
FieldMembersWithLock(detail::Buffer *firstBuffer, size_t initialBufferSize, unsigned int bufferGrowthInPercent)
TMonoAllocator< TAllocator > allocator
The allocator that this class is contained in.