ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
box.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_boxing of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under #"mainpage_license".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace boxing {
9
10//==================================================================================================
11/// This is the central class of \alib_boxing_nl . By making extensive use of template programming
12/// and keyword \c requires on overloaded constructors, an object of this class can be created by
13/// passing instances of (almost) any C++ type to the constructor.
14/// The passed value will be "boxed" within the instance of this class.
15///
16/// Then, the instances of this class support type checking, value extraction ("unboxing") and the
17/// invocation of "virtual methods". All features are customizable via
18/// #"alib_manual_appendix_tca;type traits", and thus the built-in defaulted behavior for a
19/// custom type can be changed.
20///
21/// A thorough introduction to and documentation of all aspects of \alib_boxing_nl is given
22/// with Programmer's Manual \alib_boxing.
23///
24/// ## Functors In Namespace std ##
25/// Functors <c>std::hash</c>, <c>std::equal_to,</c> and <c>std::less</c> are specialized for
26/// this type with the inclusion of the header-file #"F;ALib.Boxing.StdFunctors.H".
27//==================================================================================================
28class Box
29{
30 protected:
31 //################################################################################################
32 // protected fields and methods
33 //################################################################################################
34
35 /// The singleton of a class derived from class \b %VTable which defines our type and
36 /// behavior.
38
39 /// The data that we encapsulate.
41
42
43 //################################################################################################
44 // Two local macros that check whether T is a valid type to box, respectively unbox.
45 // For this, various different cases are (redundantly) checked to produce compiler
46 // errors that provide all necessary information about why the operation cannot be
47 // performed.
48 // Note: Using an empty templated method for this, produced the static assertion only after
49 // other compiler errors. Therefore, a macro is used.
50 //################################################################################################
51
52#if !DOXYGEN
53 #define ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(TBoxable, valueBoxing) \
54 using TVal = ALIB_TVALUE(TBoxable); \
55 using TPtr = TVal*; \
56 constexpr bool isVolatile = std::is_volatile_v<std::remove_pointer_t<TBoxable>>; \
57 constexpr bool isPointer = std::is_pointer<TBoxable>::value; \
58 constexpr bool isValue = !isPointer; \
59 constexpr bool valIsString = IsStringType<TVal>; \
60 constexpr bool isCustomizedTV= IsCustomized<TVal>; \
61 constexpr bool isCustomizedTP= IsCustomized<TPtr>; \
62 constexpr bool isBlockedTV = std::same_as<NotBoxableTag, \
63 typename BoxTraits<TVal>::Mapping>; \
64 constexpr bool isBlockedTP = std::same_as<NotBoxableTag, \
65 typename BoxTraits<TPtr>::Mapping>; \
66 \
67 ALIB_STATIC_DENY( GeneralBoxingRule1, !valueBoxing && isVolatile, \
68 "Types boxed as pointers cannot be boxed if volatile." ); \
69 \
70 ALIB_STATIC_DENY( GeneralBoxingRule4, isPointer && valIsString, \
71 "String types must not be given as pointers." ); \
72 \
73 ALIB_STATIC_DENY( CustomBoxingRule3, isBlockedTV && isValue, \
74 "Customized boxing forbids boxing this value type: " \
75 "'BoxTraits<T>::Type == NotBoxable'!" ); \
76 \
77 ALIB_STATIC_DENY( CustomBoxingRule4, isBlockedTP && isPointer, \
78 "Customized boxing forbids boxing this pointer type: " \
79 "'BoxTraits<T*>::Type == NotBoxable'!" ); \
80 \
81 ALIB_STATIC_DENY( CustomBoxingRule5, isBlockedTV && !isCustomizedTP && isPointer, \
82 "Customized boxing forbids boxing value type T (BoxTraits<T>::Type == NotBoxable), while " \
83 "no customization for this pointer type T* was given." ); \
84 \
85 ALIB_STATIC_DENY( CustomBoxingRule6, isBlockedTP && !isCustomizedTV && isValue, \
86 "Customized boxing forbids boxing pointer type T* " \
87 "(BoxTraits<T*>::Type == NotBoxable), while no customization for this value type T was " \
88 "given. " ); \
89 \
90 // check IsType/Unbox
91 #define ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TUnboxable) \
92 using TVal = ALIB_TVALUE(TUnboxable); \
93 using TPtr = TVal*; \
94 constexpr bool isConst = std::is_const_v <std::remove_pointer_t<TUnboxable>>; \
95 constexpr bool isVolatile = std::is_volatile_v<std::remove_pointer_t<TUnboxable>>; \
96 constexpr bool isPointer = std::is_pointer<TUnboxable>::value; \
97 constexpr bool isValue = !isPointer; \
98 constexpr bool valuesFit = sizeof(std::conditional_t<std::same_as<void,TVal>,void*,TVal>)\
99 <= sizeof(Placeholder); \
100 constexpr bool isCopyConstr = std::is_copy_constructible<TVal>::value; \
101 constexpr bool isTrivDest = std::is_trivially_destructible<TVal>::value; \
102 constexpr bool isCustomizedTV= IsCustomized<TVal>; \
103 constexpr bool isCustomizedTP= IsCustomized<TPtr>; \
104 constexpr bool isDefault = !(isCustomizedTV || isCustomizedTP); \
105 constexpr bool isBlockedTV = std::same_as<NotBoxableTag, \
106 typename BoxTraits<TVal>::Mapping>; \
107 constexpr bool isBlockedTP = std::same_as<NotBoxableTag, \
108 typename BoxTraits<TPtr>::Mapping>; \
109 constexpr bool isLockedTV = IsLocked<TVal>; \
110 constexpr bool isLockedTP = IsLocked<TPtr>; \
111 \
112 /* Redundant type qualifiers */ \
113 ALIB_STATIC_DENY( GeneralBoxingRule2, isConst, \
114 "Type qualifier 'const' not allowed with template type TUnboxable. Types boxed as values" \
115 " are always unboxed mutable, types boxed as pointers are always unboxed constant." ); \
116 \
117 ALIB_STATIC_DENY( GeneralBoxingRule3, isVolatile, \
118 "Type qualifier 'volatile' not allowed with template type TUnboxable" ); \
119 \
120 /* Default boxing */ \
121 ALIB_STATIC_DENY( DefaultBoxingRule1, isDefault && isValue && !valuesFit, \
122 "This type cannot be unboxed by value: " \
123 "By default, values that do not fit into boxes are boxed as pointers." ); \
124 \
125 ALIB_STATIC_DENY( DefaultBoxingRule2, \
126 isDefault && isValue && (!isCopyConstr || !isTrivDest), \
127 "This type cannot be unboxed by value: " \
128 "By default, types that are not copy-constructible or not trivially destructible, " \
129 "are boxed as pointers." ); \
130 \
131 ALIB_STATIC_DENY( DefaultBoxingRule3, \
132 isDefault && isPointer && valuesFit && isCopyConstr && isTrivDest, \
133 "This type cannot be unboxed as pointer: Default boxing of types that fit " \
134 "into boxes and are copy-constructible and trivially destructible, " \
135 "is performed by value." ); \
136 \
137 \
138 /* Custom boxing */ \
139 ALIB_STATIC_DENY( CustomBoxingRule1, isCustomizedTV && !isCustomizedTP && isPointer, \
140 "This pointer type T* cannot be unboxed, because custom boxing is defined for " \
141 "value type T, while no custom boxing is defined for pointer type T*." ); \
142 \
143 ALIB_STATIC_DENY( CustomBoxingRule2, !isCustomizedTV && isCustomizedTP && isValue, \
144 "This value type T cannot be unboxed, because custom boxing is defined for " \
145 "pointer type T*, while no custom boxing is defined for value type T." ); \
146 \
147 \
148 /* Boxing blocked */ \
149 ALIB_STATIC_DENY( CustomBoxingRule3, isBlockedTV && isValue, \
150 "Customized boxing forbids unboxing (and even boxing) this value type: " \
151 "'BoxTraits<T>::Type == NotBoxable'!" ); \
152 \
153 ALIB_STATIC_DENY( CustomBoxingRule4, isBlockedTP && isPointer, \
154 "Customized boxing forbids unboxing (and even boxing) this pointer type: " \
155 "'BoxTraits<T*>::Type == NotBoxable'!" ); \
156 \
157 ALIB_STATIC_DENY( CustomBoxingRule5, isBlockedTV && !isCustomizedTP && isPointer, \
158 "Customized boxing forbids unboxing (and even boxing) value type T " \
159 "(BoxTraits<T>::Type == NotBoxable), while no customization for this pointer type T* " \
160 "was given." ); \
161 \
162 ALIB_STATIC_DENY( CustomBoxingRule6, isBlockedTP && !isCustomizedTV && isValue, \
163 "Customized boxing forbids unboxing (and even boxing) pointer type T* " \
164 "(BoxTraits<T*>::Type == NotBoxable), while no customization for this value type T was" \
165 "given." ); \
166 \
167 /* Unboxing locked */ \
168 ALIB_STATIC_DENY( CustomBoxingRule7, isLockedTV && isValue, \
169 "Customized boxing forbids unboxing this value type: " \
170 "'BoxTraits<T>::Read' returns a different type." ); \
171 \
172 ALIB_STATIC_DENY( CustomBoxingRule8, isLockedTP && isPointer, \
173 "Customized boxing forbids unboxing this pointer type: " \
174 "'BoxTraits<T*>::Read' returns a different type." ); \
175 \
176 ALIB_STATIC_DENY( CustomBoxingRule9, isLockedTV && !isCustomizedTP && isPointer, \
177 "Customized boxing forbids unboxing value type T " \
178 "('BoxTraits<T>::Read' returns a different type), while no customization for this pointer " \
179 "type T* was given." ); \
180 \
181 ALIB_STATIC_DENY( CustomBoxingRule10, isLockedTP && !isCustomizedTV && isValue, \
182 "Customized boxing forbids unboxing pointer type T* " \
183 "('BoxTraits<T*>::Read' returns a different type), while no customization for this value " \
184 "type T was given." ); \
185
186#endif // !DOXYGEN
187
188 /// Shortcut inline method to retrieve the vtable singleton for the template type.
189 /// In debug-compilations, the received \e vtable is checked for being registered.
190 ///
191 /// @tparam TBoxable The source type to receive the vtable for.
192 /// @return The vtable singleton.
193 template<typename TBoxable>
194 static constexpr detail::VTable* getVTable() {
195 using TCV= std::remove_cv_t<TBoxable>;
196 // not customized?
197 if constexpr (std::same_as<typename BoxTraits<TCV>::Mapping, DefaultBoxingTag>)
199
200 // customized
203 }
204
205 /// Helper method that writes data into the placeholder.
206 /// @tparam T The source type to receive the data for.
207 /// @param src The source object to box.
208 template<typename T>
209 constexpr void initPH(const T& src) noexcept
210 { BoxTraits<std::remove_cv_t<T>>::Write( data, const_cast<T const &>( src ) ); }
211
212
213 //################################################################################################
214 // Constructors
215 //################################################################################################
216 public:
217
218 //TODO(251125 12:06): search all "reinterpret_cast" and check if this is from void* and thus replaceable with
219 // static cast.
220 // The following TypeCode sample is NOT a valid sample and cannot be changed.
221 // The reinterpret_cast has to be done in the interface when exporting/importing.
222 // See my CLion AI chat "KEEP (is a todo)!: Using static_cast with void pointers in C++")
223 /// The type of type codes received with #"ExportType".
225
226 /// Default constructor.<br>
227 /// After creation with this constructor, a call to #".IsType" returns true.
228 /// To reset an instance previously used, assign keyword \c nullptr.
229 Box() noexcept
230 : vtable( nullptr ) {}
231
232 /// Constructor accepting previously exported values.
233 /// @param typeCode The type code this box will be set to.
234 /// @param placeholder The data this box will be set to.
235 Box( TypeCode typeCode, const Placeholder& placeholder ) noexcept
236 : vtable(reinterpret_cast<detail::VTable*>(typeCode))
237 , data (placeholder) {}
238
239 #if DOXYGEN
240 /// Constructor to fetch any type of object.<br>
241 /// Internally, this constructor is implemented using a set of different constructors
242 /// which are selected by the compiler using keyword \c requires.
243 ///
244 /// Types derived from class \b %Box itself are boxed by copying the internal values
245 /// of the box. This means that boxing objects of derived types is similar to
246 /// "downcasting" the object to class \b %Box.
247 ///
248 /// @tparam TBoxable Any C++ type to be boxed.
249 /// @param src The src value or pointer type \c T.
250 template <typename TBoxable>
251 inline constexpr Box(const TBoxable& src ) noexcept;
252 #else
253 //######################################### Special types ########################################
254
255 // Keyword 'nullptr'
256 constexpr Box(const std::nullptr_t& ) noexcept : vtable(nullptr) {}
257
258 // C++ arrays
259 template<typename T>
260 requires std::is_array_v<T>
261 constexpr Box( T& src ) noexcept {
262 using TElem= std::remove_cv_t<std::remove_pointer_t<std::decay_t<T>>>;
264
265 constexpr integer length= characters::IsCharacter<TElem> ? std::extent<T>::value - 1
266 : std::extent<T>::value;
267 data = Placeholder( &src, length );
268 }
269
270 // Derived Box value types (like copy constructor but fetches derived types)
271 template<typename T>
272 requires ( std::is_base_of<Box, std::remove_cv_t<T>>::value )
273 constexpr Box( const T& src ) noexcept
274 : vtable( src.vtable )
275 , data ( src.data ) {}
276
277 //##################################### Boxing with BoxTraits ####################################
278
279 // 0) Strings
280 template<typename T>
281 requires ( IsStringType<std::remove_cv_t<T>> )
282 constexpr Box( const T& src ) noexcept {
283
284 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
285 if constexpr ( characters::ArrayTraits <T, nchar>::Access == characters::Policy::Implicit ) {
287 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, nchar>::Buffer( src ),
288 characters::ArrayTraits<std::remove_cv_t<T>, nchar>::Length( src ) );
289 }
292 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, wchar>::Buffer( src ),
293 characters::ArrayTraits<std::remove_cv_t<T>, wchar>::Length( src ) );
294 }
297 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, xchar>::Buffer( src ),
298 characters::ArrayTraits<std::remove_cv_t<T>, xchar>::Length( src ) );
299 }
300
301 }
302
303 // 1) Value remains value
304 template<typename T>
305 requires ( !std::is_pointer_v<T>
306 && !IsStringType<std::remove_cv_t<T>>
307 && ( IsCustomized<std::decay_t<T> >
308 || ( !IsCustomized<std::decay_t<T>*> && IsStdPH<T> ) )
309 )
310 constexpr Box( const T& src ) noexcept {
311 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
312 vtable= getVTable<T>();
313 initPH( src );
314 }
315
316 // 2) Value converted to pointer
317 template<typename T>
318 requires( !std::is_pointer_v<T>
319 && !IsStringType<std::remove_cv_t<T>>
320 && !std::is_array_v<T>
321 && !std::is_base_of_v<Box, T>
322 && !IsCustomized<std::decay_t<T> >
323 && ( IsCustomized<std::remove_cv_t<T> >
324 || ( !IsCustomized<std::decay_t<T>*> && !IsStdPH<T> )
325 || ( IsCustomized<std::decay_t<T>*> )
326 )
327 )
328 constexpr Box( const T& src ) noexcept {
329 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
330 vtable= getVTable<std::remove_cv_t<T>*>();
331 initPH( &src );
332 }
333
334 // 3) Pointer remains pointer
335 template<typename T>
336 requires ( std::is_pointer_v<T>
337 && !std::is_base_of_v<Box, ALIB_TVALUE(T)>
338 &&
339 ( IsCustomized<std::remove_cv_t<T>>
340 || !( IsCustomized<ALIB_TVALUE(T)> || IsStdPH<T> )
341 ))
342 constexpr Box( const T& src ) noexcept {
343 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, false)
344 vtable= getVTable<T>();
345 initPH( src );
346 }
347
348 // 4) Pointer dereferenced to value
349 template<typename T>
350 requires ( std::is_pointer_v<T>
351 && !std::is_base_of_v<Box, ALIB_TVALUE(T)>
352 && !IsStringType<std::remove_cv_t<T>>
353 && !
354 ( IsCustomized<std::remove_cv_t<T>>
355 || !( IsCustomized<ALIB_TVALUE(T)> || IsStdPH<T> )
356 )
357 )
358 constexpr Box( const T& src ) noexcept {
359 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, false)
360 using TV= ALIB_TVALUE(T);
361 vtable= getVTable<TV>();
362 if ( src ) initPH( *src );
363 else data = Placeholder( sizeof(TV) <= sizeof(integer)
364 ? Placeholder( 0 )
365 : Placeholder( integer(0), integer(0) ) );
366 }
367
368
369 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING
370 #undef ALIB_TM_IS_DEFAULT_BOXING
371
372 #endif // DOXYGEN
373
374 //################################################################################################
375 // Interface
376 //################################################################################################
377 #if ALIB_DEBUG
378 /// Returns the \e vtable of this instance that is associated with the currently boxed
379 /// type.<br>
380 /// Available only with debug-builds.
381 ///
382 /// \see
383 /// Manual chapter #"alib_boxing_more_debug" of the Programmer's Manual.
384 ///
385 /// @return The \e vtable of this instance.
386 const detail::VTable* DbgGetVTable() const { return vtable; }
387
388 #endif
389
390 #if DOXYGEN
391 /// Checks if this box stores a value of type \p{TBoxable}.
392 ///
393 /// If template parameter \p{TBoxable} it is not unboxable, a compile-time assertion
394 /// is given, with specific guidance why the type must not be unboxed and for that
395 /// reason must not even be tested for.
396 ///
397 /// Special type \c void may be given for testing if this box does contain a value at all.
398 /// A box does not contain a value, after
399 /// - default construction,
400 /// - construction with keyword \c nullptr, or
401 /// - assignment of keyword \c nullptr.
402 ///
403 /// For more information on the "void state" of boxes, see manual chapter
404 /// #"alib_boxing_more_void".
405 ///
406 ///
407 /// @tparam TBoxable The boxable type guessed.
408 /// @return \c true if this box stores a value that is convertible to type \p{TBoxable},
409 /// \c false otherwise.
410 template<typename TBoxable>
411 bool IsType() const;
412
413 #else
414 template<typename TBoxable>
416 bool IsType() const {
419
422
425 }
426
427 template<typename TBoxable>
428 requires ( !std::same_as<TBoxable, void>
430 bool IsType() const {
431 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TBoxable)
432 return vtable == getVTable<TBoxable>();
433 }
434
435 template<typename TBoxable>
436 requires std::same_as<TBoxable, void>
437 bool IsType() const { return vtable == nullptr; }
438 #endif
439
440 #if !ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS || DOXYGEN
441 /// Tests if this box contains a signed integral type (one of the C++ fundamental
442 /// types of different sizes).
443 ///
444 /// With compilation that disables
445 /// #"ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS", this method will be inlined and
446 /// simply returns <c>IsType<integer>()</c>.<br>
447 /// Otherwise this method will not be inlined and tests for the five different
448 /// integer sizes (\c int8_t, \c int16_t, \c int32_t, \c int64_t, and #"lang::intGap_t").
449 ///
450 /// @return \c true if this box contains a signed integral type, \c false otherwise.
451 bool IsSignedIntegral() const { return IsType<integer >(); }
452
453 /// Tests if this box contains an unsigned integral type (one of the C++ fundamental
454 /// type of different sizes).
455 ///
456 /// With default library compilation that disables
457 /// #"ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS", this method will be inlined and
458 /// simply returns <c>IsType<uinteger>()</c>.<br>
459 /// Otherwise this method will not be inlined and tests for the five different
460 /// integer sizes (\c uint8_t, \c uint16_t, \c uint32_t, \c uint64_t, and
461 /// #"lang::uintGap_t").
462 ///
463 /// @return \c true if this box contains an unsigned integral type, \c false otherwise.
464 bool IsUnsignedIntegral() const { return IsType<uinteger>(); }
465
466 /// Unboxes a signed integral.
467 ///
468 /// With default library compilation that disables
469 /// #"ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS", this method will be inlined and
470 /// simply returns <c>Unbox<integer>()</c>.<br>
471 /// Otherwise, this method will not be inlined and tests for the five different
472 /// integer sizes (1, 2, 4, and 8 bytes size and the #"alib::intGap_t;2") before
473 /// unboxing.
474 ///
475 /// @return The boxed signed integral value.
477
478 /// Unboxes an unsigned integral.
479 ///
480 /// With default library compilation that disables
481 /// #"ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS", this method will be inlined and
482 /// simply returns <c>Unbox<uinteger>()</c>.<br>
483 /// Otherwise this method will not be inlined and tests for the five different
484 /// integer sizes (1, 2, 4, and 8 bytes size and the #"alib::uintGap_t;2") before
485 /// unboxing.
486 ///
487 /// @return The boxed unsigned integral value.
489 #else
490 ALIB_DLL bool IsSignedIntegral() const;
491 ALIB_DLL bool IsUnsignedIntegral() const;
494 #endif
495
496
497 #if !ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS || DOXYGEN
498 /// Tests if this box contains one of types \c char, \c wchar_t, \c char8_t, \c char16_t,
499 /// or \c char32_t.
500 ///
501 /// With default library compilation that disables symbol
502 /// #"ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS", this method will be inlined and
503 /// simply returns <c>IsType<wchar>()</c>.<br>
504 /// Otherwise, this method will not be inlined and tests for all five different
505 /// character types.
506 ///
507 /// @return \c true if this box contains a character type, \c false otherwise.
508 bool IsCharacter() const { return IsType<wchar>(); }
509
510 /// Unboxes one of the types \c char, \c wchar_t, \c char8_t, \c char16_t, or \c char32_t
511 /// and converts it to #"characters::wchar".
512 ///
513 /// With default library compilation that disables
514 /// #"ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS", this method will be inlined and
515 /// simply returns <c>Unbox<wchar>()</c>.<br>
516 /// Otherwise, this method will not be inlined and tests for the five different
517 /// character types before unboxing.
518 ///
519 /// @return The stored character.
520 wchar UnboxCharacter() const { return Unbox<wchar>(); }
521
522 #else
523 ALIB_DLL bool IsCharacter() const;
525 #endif
526
527
528 /// Tests if this box contains a floating point type.
529 ///
530 /// \note
531 /// If #"ALIB_FEAT_BOXING_BIJECTIVE_FLOATS" is not set, this method will
532 /// test against \c double and <c>long double</c>. If it is set, in addition
533 /// type \c float is tested.
534 ///
535 /// @return \c true if this box contains a floating point type, \c false otherwise.
536 bool IsFloatingPoint() const;
537
538 /// Unboxes a floating point value as \c double.
539 ///
540 /// \note
541 /// If #"ALIB_FEAT_BOXING_BIJECTIVE_FLOATS" is not set, this method will
542 /// test against \c double and <c>long double</c> and convert the latter.
543 /// If it is set, in addition type \c float is tested.
544 ///
545 /// @return \c true if this box contains a floating point type, \c false otherwise.
547 double UnboxFloatingPoint() const;
548
549 /// Returns \c true if this box represents an array of objects.
550 /// In this case, method #"UnboxLength" (usually) will return the length of the array and
551 /// #"UnboxElement" may be used to access elements of the array.
552 ///
553 /// @return \c true if this box represents an array, \c false otherwise.
554 bool IsArray() const { return vtable && vtable->IsArray(); }
555
556 /// Returns \c true if this objects represents an array and the element type
557 /// equals template parameter \p{TElementType}.
558 ///
559 /// @tparam TElementType The array element type to compare our element type with.
560 /// @return \c true if this box represents an array of given type, \c false otherwise.
561 template<typename TElementType>
562 bool IsArrayOf() const
563 { return vtable && typeid(TElementType) == vtable->ElementType; }
564
565 /// Returns \c true if this box uses pointer-boxing, otherwise \c false.
566 /// The default boxing of pointers will store the pointer to the boxed object
567 /// in union #"Placeholder::VoidP".
568 ///
569 /// @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
570 bool IsPointer() const { return vtable && vtable->IsPointer(); }
571
572 /// Returns \c true if this box contains an element of a scoped or non-scoped enum type.
573 /// Enum element values are always boxed as type #"lang::integer" stored in
574 /// union field #"boxing::Placeholder".
575 ///
576 /// @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
577 bool IsEnum() const { return vtable && vtable->IsEnum(); }
578
579 /// Returns \c true if \p{other} and this object share the same boxed type.
580 /// Note, if this box has void state (no value boxed), then this method returns
581 /// \c false, even if given \p{other} is void state as well.
582 ///
583 /// @param other The box to compare our type with.
584 /// @return \c true if this box has the same type like \p{other}, \c false otherwise.
585 bool IsSameType(const Box& other) const
586 { return vtable && vtable == other.vtable; }
587
588
589// Doxygen (V1.15) would create identical entries in its tag-file, so those are not reachable.
590// On the other hand, it complains if the methods are not doxed. So, we hide them from doxygen.
591#if DOXYGEN
592 /// Creates a value of type \p{TBoxable} from the contents of this box.
593 /// By default, this is done by invoking the template method #"Placeholder::Read"
594 /// on field #data.
595 /// This behavior might be customized by specializing type trait #"BoxTraits".
596 ///
597 /// For details on unboxing values and pointers, see chapter
598 /// #"alib_boxing_classes_constant" of the Programmer's Manual of this module \alib_boxing_nl.
599 ///
600 /// With debug-builds, it is #"ALIB_ASSERT_ERROR;asserted" that the given \p{TBoxable}
601 /// is mapped to the type stored, so that #IsType returned \c true for \p{TBoxable}.
602 /// In release compilations, no checks are performed!
603 ///
604 /// Internally, this method is implemented by providing different versions, selected with the
605 /// keyword \c requires.
606 /// @tparam TValue The value-type to unbox.
607 /// If it is not unboxable, a compile-time assertion is raised.
608 /// @return The unboxed value.
609 template<typename TValue>
610 requires ( !std::is_pointer_v<TValue>
612 TValue Unbox();
613#else
614 template<typename TValue>
616 TValue Unbox() const {
617 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TValue)
618
619 ALIB_ASSERT_ERROR( vtable, "BOXING","Box not initialized. Unboxing is undefined behavior." )
621 "Cannot unbox string-type <{}> from mapped type <{}>.", &typeid(TValue), &vtable->Type )
623
625 return characters::ArrayTraits<TValue, nchar>::Construct( data.GetPointer<nchar>(), data.GetLength() );
626
628 return characters::ArrayTraits<TValue, wchar>::Construct( data.GetPointer<wchar>(), data.GetLength() );
629
631 return characters::ArrayTraits<TValue, xchar>::Construct( data.GetPointer<xchar>(), data.GetLength() );
632 }
633
634 template<typename TValue>
635 requires ( !std::is_pointer_v<TValue>
637 TValue Unbox() const {
638 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TValue)
639
640 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior." )
641 ALIB_ASSERT_ERROR( vtable == getVTable<TValue>(), "BOXING",
642 "Cannot unbox type <{}> from mapped type <{}>.", &typeid(TValue), &vtable->Type )
643
644 debug::DbgCheckRegistration( vtable, true );
645 return BoxTraits<TValue>::Read(data);
646 }
647 template<typename TPointer>
648 requires ( std::is_pointer_v<TPointer>
649 && !IsUnboxableStringType<TPointer> )
650 const std::remove_pointer_t<TPointer>* Unbox() const {
651 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TPointer)
652
653 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
654 ALIB_ASSERT_ERROR( vtable == getVTable<TPointer>(),
655 "Cannot unbox type <{}> from mapped type <{}>.", &typeid(TPointer), &vtable->Type )
656 debug::DbgCheckRegistration( vtable, true );
657 return BoxTraits<TPointer>::Read(data);
658 }
659#endif
660
661 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING
662
663 /// Convenient method to unbox types boxed as pointers, as a non-<c>const</c> pointer type.
664 ///
665 /// \see Refer to manual chapter #"alib_boxing_classes_constant" for more information.
666 ///
667 /// @tparam TPointer The type to unbox.
668 /// If it is not unboxable, a compile-time assertion is given.
669 /// @return The unboxed value of type \p{TPointer} cast to a non-<c>const</c> object.
670 template <typename TPointer>
671 requires std::is_pointer_v<TPointer>
672 TPointer
673 UnboxMutable() const { return const_cast<std::remove_const_t<TPointer>>( Unbox<TPointer>() ); }
674
675 /// Returns the "raw" placeholder of this box.
676 ///
677 /// In some special situations, this method might be used inspect into the boxed data and
678 /// "reinterpret" its contents in a custom way.
679 ///
680 /// @return The raw contents of this box.
681 const Placeholder& Data() const {
682 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
683 return data;
684 }
685
686 /// Non-constant variant of #Data, that allows write access to the internal
687 /// memory of this box.
688 ///
689 /// A use case for non-constant access could be the implementation of a
690 /// #"alib_boxing_functions_mutable;non-constant box-function".
691 /// In fact, this is the only occasion where within any \alibmod_nl this method was
692 /// needed.
693 ///
694 /// @return The raw contents of this box.
696 {
697 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
698 return data;
699 }
700
701 /// Returns the number of relevant bytes used in the placeholder.
702 ///
703 /// This method is used with default implementations of box-functions #"FHashcode"
704 /// and #"FEquals".
705 ///
706 /// \see
707 /// The documentation of #"SizeTraits" provides details on and rationals for
708 /// the existence of this method.
709 ///
710 /// @return The number of written bytes in this box's placeholder.
711 unsigned GetPlaceholderUsageLength() const {
712 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized." )
713 return vtable->PlaceholderUsage;
714 }
715
716 /// Returns the type of this box as an integral value. This value might be stored and used
717 /// to compare types of boxes later.
718 ///
719 /// @return An identifier of type of this box.
720 TypeCode ExportType() const { return TypeCode(vtable); }
721
722 /// Returns the data-placeholder of this box.
723 ///
724 /// \note
725 /// This method is provided for "completeness" and only be used in special situations.
726 ///
727 /// @return A copy of the internal placeholder
728 Placeholder ExportValue() const { return data; }
729
730 /// Changes this box to use the given type code previously exported with #ExportType.
731 /// The value of this box will be set to \c 0.
732 /// @param typeCode The type code this box will be set to.
733 void Import(TypeCode typeCode) {
734 vtable= reinterpret_cast<detail::VTable*>(typeCode);
735 data.Array.Pointer= nullptr;
736 data.Array.Length = 0;
737 }
738
739 /// Changes this box to use the given type and data, previously received with methods
740 /// #ExportType and ExportValue.
741 ///
742 /// @param typeCode The type code this box will be set to.
743 /// @param placeholder The data this box will be set to.
744 void Import(TypeCode typeCode, const Placeholder& placeholder )
745 {
746 vtable= reinterpret_cast<detail::VTable*>(typeCode);
747 data= placeholder;
748 }
749
750 /// Returns the \c std::type_info struct describing the boxed type.
751 /// To get the element type of boxed arrays, use #ElementTypeID.
752 ///
753 /// \note
754 /// This method is provided for "completeness" and only be used in special situations.
755 ///
756 /// \note
757 /// If a box is not initialized (or has \c nullptr assigned, <c>typeid(void)</c> is
758 /// returned.
759 ///
760 /// \note
761 /// In case of arrays, a \c std::type_info reference is returned that corresponds
762 /// to an array of the element type of size \c 1. For example, if an array of type
763 /// \c double of an arbitrary size was boxed, then <c>typeid(double[1])</c>is returned.
764 ///
765 /// @return The \c std::type_info of the mapped type.
766 const std::type_info& TypeID() const {
768 return vtable ? vtable->Type : typeid(void);
769 }
770
771 /// Returns the \c std::type_info struct describing the element type of mapped array types.
772 ///
773 /// \note
774 /// This method is provided for "completeness" and only be used in special situations.<br>
775 /// In case this box is not of array type, <c>typeid(void)</c> is returned.
776 ///
777 /// @return The \c std::type_info of the mapped type.
778 const std::type_info& ElementTypeID() const {
779 ALIB_ASSERT_ERROR( vtable , "BOXING", "Box not initialized. Cannot get type information.")
780 return vtable->ElementType;
781 }
782
783 /// Returns the size in bytes of on element of the stored array.
784 /// For non-array types, \c 0 is returned.
785 ///
786 /// @return The size of elements in the array.
787 size_t ArrayElementSize() const {
788 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
789 return vtable->Mapping > 0 ? size_t( vtable->Mapping )
790 : 0;
791 }
792
793 /// Returns the pointer to the first array element.
794 ///
795 /// \note
796 /// With debug-builds, it is #"ALIB_ASSERT_ERROR;asserted" that #IsArray
797 /// returns \c true and the stored type is the same as requested.
798 /// In release compilations, no checks are performed!
799 ///
800 /// @tparam TElementType The type of array elements
801 /// @return A pointer to the first array element.
802 template <typename TElementType>
803 TElementType* UnboxArray() const {
804 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
805 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
806 "Box::UnboxArray() invoked on box of non-array type <{}>.", &vtable->Type )
807
808 ALIB_ASSERT_ERROR( typeid(TElementType) == vtable->ElementType,
809 "BOXING: Cannot unbox array type<{}[]> from mapped type<{}[]>.",
810 &typeid(TElementType*), &vtable->ElementType )
811
813 return data.GetPointer<TElementType>();
814 }
815
816 /// Returns the length of a boxed Array. While in theory, the length applies only to
817 /// arrays, in debug-compilations, \b no run-time type check is performed.
818 /// This way, mapped types that use the second "word" of the placeholder to store a
819 /// value of type \c integer, may also use this function.<br>
820 /// In the latter case, the name of this method might be misleading and therefore, it is
821 /// recommended to use <b>Data().integer[1]</b> to denote that a custom interpretation of the
822 /// placeholder is performed. The compilation result is the same.
823 ///
824 /// Some quick rationale for why \alib is generally using signed types for array lengths,
825 /// is given #"alib_strings_details_signedlength;here".
826 ///
827 /// @return The length of the boxed object.
829 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
830 return data.GetLength();
831 }
832
833 /// Returns a reference to element \p{idx} of the boxed array.
834 ///
835 /// \note
836 /// With debug-builds, it is #"alib_mod_assert;asserted" that #IsArray returns
837 /// \c true, that the stored type is the same as the requested type and the provided
838 /// \p{idx} is between \c 0 and the length of the array.
839 /// In release compilations, no checks are performed!
840 ///
841 /// @tparam TElementType The type of array elements
842 /// @param idx The index of the element to receive.
843 /// @return The value of the element at \p{idx}.
844 template <typename TElementType>
845 TElementType& UnboxElement(integer idx) const {
846 ALIB_ASSERT_ERROR( vtable, "BOXING",
847 "Box is void (no contents). Unboxing is undefined behavior." )
848 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
849 "Box::UnboxElement() invoked on box of non-array type <{}>.", &vtable->Type )
850
851 ALIB_ASSERT_ERROR( typeid(TElementType) == vtable->ElementType,
852 "BOXING: Cannot unbox array element type <{}> from mapped type <{}[]>.",
853 &typeid(TElementType), &vtable->ElementType )
854
855 ALIB_ASSERT_ERROR( idx >= 0 && idx < UnboxLength(), "BOXING",
856 "Box::UnboxElement<{}>(): Index out of bounds.", &typeid(TElementType))
857
859
860 return *( data.GetPointer<TElementType>() + idx );
861 }
862
863 #if DOXYGEN
864 /// Searches an implementation of a box-function identified by template parameter
865 /// \p{TFDecl}, which has to be implemented according the rules of
866 /// #"alib_boxing_functions_concepts_decl;function declarations".<br>
867 /// If found, a <em>non-nulled</em> function pointer is returned, otherwise a \e nulled one.
868 ///
869 /// On success, the function can be invoked by passing the returned pointer to method
870 /// #CallDirect.
871 /// This approach avoids further searches that are otherwise to be performed with multiple
872 /// invocations of method #Call.
873 ///
874 /// If parameter \p{defaults} equals #"Reach::Local;*", functions specific to the mapped
875 /// type of this box (registered using #"BootstrapRegister") are searched.
876 /// If #"Reach::Global;*" is given, then a defaulted function (registered using
877 /// #"BootstrapRegisterDefault") is searched, if no specific function was found.
878 ///
879 /// \note
880 /// #"Reach::Local;*" can be used to detect specific behavior and to avoid the use
881 /// of default functions. This can be useful if the default implementation of a function
882 /// is just not applicable in a certain situation.
883 ///
884 /// \note
885 /// A second use case of this method are situations where multiple invocations of the
886 /// same function are to be done, on just one or on several boxes of the same mapped type:
887 ///
888 /// assert( box1.IsSameType( box2 ) );
889 ///
890 /// auto* func= box1.GetFunction<FMyFunc>( Reach::Global );
891 /// if( func != nullptr )
892 /// for( int i= 0; i< 10; ++i )
893 /// {
894 /// box1.CallDirect<FMyFunc>( func, i );
895 /// box2.CallDirect<FMyFunc>( func, i );
896 /// }
897 ///
898 /// @tparam TFDecl The #"alib_boxing_functions_concepts_decl;function declaration"
899 /// to search for.
900 /// @param searchScope #"Reach::Local;*" chooses type-specific functions only, while.
901 /// #"Reach::Global;*" includes default functions in the search.
902 /// @param isInvocation Available only in debug compilations. If \c true, a counter
903 /// associated with an implementation found is increaed to provide
904 /// statistics. Defaults to false and should not be given.
905 /// @return The function implementation.
906 /// \c nullptr in case that no function is available.
907 template <typename TFDecl>
908 inline
909 typename TFDecl::Signature GetFunction( Reach searchScope
910 , bool isInvocation = false ) const;
911 #else
912 template <typename TFDecl>
913 typename TFDecl::Signature GetFunction( lang::Reach searchScope
914 ALIB_DBG( , bool isInvocation = false) ) const {
915 if( !vtable )
916 return nullptr;
917
918 ALIB_DBG( ++vtable->DbgCntUsage );
919
920 auto result= vtable->Functions.Get<TFDecl>( ALIB_DBG(isInvocation) );
921 return result
922 ? result
923 : searchScope == lang::Reach::Global
924 ? detail::DEFAULT_FUNCTIONS.Get<TFDecl>( ALIB_DBG(isInvocation) )
925 : nullptr;
926 }
927 #endif //DOXYGEN
928
929
930
931 /// Invokes a function registered for boxes of the mapped type.
932 /// The #"alib_boxing_functions_concepts_decl;function declaration" is provided with the
933 /// first template parameter \p{TFDecl}.
934 /// The further variadic template parameters do not need to be specified.
935 /// They specify the types of the called function's parameters and are matched against
936 /// the function signature given with the declaration.
937 /// If the types of the given function arguments do not correspond to the types of
938 /// the box-function called, a compile-time error is raised.
939 ///
940 /// \note
941 /// Precisely, the variadic template types denote the function arguments starting from the
942 /// second, as the first argument is always a reference to the box that this method was
943 /// invoked on.
944 ///
945 /// If no corresponding function #"BootstrapRegister;was registered" for the mapped
946 /// type, then a #"BootstrapRegisterDefault;default function", that is applicable
947 /// to any mapped type is searched.
948 /// If neither is found, a default value of the function' return-type is returned.
949 ///
950 /// With debug-builds, an #"alib_mod_assert;error is raised" if the function type is not
951 /// known at all to \alib_boxing_nl. This is true, if an implementation was neither registered
952 /// with any other mapped type, nor registered as a default.
953 ///
954 /// \see
955 /// Description of method #GetFunction to implement two use cases:
956 /// - Repetitive invocation of the same function.
957 /// - Avoidance of default functions
958 ///
959 /// \see
960 /// A non-constant overload exists, for the seldom case the reference to this box that is
961 /// passed to the function, needs to be of non-constant type.
962 ///
963 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
964 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
965 /// @param args Variadic arguments forwarded to the function.
966 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
967 /// respectively <c>TReturn()</c> if the requested function type was not found for
968 /// this \b %Box.
969 template <typename TFDecl, typename... TArgs>
970 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
971 Call(TArgs&&... args) const {
972 auto* func= GetFunction<TFDecl>( lang::Reach::Global ALIB_DBG(, true) );
973 if( func != nullptr )
974 return reinterpret_cast<typename TFDecl::Signature>(func)
975 ( *this, std::forward<TArgs>(args)... );
976
977
978 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
979 std::declval<TArgs>()... )) ();
980 }
981
982 /// Alternative version of method #Call, which accepts the function's pointer as a first
983 /// argument. Such a pointer can be received upfront with method #GetFunction.
984 ///
985 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
986 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
987 /// @param args Variadic arguments forwarded to the function.
988 /// @param function The function to invoke.
989 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
990 /// respectively <c>TReturn()</c> if the requested function type was not found for
991 /// this \b %Box.
992 template <typename TFDecl, typename... TArgs>
993 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
994 CallDirect(typename TFDecl::Signature function, TArgs&&... args) const {
995 ALIB_ASSERT_ERROR( vtable, "BOXING",
996 "Box not initialized (does not contain value). Function call not allowed." )
997 return reinterpret_cast<typename TFDecl::Signature>(function)
998 ( *this, std::forward<TArgs>(args)... );
999 }
1000
1001 /// Same as method #Call, but usable with interfaces that only accept a mutable
1002 /// (aka not constant) box. Technically, the only difference between this method and \b Call
1003 /// is that the latter is declared \c const.
1004 ///
1005 /// \note
1006 /// The only built-in boxing function that requires a mutable reference
1007 /// to a box, is function #"FClone". This modifies the contents
1008 /// of a box by performing deep copies, with the goal to
1009 /// #"alib_boxing_more_iclone;extent the lifecylce of boxes".
1010 ///
1011 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
1012 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1013 /// @param args Variadic arguments forwarded to the function.
1014 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1015 /// respectively <c>TReturn()</c> if the requested function type was not found for
1016 /// this \b %Box.
1017 template <typename TFDecl, typename... TArgs>
1018 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1019 Call(TArgs&&... args) {
1020 ALIB_ASSERT_ERROR( vtable, "BOXING",
1021 "Box not initialized (does not contain value). Function call not allowed." )
1022 auto* func= GetFunction<TFDecl>( lang::Reach::Global ALIB_DBG(, true));
1023 if( func != nullptr )
1024 return reinterpret_cast<typename TFDecl::Signature>(func)
1025 ( *this, std::forward<TArgs>(args)... );
1026
1027 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
1028 std::declval<TArgs>()... )) ();
1029 }
1030
1031 /// Alternative version of non-constant version of method #Call, which accepts the function's
1032 /// pointer as a first argument.
1033 /// Such a pointer can be received upfront with the method #GetFunction.
1034 ///
1035 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
1036 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1037 /// @param args Variadic arguments forwarded to the function.
1038 /// @param function The function to invoke.
1039 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1040 /// respectively <c>TReturn()</c> if the requested function type was not found for
1041 /// this \b %Box.
1042 template <typename TFDecl, typename... TArgs>
1043 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1044 CallDirect(typename TFDecl::Signature function, TArgs &&... args) {
1045 ALIB_ASSERT_ERROR( vtable, "BOXING",
1046 "Box not initialized (does not contain value). Function call not allowed." )
1047 return reinterpret_cast<typename TFDecl::Signature>( function )
1048 ( *this, std::forward<TArgs>(args)... );
1049 }
1050
1051 /// Comparison operator. Returns the result of invocation of built-in boxing function
1052 /// #"FEquals".
1053 ///
1054 /// @param rhs The right-hand side argument of the comparison.
1055 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
1056 ALIB_DLL
1057 bool operator==(Box const& rhs) const;
1058
1059 /// Comparison operator. Returns the negated result of #operator==.
1060 ///
1061 /// @param rhs The right-hand side argument of the comparison.
1062 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
1063 bool operator!=(const Box& rhs) const { return !((*this) == rhs); }
1064
1065 /// Comparison operator. Returns the result of invocation of built-in box-function
1066 /// #"FIsLess".
1067 ///
1068 /// \see
1069 /// Sample code provided with documentation of box-function #"FIsLess".
1070 ///
1071 /// @param rhs The right-hand side argument of the comparison.
1072 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1073 ALIB_DLL
1074 bool operator< (Box const& rhs) const;
1075
1076 /// Comparison operator. Uses a combination of \c operator< and \c operator==.
1077 ///
1078 /// @param rhs The right-hand side argument of the comparison.
1079 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1080 ALIB_DLL
1081 bool operator<=(Box const& rhs) const;
1082
1083 /// Comparison operator. Uses a combination of \c operator< and \c operator==.
1084 ///
1085 /// @param rhs The right-hand side argument of the comparison.
1086 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1087 ALIB_DLL
1088 bool operator> (Box const& rhs) const;
1089
1090 /// Comparison operator. Returns the negated result of \c operator<.
1091 ///
1092 /// @param rhs The right-hand side argument of the comparison.
1093 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1094 bool operator>= (Box const& rhs) const { return !( (*this) < rhs); }
1095
1096 /// Explicit cast operator to \c bool. Returns the result of built-in box-function
1097 /// #"FIsTrue".
1098 ///
1099 /// @return \c true if the boxed value <em>represents value true</em>, \c false otherwise.
1100 ALIB_DLL
1101 explicit operator bool() const;
1102
1103
1104 /// Returns the result of a call to built-in boxing function #"FIsNotNull".
1105 ///
1106 /// @return \c false if this object represents a \e nulled object, \c true otherwise.
1107 ALIB_DLL
1108 bool IsNotNull() const;
1109
1110 /// Returns the negated result of a call to built-in boxing function
1111 /// #"FIsNotNull".
1112 ///
1113 /// @return \c true if this object represents a \e nulled object, \c false otherwise.
1114 bool IsNull() const { return !IsNotNull(); }
1115
1116 /// Returns the result of invocation of built-in boxing function #"FHashcode".
1117 ///
1118 /// @return A hashcode for the boxed type and value.
1119 ALIB_DLL size_t Hashcode() const;
1120
1121 #if ALIB_MONOMEM
1122 /// Returns the result of invocation of built-in boxing function #"FHashcode".
1123 ///
1124 /// \par Availability
1125 /// This method is available only if the module \alib_monomem is included in the \alibbuild.
1126 /// @param memory A monotonic allocator used for storing cloned data.
1128 #endif
1129
1130}; // class Box
1131
1132} // namespace alib[::boxing]
1133
1134/// Type alias in namespace \b alib.
1136} // namespace [alib]
1137
1140
1141#include "ALib.Lang.CIFunctions.H"
1142ALIB_EXPORT namespace alib::boxing {
1143//==================================================================================================
1144/// Registers #"alib_boxing_functions;box-function" \p{function} of type \p{TFDecl} for
1145/// boxes of mapped type \p{TMapping}.
1146///
1147/// \attention
1148/// Function registration and function invocation are not protected against racing conditions
1149/// of multithreaded access. For this reason, it is advised to invoke this function exclusively
1150/// while #"alib_mod_bs;bootstrapping" software, when no threads are started,
1151/// yet. Registrations can be made before bootstrapping \alib, respectively during or after
1152/// phase #"BootstrapPhases::PrepareResources;2".
1153///
1154/// \attention
1155/// If for any reason registration is performed \b after bootstrapping \alib and module
1156/// \alib_monomem is included in the \alibbuild, and this function is invoked after
1157/// \alib was bootstrapped, then before an invocation of this method, mutex
1158/// #"GLOBAL_ALLOCATOR_LOCK" has to be acquired. This can be done with:
1159/// \snippet "ut_monomem.cpp" DOX_MONOMEM_LOCK_GLOBALALLOCATOR
1160///
1161/// \attention
1162/// Note that even when this lock is set, still multithreaded access to registration and/or
1163/// box-function invocations is <b>not allowed</b>.
1164///
1165/// @tparam TFDecl The #"alib_boxing_functions_concepts_decl;type of function" to register.
1166/// @tparam TMapped The mapped type that boxes store, which are to be equipped with a specialized
1167/// function implementation.
1168/// @tparam TIsArray Denotes whether array-boxing is applied. Defaults to \c false.
1169/// @param function Pointer to the function implementation.
1170//==================================================================================================
1171template<typename TFDecl, typename TMapped, bool TIsArray= false>
1172inline
1173void BootstrapRegister( typename TFDecl::Signature function ) {
1175 ->Functions.template Get<TFDecl>(false),
1176 "BOXING", "Box-function \"{}\" already registered for type \"{}\".",
1177 &typeid(TFDecl), &typeid(TMapped) )
1178
1180 ->Functions.template Set<TFDecl>( function );
1181}
1182
1183//==================================================================================================
1184/// Registers a default implementation of a #"alib_boxing_functions;box-function", which
1185/// is invoked if no type-specific implementation is registered for a mapped type.
1186///
1187/// \attention
1188/// Function registration and function invocation are not protected against racing conditions
1189/// of multithreaded access. For this reason, it is advised to invoke this function exclusively
1190/// while #"alib_mod_bs;bootstrapping" software, when no threads are started,
1191/// yet. Registrations can be made before bootstrapping \alib, respectively during or after
1192/// phase #"BootstrapPhases::PrepareResources;2".
1193///
1194/// \attention
1195/// If for any reason registration is performed \b after bootstrapping \alib and module
1196/// \alib_monomem is included in the \alibbuild, and this function is invoked after
1197/// \alib was bootstrapped, then, before an invocation of this method, mutex
1198/// #"GLOBAL_ALLOCATOR_LOCK" has to be acquired. This can be done with:
1199/// \snippet "ut_monomem.cpp" DOX_MONOMEM_LOCK_GLOBALALLOCATOR
1200///
1201/// \attention
1202/// Note that even when this lock is set, still multithreaded access to registration and/or
1203/// box-function invocations is <b>not allowed</b>.
1204///
1205/// @tparam TFDecl The #"alib_boxing_functions_concepts_decl;type of function" to register.
1206/// @param function Pointer to the function's default implementation.
1207//==================================================================================================
1208template<typename TFDecl>
1209inline
1210void BootstrapRegisterDefault( typename TFDecl::Signature function )
1211{ detail::DEFAULT_FUNCTIONS.Set<TFDecl>( function ); }
1212} // namespace [alib::boxing]
#define ALIB_DLL
Definition alib.inl:573
#define ALIB_TVALUE(T)
Definition alib.inl:1081
#define ALIB_EXPORT
Definition alib.inl:562
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
void Clone(MonoAllocator &memory)
detail::VTable * vtable
Definition box.inl:37
bool operator>(Box const &rhs) const
Definition box.cpp:181
TElementType & UnboxElement(integer idx) const
Definition box.inl:845
uinteger UnboxUnsignedIntegral() const
Definition box.inl:488
const detail::VTable * DbgGetVTable() const
Definition box.inl:386
uinteger TypeCode
The type of type codes received with #"ExportType".
Definition box.inl:224
bool IsUnsignedIntegral() const
Definition box.inl:464
double UnboxFloatingPoint() const
Definition box.cpp:150
Placeholder data
The data that we encapsulate.
Definition box.inl:40
const std::type_info & ElementTypeID() const
Definition box.inl:778
Box(TypeCode typeCode, const Placeholder &placeholder) noexcept
Definition box.inl:235
integer UnboxSignedIntegral() const
Definition box.inl:476
size_t Hashcode() const
bool IsNotNull() const
bool operator!=(const Box &rhs) const
Definition box.inl:1063
bool IsFloatingPoint() const
Definition box.cpp:139
TypeCode ExportType() const
Definition box.inl:720
void Import(TypeCode typeCode)
Definition box.inl:733
constexpr void initPH(const T &src) noexcept
Definition box.inl:209
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) CallDirect(typename TFDecl::Signature function, TArgs &&... args) const
Definition box.inl:994
bool IsSameType(const Box &other) const
Definition box.inl:585
bool operator>=(Box const &rhs) const
Definition box.inl:1094
bool IsArrayOf() const
Definition box.inl:562
bool IsPointer() const
Definition box.inl:570
Placeholder ExportValue() const
Definition box.inl:728
bool IsEnum() const
Definition box.inl:577
void Import(TypeCode typeCode, const Placeholder &placeholder)
Definition box.inl:744
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.inl:971
constexpr Box(const TBoxable &src) noexcept
bool IsType() const
TPointer UnboxMutable() const
Definition box.inl:673
size_t ArrayElementSize() const
Definition box.inl:787
const std::type_info & TypeID() const
Definition box.inl:766
bool IsArray() const
Definition box.inl:554
const Placeholder & Data() const
Definition box.inl:681
bool operator<(Box const &rhs) const
Definition box.cpp:179
bool IsCharacter() const
Definition box.inl:508
TElementType * UnboxArray() const
Definition box.inl:803
static constexpr detail::VTable * getVTable()
Definition box.inl:194
integer UnboxLength() const
Definition box.inl:828
bool operator==(Box const &rhs) const
Definition box.cpp:178
bool IsSignedIntegral() const
Definition box.inl:451
bool operator<=(Box const &rhs) const
Definition box.cpp:180
unsigned GetPlaceholderUsageLength() const
Definition box.inl:711
Placeholder & Data()
Definition box.inl:695
wchar UnboxCharacter() const
Definition box.inl:520
TFDecl::Signature GetFunction(Reach searchScope, bool isInvocation=false) const
Box() noexcept
Definition box.inl:229
bool IsNull() const
Definition box.inl:1114
void DbgCheckRegistration(detail::VTable *vtable, bool increaseUsageCounter)
FunctionTable DEFAULT_FUNCTIONS
The default box-functions set.
Definition vtable.cpp:95
void BootstrapRegisterDefault(typename TFDecl::Signature function)
Definition box.inl:1210
void BootstrapRegister(typename TFDecl::Signature function)
Definition box.inl:1173
Reach
Denotes the reach of something.
@ Global
Denotes global reach.
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
characters::wchar wchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1135
characters::nchar nchar
Type alias in namespace alib.
characters::xchar xchar
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
static constexpr bool IsArray
Denotes whether type TBoxable is boxed as an array-type or not.
static constexpr detail::VTable * Get()
Definition vtable.inl:467
The custom function hash.
Definition vtable.inl:228
FunctionTable Functions
Box-functions attached with #"BootstrapRegister".
Definition vtable.inl:260
static constexpr Policy Access
static TStringSource Construct(const TChar *array, integer length)
static constexpr Policy Construction