ALib C++ Library
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 \ref mainpage_license "Boost Software 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/// \ref 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 \implude{Boxing.StdFunctors}.
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 /// The type of type codes received with #ExportType.
220
221 /// Default constructor.<br>
222 /// After creation with this constructor, a call to #IsType<void> returns true.
223 /// To reset an instance previously used, assign keyword \c nullptr.
224 Box() noexcept
225 : vtable( nullptr ) {}
226
227 /// Constructor accepting previously exported values.
228 /// @param typeCode The type code this box will be set to.
229 /// @param placeholder The data this box will be set to.
230 Box( TypeCode typeCode, const Placeholder& placeholder ) noexcept
231 : vtable(reinterpret_cast<detail::VTable*>(typeCode))
232 , data (placeholder) {}
233
234 #if DOXYGEN
235 /// Constructor to fetch any type of object.<br>
236 /// Internally, this constructor is implemented using a set of different constructors
237 /// which are selected by the compiler using keyword \c requires.
238 ///
239 /// Types derived from class \b %Box itself are boxed by copying the internal values
240 /// of the box. This means that boxing objects of derived types is similar to
241 /// "downcasting" the object to class \b %Box.
242 ///
243 /// @tparam TBoxable Any C++ type to be boxed.
244 /// @param src The src value or pointer type \c T.
245 template <typename TBoxable>
246 inline constexpr Box(const TBoxable& src ) noexcept;
247 #else
248 //######################################### Special types ########################################
249
250 // Keyword 'nullptr'
251 constexpr Box(const std::nullptr_t& ) noexcept : vtable(nullptr) {}
252
253 // C++ arrays
254 template<typename T>
255 requires std::is_array_v<T>
256 constexpr Box( T& src ) noexcept {
257 using TElem= std::remove_cv_t<std::remove_pointer_t<std::decay_t<T>>>;
259
260 constexpr integer length= characters::IsCharacter<TElem> ? std::extent<T>::value - 1
261 : std::extent<T>::value;
262 data = Placeholder( &src, length );
263 }
264
265 // Derived Box value types (like copy constructor but fetches derived types)
266 template<typename T>
267 requires ( std::is_base_of<Box, std::remove_cv_t<T>>::value )
268 constexpr Box( const T& src ) noexcept
269 : vtable( src.vtable )
270 , data ( src.data ) {}
271
272 //##################################### Boxing with BoxTraits ####################################
273
274 // 0) Strings
275 template<typename T>
276 requires ( IsStringType<std::remove_cv_t<T>> )
277 constexpr Box( const T& src ) noexcept {
278
279 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
280 if constexpr ( characters::ArrayTraits <T, nchar>::Access == characters::Policy::Implicit ) {
282 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, nchar>::Buffer( src ),
283 characters::ArrayTraits<std::remove_cv_t<T>, nchar>::Length( src ) );
284 }
287 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, wchar>::Buffer( src ),
288 characters::ArrayTraits<std::remove_cv_t<T>, wchar>::Length( src ) );
289 }
292 data = Placeholder( characters::ArrayTraits<std::remove_cv_t<T>, xchar>::Buffer( src ),
293 characters::ArrayTraits<std::remove_cv_t<T>, xchar>::Length( src ) );
294 }
295
296 }
297
298 // 1) Value remains value
299 template<typename T>
300 requires ( !std::is_pointer_v<T>
301 && !IsStringType<std::remove_cv_t<T>>
302 && ( IsCustomized<std::decay_t<T> >
303 || ( !IsCustomized<std::decay_t<T>*> && IsStdPH<T> ) )
304 )
305 constexpr Box( const T& src ) noexcept {
306 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
307 vtable= getVTable<T>();
308 initPH( src );
309 }
310
311 // 2) Value converted to pointer
312 template<typename T>
313 requires( !std::is_pointer_v<T>
314 && !IsStringType<std::remove_cv_t<T>>
315 && !std::is_array_v<T>
316 && !std::is_base_of_v<Box, T>
317 && !IsCustomized<std::decay_t<T> >
318 && ( IsCustomized<std::remove_cv_t<T> >
319 || ( !IsCustomized<std::decay_t<T>*> && !IsStdPH<T> )
320 || ( IsCustomized<std::decay_t<T>*> )
321 )
322 )
323 constexpr Box( const T& src ) noexcept {
324 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, true)
325 vtable= getVTable<std::remove_cv_t<T>*>();
326 initPH( &src );
327 }
328
329 // 3) Pointer remains pointer
330 template<typename T>
331 requires ( std::is_pointer_v<T>
332 && !std::is_base_of_v<Box, ALIB_TVALUE(T)>
333 &&
334 ( IsCustomized<std::remove_cv_t<T>>
335 || !( IsCustomized<ALIB_TVALUE(T)> || IsStdPH<T> )
336 ))
337 constexpr Box( const T& src ) noexcept {
338 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, false)
339 vtable= getVTable<T>();
340 initPH( src );
341 }
342
343 // 4) Pointer dereferenced to value
344 template<typename T>
345 requires ( std::is_pointer_v<T>
346 && !std::is_base_of_v<Box, ALIB_TVALUE(T)>
347 && !IsStringType<std::remove_cv_t<T>>
348 && !
349 ( IsCustomized<std::remove_cv_t<T>>
350 || !( IsCustomized<ALIB_TVALUE(T)> || IsStdPH<T> )
351 )
352 )
353 constexpr Box( const T& src ) noexcept {
354 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(T, false)
355 using TV= ALIB_TVALUE(T);
356 vtable= getVTable<TV>();
357 if ( src ) initPH( *src );
358 else data = Placeholder( sizeof(TV) <= sizeof(integer)
359 ? Placeholder( 0 )
360 : Placeholder( integer(0), integer(0) ) );
361 }
362
363
364 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING
365 #undef ALIB_TM_IS_DEFAULT_BOXING
366
367 #endif // DOXYGEN
368
369 //################################################################################################
370 // Interface
371 //################################################################################################
372 #if ALIB_DEBUG
373 /// Returns the \e vtable of this instance that is associated with the currently boxed
374 /// type.<br>
375 /// Available only with debug-builds.
376 ///
377 /// \see
378 /// Manual chapter \ref alib_boxing_more_debug of the Programmer's Manual.
379 ///
380 /// @return The \e vtable of this instance.
381 const detail::VTable* DbgGetVTable() const { return vtable; }
382
383 #endif
384
385 #if DOXYGEN
386 /// Checks if this box stores a value of type \p{TBoxable}.
387 ///
388 /// If template parameter \p{TBoxable} it is not unboxable, a compile-time assertion
389 /// is given, with specific guidance why the type must not be unboxed and for that
390 /// reason must not even be tested for.
391 ///
392 /// Special type \c void may be given for testing if this box does contain a value at all.
393 /// A box does not contain a value, after
394 /// - default construction,
395 /// - construction with keyword \c nullptr, or
396 /// - assignment of keyword \c nullptr.
397 ///
398 /// For more information on the "void state" of boxes, see manual chapter
399 /// \ref alib_boxing_more_void.
400 ///
401 ///
402 /// @tparam TBoxable The boxable type guessed.
403 /// @return \c true if this box stores a value that is convertible to type \p{TBoxable},
404 /// \c false otherwise.
405 template<typename TBoxable>
406 bool IsType() const;
407
408 #else
409 template<typename TBoxable>
411 bool IsType() const {
414
417
420 }
421
422 template<typename TBoxable>
423 requires ( !std::same_as<TBoxable, void>
425 bool IsType() const {
426 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TBoxable)
427 return vtable == getVTable<TBoxable>();
428 }
429
430 template<typename TBoxable>
431 requires std::same_as<TBoxable, void>
432 bool IsType() const { return vtable == nullptr; }
433 #endif
434
435 #if !ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS || DOXYGEN
436 /// Tests if this box contains a signed integral type (one of the C++ fundamental
437 /// types of different sizes).
438 ///
439 /// With compilation that disables
440 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
441 /// simply returns <c>IsType<integer>()</c>.<br>
442 /// Otherwise this method will not be inlined and tests for the five different
443 /// integer sizes (\c int8_t, \c int16_t, \c int32_t, \c int64_t, and \alib{intGap_t}).
444 ///
445 /// @return \c true if this box contains a signed integral type, \c false otherwise.
446 bool IsSignedIntegral() const { return IsType<integer >(); }
447
448 /// Tests if this box contains an unsigned integral type (one of the C++ fundamental
449 /// type of different sizes).
450 ///
451 /// With default library compilation that disables
452 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
453 /// simply returns <c>IsType<uinteger>()</c>.<br>
454 /// Otherwise this method will not be inlined and tests for the five different
455 /// integer sizes (\c uint8_t, \c uint16_t, \c uint32_t, \c uint64_t, and
456 /// \alib{uintGap_t}).
457 ///
458 /// @return \c true if this box contains an unsigned integral type, \c false otherwise.
459 bool IsUnsignedIntegral() const { return IsType<uinteger>(); }
460
461 /// Unboxes a signed integral.
462 ///
463 /// With default library compilation that disables
464 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
465 /// simply returns <c>Unbox<integer>()</c>.<br>
466 /// Otherwise this method will not be inlined and tests for the five different
467 /// integer sizes (1, 2, 4, and 8 bytes size and the #alib::intGap_t) before
468 /// unboxing.
469 ///
470 /// @return The boxed signed integral value.
472
473 /// Unboxes an unsigned integral.
474 ///
475 /// With default library compilation that disables
476 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
477 /// simply returns <c>Unbox<uinteger>()</c>.<br>
478 /// Otherwise this method will not be inlined and tests for the five different
479 /// integer sizes (1, 2, 4, and 8 bytes size and the #alib::uintGap_t) before
480 /// unboxing.
481 ///
482 /// @return The boxed unsigned integral value.
484 #else
485 ALIB_DLL bool IsSignedIntegral() const;
486 ALIB_DLL bool IsUnsignedIntegral() const;
489 #endif
490
491
492 #if !ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS || DOXYGEN
493 /// Tests if this box contains one of types \c char, \c wchar_t, \c char8_t, \c char16_t,
494 /// or \c char32_t.
495 ///
496 /// With default library compilation that disables symbol
497 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS, this method will be inlined and
498 /// simply returns <c>IsType<wchar>()</c>.<br>
499 /// Otherwise, this method will not be inlined and tests for all five different
500 /// character types.
501 ///
502 /// @return \c true if this box contains a character type, \c false otherwise.
503 bool IsCharacter() const { return IsType<wchar>(); }
504
505 /// Unboxes one of the types \c char, \c wchar_t, \c char8_t, \c char16_t, or \c char32_t
506 /// and converts it to \alib{characters;wchar}.
507 ///
508 /// With default library compilation that disables
509 /// \ref ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS, this method will be inlined and
510 /// simply returns <c>Unbox<wchar>()</c>.<br>
511 /// Otherwise, this method will not be inlined and tests for the five different
512 /// character types before unboxing.
513 ///
514 /// @return The stored character.
515 wchar UnboxCharacter() const { return Unbox<wchar>(); }
516
517 #else
518 ALIB_DLL bool IsCharacter() const;
520 #endif
521
522
523 /// Tests if this box contains a floating point type.
524 ///
525 /// \note
526 /// If \ref ALIB_FEAT_BOXING_BIJECTIVE_FLOATS is not set, this method will
527 /// test against \c double and <c>long double</c>. If it is set, in addition
528 /// type \c float is tested.
529 ///
530 /// @return \c true if this box contains a floating point type, \c false otherwise.
531 bool IsFloatingPoint() const;
532
533 /// Unboxes a floating point value as \c double.
534 ///
535 /// \note
536 /// If \ref ALIB_FEAT_BOXING_BIJECTIVE_FLOATS is not set, this method will
537 /// test against \c double and <c>long double</c> and convert the latter.
538 /// If it is set, in addition type \c float is tested.
539 ///
540 /// @return \c true if this box contains a floating point type, \c false otherwise.
542 double UnboxFloatingPoint() const;
543
544 /// Returns \c true if this box represents an array of objects.
545 /// In this case, method #UnboxLength (usually) will return the length of the array and
546 /// #UnboxElement may be used to access elements of the array.
547 ///
548 /// @return \c true if this box represents an array, \c false otherwise.
549 bool IsArray() const { return vtable && vtable->IsArray(); }
550
551 /// Returns \c true if this objects represents an array and the element type
552 /// equals template parameter \p{TElementType}.
553 ///
554 /// @tparam TElementType The array element type to compare our element type with.
555 /// @return \c true if this box represents an array of given type, \c false otherwise.
556 template<typename TElementType>
557 bool IsArrayOf() const
558 { return vtable && typeid(TElementType) == vtable->ElementType; }
559
560 /// Returns \c true if this box uses pointer-boxing, otherwise \c false.
561 /// The default boxing of pointers will store the pointer to the boxed object
562 /// in union \alib{boxing;Placeholder::VoidP}.
563 ///
564 /// @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
565 bool IsPointer() const { return vtable && vtable->IsPointer(); }
566
567 /// Returns \c true if this box contains an element of a scoped or non-scoped enum type.
568 /// Enum element values are always boxed as type \alib{integer} stored in
569 /// union field \alib{boxing;Placeholder}.
570 ///
571 /// @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
572 bool IsEnum() const { return vtable && vtable->IsEnum(); }
573
574 /// Returns \c true if \p{other} and this object share the same boxed type.
575 /// Note, if this box has void state (no value boxed), then this method returns
576 /// \c false, even if given \p{other} is void state as well.
577 ///
578 /// @param other The box to compare our type with.
579 /// @return \c true if this box has the same type like \p{other}, \c false otherwise.
580 bool IsSameType(const Box& other) const
581 { return vtable && vtable == other.vtable; }
582
583
584 /// This overload unboxes character string types that meet the concept
585 /// \alib{boxing;IsUnboxableStringType}.
586 /// This is done by testing the availability of \alib{characters;ArrayTraits} (provided with
587 /// module \alib_characters) for the given type \p{TString} and invoking its method
588 /// \alib{characters::ArrayTraits;Construct} passing the boxed character-array data.
589 ///
590 /// @tparam TValue The string-type to unbox.
591 /// If it is not unboxable, a compile-time assertion is raised.
592 /// @return The unboxed string instance.
593 template<typename TValue>
595 TValue Unbox() const {
596 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TValue)
597
598 ALIB_ASSERT_ERROR( vtable, "BOXING","Box not initialized. Unboxing is undefined behavior." )
600 "Cannot unbox string-type <{}> from mapped type <{}>.", &typeid(TValue), &vtable->Type )
602
604 return characters::ArrayTraits<TValue, nchar>::Construct( data.GetPointer<nchar>(), data.GetLength() );
605
607 return characters::ArrayTraits<TValue, wchar>::Construct( data.GetPointer<wchar>(), data.GetLength() );
608
610 return characters::ArrayTraits<TValue, xchar>::Construct( data.GetPointer<xchar>(), data.GetLength() );
611 }
612
613 /// Creates a value of type \p{TBoxable} from the contents of this box .
614 /// By default, this is done by invoking the template method \alib{boxing;Placeholder::Read}
615 /// on field #data.
616 /// This behavior might be customized by specializing type trait \alib{boxing;BoxTraits}.
617 ///
618 /// This overload of the method accepts only (non-const) value types.
619 /// For details on unboxing values and pointers, see chapter
620 /// \ref alib_boxing_classes_constant of the Programmer's Manual of this module \alib_boxing_nl.
621 ///
622 /// With debug-builds, it is \ref ALIB_ASSERT_ERROR "asserted" that given \p{TBoxable}
623 /// is mapped to the type stored, so that #IsType returned \c true for \p{TBoxable}.
624 /// In release compilations, no checks are performed!
625 ///
626 /// @tparam TValue The value-type to unbox.
627 /// If it is not unboxable, a compile-time assertion is raised.
628 /// @return The unboxed value.
629 template<typename TValue>
630 requires ( !std::is_pointer_v<TValue>
632 TValue Unbox() const {
633 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TValue)
634
635 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior." )
637 "Cannot unbox type <{}> from mapped type <{}>.", &typeid(TValue), &vtable->Type )
638
641 }
642
643 /// Returns a pointer to a constant instance of type \p{TPointer} that this box stored.
644 /// By default, this is done by invoking the template method \alib{boxing;Placeholder::Read}
645 /// on field #data.
646 /// This behavior might be customized by specializing type trait \alib{boxing;BoxTraits}.
647 ///
648 /// This overload of the method accepts only (non-const) pointer-types.
649 /// For details on unboxing values and pointers, see chapter
650 /// \ref alib_boxing_classes_constant of the Programmer's Manual of this module \alib_boxing_nl.
651 ///
652 /// With debug-builds, it is \ref alib_mod_assert "asserted" that given \p{TBoxable}
653 /// is mapped to the type stored, so that #IsType returned \c true for \p{TBoxable}.
654 /// In release compilations, no checks are performed!
655 ///
656 /// @tparam TPointer The pointer-type to unbox.
657 /// If it is not unboxable, a compile-time assertion is raised.
658 /// @return The unboxed pointer to a constant instance of \p{TPointer}.
659 template<typename TPointer>
660 requires ( std::is_pointer_v<TPointer>
662 const std::remove_pointer_t<TPointer>* Unbox() const {
663 ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TPointer)
664
665 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
667 "Cannot unbox type <{}> from mapped type <{}>.", &typeid(TPointer), &vtable->Type )
670 }
671
672 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING
673
674 /// Convenient method to unbox types boxed as pointers, as a non-<c>const</c> pointer type.
675 ///
676 /// \see Refer to manual chapter \ref alib_boxing_classes_constant for more information.
677 ///
678 /// @tparam TPointer The type to unbox.
679 /// If it is not unboxable, a compile-time assertion is given.
680 /// @return The unboxed value of type \p{TPointer} cast to a non-<c>const</c> object.
681 template <typename TPointer>
682 requires std::is_pointer_v<TPointer>
683 TPointer
684 UnboxMutable() const { return const_cast<std::remove_const_t<TPointer>>( Unbox<TPointer>() ); }
685
686 /// Returns the "raw" placeholder of this box.
687 ///
688 /// In some special situations, this method might be used inspect into the boxed data and
689 /// "reinterpret" its contents in a custom way.
690 ///
691 /// @return The raw contents of this box.
692 const Placeholder& Data() const {
693 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
694 return data;
695 }
696
697 /// Non-constant variant of #Data, that allows write access to the internal
698 /// memory of this box.
699 ///
700 /// A use case for non-constant access could be the implementation of a
701 /// \ref alib_boxing_functions_mutable "non-constant box-function".
702 /// In fact, this is the only occasion where within any \alibmod_nl this method was
703 /// needed.
704 ///
705 /// @return The raw contents of this box.
707 {
708 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
709 return data;
710 }
711
712 /// Returns the number of relevant bytes used in the placeholder.
713 ///
714 /// This method is used with default implementations of box-functions \alib{boxing;FHashcode}
715 /// and \alib{boxing;FEquals}.
716 ///
717 /// \see
718 /// The documentation of \alib{boxing;SizeTraits} provides details on and rationals for
719 /// the existence of this method.
720 ///
721 /// @return The raw contents of this box.
722 unsigned GetPlaceholderUsageLength() const {
723 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized." )
724 return vtable->PlaceholderUsage;
725 }
726
727 /// Returns the type of this box as an integral value. This value might be stored and used
728 /// to compare types of boxes later.
729 ///
730 /// @return An identifier of type of this box.
731 TypeCode ExportType() const { return uinteger(vtable); }
732
733 /// Returns the type of this box as an integral value. This value might be stored and used
734 /// to compare types of boxes later.
735 ///
736 /// \note
737 /// This method is provided for "completeness" and only be used in special situations.<br>
738 /// If a box is not initialized (or has \c nullptr assigned, <c>0</c> is
739 /// returned.
740 ///
741 /// @return An identifier of type of this box.
742 Placeholder ExportValue() const { return data; }
743
744 /// Changes this box to use the given type code previously exported with #ExportType.
745 /// The value of this box will be set to \c 0.
746 /// @param typeCode The type code this box will be set to.
747 void Import(TypeCode typeCode) {
748 vtable= reinterpret_cast<detail::VTable*>(typeCode);
749 data.Array.Pointer= nullptr;
750 data.Array.Length = 0;
751 }
752
753 /// Changes this box to use the given type and data, previously received with methods
754 /// #ExportType and ExportValue.
755 ///
756 /// @param typeCode The type code this box will be set to.
757 /// @param placeholder The data this box will be set to.
758 void Import(TypeCode typeCode, const Placeholder& placeholder )
759 {
760 vtable= reinterpret_cast<detail::VTable*>(typeCode);
761 data= placeholder;
762 }
763
764 /// Returns the \c std::type_info struct describing the boxed type.
765 /// To get the element type of boxed arrays, use #ElementTypeID.
766 ///
767 /// \note
768 /// This method is provided for "completeness" and only be used in special situations.
769 ///
770 /// \note
771 /// If a box is not initialized (or has \c nullptr assigned, <c>typeid(void)</c> is
772 /// returned.
773 ///
774 /// \note
775 /// In case of arrays, a \c std::type_info reference is returned that corresponds
776 /// to an array of the element type of size \c 1. For example, if an array of type
777 /// \c double of an arbitrary size was boxed, then <c>typeid(double[1])</c>is returned.
778 ///
779 /// @return The \c std::type_info of the mapped type.
780 const std::type_info& TypeID() const {
782 return vtable ? vtable->Type : typeid(void);
783 }
784
785 /// Returns the \c std::type_info struct describing the element type of mapped array types.
786 ///
787 /// \note
788 /// This method is provided for "completeness" and only be used in special situations.<br>
789 /// In case this box is not of array type, <c>typeid(void)</c> is returned.
790 ///
791 /// @return The \c std::type_info of the mapped type.
792 const std::type_info& ElementTypeID() const {
793 ALIB_ASSERT_ERROR( vtable , "BOXING", "Box not initialized. Cannot get type information.")
794 return vtable->ElementType;
795 }
796
797 /// Returns the size in bytes of on element of the stored array.
798 /// For non-array types, \c 0 is returned.
799 ///
800 /// @return The size of elements in the array.
801 size_t ArrayElementSize() const {
802 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
803 return vtable->Mapping > 0 ? size_t( vtable->Mapping )
804 : 0;
805 }
806
807 /// Returns the pointer to the first array element.
808 ///
809 /// \note
810 /// With debug-builds, it is \ref ALIB_ASSERT_ERROR "asserted" that #IsArray
811 /// returns \c true and the stored type is the same as requested.
812 /// In release compilations, no checks are performed!
813 ///
814 /// @tparam TElementType The type of array elements
815 /// @return A pointer to the first array element.
816 template <typename TElementType>
817 TElementType* UnboxArray() const {
818 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior.")
819 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
820 "Box::UnboxArray() invoked on box of non-array type <{}>.", &vtable->Type )
821
822 ALIB_ASSERT_ERROR( typeid(TElementType) == vtable->ElementType,
823 "BOXING: Cannot unbox array type<{}[]> from mapped type<{}[]>.",
824 &typeid(TElementType*), &vtable->ElementType )
825
827 return data.GetPointer<TElementType>();
828 }
829
830 /// Returns the length of a boxed Array. While in theory, the length applies only to
831 /// arrays, in debug-compilations, \b no run-time type check is performed.
832 /// This way, mapped types that use the second "word" of the placeholder to store a
833 /// value of type \c integer, may also use this function.<br>
834 /// In the latter case, the name of this method might be misleading and therefore, it is
835 /// recommended to use <b>Data().integer[1]</b> to denote that a custom interpretation of the
836 /// placeholder is performed. The compilation result is the same.
837 ///
838 /// Some quick rationale for why \alib is generally using signed types for array lengths,
839 /// is given \ref alib_strings_details_signedlength "here".
840 ///
841 /// @return The length of the boxed object.
843 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Cannot access placeholder." )
844 return data.GetLength();
845 }
846
847 /// Returns a reference to element \p{idx} of the boxed array.
848 ///
849 /// \note
850 /// With debug-builds, it is \ref alib_mod_assert "asserted" that #IsArray returns
851 /// \c true, that the stored type is the same as the requested type and the provided
852 /// \p{idx} is between \c 0 and the length of the array.
853 /// In release compilations, no checks are performed!
854 ///
855 /// @tparam TElementType The type of array elements
856 /// @param idx The index of the element to receive.
857 /// @return The value of the element at \p{idx}.
858 template <typename TElementType>
859 TElementType& UnboxElement(integer idx) const {
860 ALIB_ASSERT_ERROR( vtable, "BOXING",
861 "Box is void (no contents). Unboxing is undefined behavior." )
862 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
863 "Box::UnboxElement() invoked on box of non-array type <{}>.", &vtable->Type )
864
865 ALIB_ASSERT_ERROR( typeid(TElementType) == vtable->ElementType,
866 "BOXING: Cannot unbox array element type <{}> from mapped type <{}[]>.",
867 &typeid(TElementType), &vtable->ElementType )
868
869 ALIB_ASSERT_ERROR( idx >= 0 && idx < UnboxLength(), "BOXING",
870 "Box::UnboxElement<{}>(): Index out of bounds.", &typeid(TElementType))
871
873
874 return *( data.GetPointer<TElementType>() + idx );
875 }
876
877 #if DOXYGEN
878 /// Searches an implementation of a box-function identified by template parameter
879 /// \p{TFDecl}, which has to be implemented according the rules of
880 /// \ref alib_boxing_functions_concepts_decl "function declarations".<br>
881 /// If found, a <em>non-nulled</em> function pointer is returned, otherwise a \e nulled one.
882 ///
883 /// On success, the function can be invoked by passing the returned pointer to method
884 /// #CallDirect.
885 /// This approach avoids further searches that are otherwise to be performed with multiple
886 /// invocations of method #Call.
887 ///
888 /// If parameter \p{defaults} equals \alib{lang;Reach::Local}, functions specific to the mapped
889 /// type of this box (registered using \alib{boxing;BootstrapRegister}) are searched.
890 /// If \alib{lang;Reach::Global} is given, then a defaulted function (registered using
891 /// \alib{boxing;BootstrapRegisterDefault}) is searched, if no specific function was found.
892 ///
893 /// \note
894 /// \alib{lang;Reach::Local} can be used to detect specific behavior and to avoid the use
895 /// of default functions. This can be useful if the default implementation of a function
896 /// is just not applicable in a certain situation.
897 ///
898 /// \note
899 /// A second use case of this method are situations where multiple invocations of the
900 /// same function are to be done, on just one or on several boxes of the same mapped type:
901 ///
902 /// assert( box1.IsSameType( box2 ) );
903 ///
904 /// auto* func= box1.GetFunction<FMyFunc>( Reach::Global );
905 /// if( func != nullptr )
906 /// for( int i= 0; i< 10; ++i )
907 /// {
908 /// box1.CallDirect<FMyFunc>( func, i );
909 /// box2.CallDirect<FMyFunc>( func, i );
910 /// }
911 ///
912 /// @tparam TFDecl The \ref alib_boxing_functions_concepts_decl "function declaration"
913 /// to search for.
914 /// @param searchScope \alib{lang;Reach::Local} chooses type-specific functions only, while.
915 /// \alib{lang;Reach::Global} includes default functions in the search.
916 /// @param isInvocation Available only in debug compilations. If \c true, a counter
917 /// associated with an implementation found is increaed to provide
918 /// statistics. Defaults to false and should not be given.
919 /// @return The function implementation.
920 /// \c nullptr in case that no function is available.
921 template <typename TFDecl>
922 inline
923 typename TFDecl::Signature GetFunction( Reach searchScope
924 , bool isInvocation = false ) const;
925 #else
926 template <typename TFDecl>
927 typename TFDecl::Signature GetFunction( lang::Reach searchScope
928 ALIB_DBG( , bool isInvocation = false) ) const {
929 if( !vtable )
930 return nullptr;
931
932 ALIB_DBG( ++vtable->DbgCntUsage );
933
934 auto result= vtable->Functions.Get<TFDecl>( ALIB_DBG(isInvocation) );
935 return result
936 ? result
937 : searchScope == lang::Reach::Global
938 ? detail::DEFAULT_FUNCTIONS.Get<TFDecl>( ALIB_DBG(isInvocation) )
939 : nullptr;
940 }
941 #endif //DOXYGEN
942
943
944
945 /// Invokes a function registered for boxes of the mapped type.
946 /// The \ref alib_boxing_functions_concepts_decl "function declaration" is provided with the
947 /// first template parameter \p{TFDecl}.
948 /// The further variadic template parameters do not need to be specified.
949 /// They specify the types of the called function's parameters and are matched against
950 /// the function signature given with the declaration.
951 /// If the types of the given function arguments do not correspond to the types of
952 /// the box-function called, a compile-time error is raised.
953 ///
954 /// \note
955 /// Precisely, the variadic template types denote the function arguments starting from the
956 /// second, as the first argument is always a reference to the box that this method was
957 /// invoked on.
958 ///
959 /// If no corresponding function \alib{boxing;BootstrapRegister;was registered} for the mapped
960 /// type, then a \alib{boxing;BootstrapRegisterDefault;default function}, that is applicable
961 /// to any mapped type is searched.
962 /// If neither is found, a default value of the return type of the function is returned.
963 ///
964 /// With debug-builds, an \ref alib_mod_assert "error is raised" if the function type is not
965 /// known at all to \alib_boxing_nl. This is true, if an implementation was neither registered with
966 /// any other mapped type, nor registered as a default.
967 ///
968 /// \see
969 /// Description of method #GetFunction to implement two use cases:
970 /// - Repetitive invocation of the same function.
971 /// - Avoidance of default functions
972 ///
973 /// \see
974 /// A non-constant overload exists, for the seldom case the reference to this box that is
975 /// passed to the function, needs to be of non-constant type.
976 ///
977 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
978 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
979 /// @param args Variadic arguments forwarded to the function.
980 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
981 /// respectively <c>TReturn()</c> if the requested function type was not found for
982 /// this \b %Box.
983 template <typename TFDecl, typename... TArgs>
984 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
985 Call(TArgs&&... args) const {
986 auto* func= GetFunction<TFDecl>( lang::Reach::Global ALIB_DBG(, true) );
987 if( func != nullptr )
988 return reinterpret_cast<typename TFDecl::Signature>(func)
989 ( *this, std::forward<TArgs>(args)... );
990
991
992 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
993 std::declval<TArgs>()... )) ();
994 }
995
996 /// Alternative version of method #Call, which accepts the function's pointer as a first
997 /// argument. Such a pointer can be received upfront with method #GetFunction.
998 ///
999 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
1000 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1001 /// @param args Variadic arguments forwarded to the function.
1002 /// @param function The function to invoke.
1003 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1004 /// respectively <c>TReturn()</c> if the requested function type was not found for
1005 /// this \b %Box.
1006 template <typename TFDecl, typename... TArgs>
1007 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1008 CallDirect(typename TFDecl::Signature function, TArgs&&... args) const {
1009 ALIB_ASSERT_ERROR( vtable, "BOXING",
1010 "Box not initialized (does not contain value). Function call not allowed." )
1011 return reinterpret_cast<typename TFDecl::Signature>(function)
1012 ( *this, std::forward<TArgs>(args)... );
1013 }
1014
1015 /// Same as method #Call, but usable with interfaces that only accept a mutable
1016 /// (aka not constant) box. Technically, the only difference between this method and \b Call
1017 /// is that the latter is declared \c const.
1018 ///
1019 /// \note
1020 /// The only built-in boxing function that requires a mutable reference
1021 /// to a box, is function \alib{boxing;FClone}. This modifies the contents
1022 /// of a box by performing deep copies, with the goal to
1023 /// \ref alib_boxing_more_iclone "extent the lifecylce of boxes".
1024 ///
1025 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
1026 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1027 /// @param args Variadic arguments forwarded to the function.
1028 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1029 /// respectively <c>TReturn()</c> if the requested function type was not found for
1030 /// this \b %Box.
1031 template <typename TFDecl, typename... TArgs>
1032 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1033 Call(TArgs&&... args) {
1034 ALIB_ASSERT_ERROR( vtable, "BOXING",
1035 "Box not initialized (does not contain value). Function call not allowed." )
1036 auto* func= GetFunction<TFDecl>( lang::Reach::Global ALIB_DBG(, true));
1037 if( func != nullptr )
1038 return reinterpret_cast<typename TFDecl::Signature>(func)
1039 ( *this, std::forward<TArgs>(args)... );
1040
1041 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
1042 std::declval<TArgs>()... )) ();
1043 }
1044
1045 /// Alternative version of non-constant version of method #Call, which accepts the function's
1046 /// pointer as a first argument.
1047 /// Such a pointer can be received upfront with the method #GetFunction.
1048 ///
1049 /// @tparam TFDecl The function type to call. Has to be explicitly specified.
1050 /// @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1051 /// @param args Variadic arguments forwarded to the function.
1052 /// @param function The function to invoke.
1053 /// @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1054 /// respectively <c>TReturn()</c> if the requested function type was not found for
1055 /// this \b %Box.
1056 template <typename TFDecl, typename... TArgs>
1057 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1058 CallDirect(typename TFDecl::Signature function, TArgs &&... args) {
1059 ALIB_ASSERT_ERROR( vtable, "BOXING",
1060 "Box not initialized (does not contain value). Function call not allowed." )
1061 return reinterpret_cast<typename TFDecl::Signature>( function )
1062 ( *this, std::forward<TArgs>(args)... );
1063 }
1064
1065 /// Comparison operator. Returns the result of invocation of built-in boxing function
1066 /// \alib{boxing;FEquals}.
1067 ///
1068 /// @param rhs The right-hand side argument of the comparison.
1069 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
1070 ALIB_DLL
1071 bool operator==(Box const& rhs) const;
1072
1073 /// Comparison operator. Returns the negated result of #operator==.
1074 ///
1075 /// @param rhs The right-hand side argument of the comparison.
1076 /// @return \c true if this object equals \p{rhs}, \c false otherwise.
1077 bool operator!=(const Box& rhs) const { return ! ((*this) == rhs); }
1078
1079 /// Comparison operator. Returns the result of invocation of built-in box-function
1080 /// \alib{boxing;FIsLess}.
1081 ///
1082 /// \see
1083 /// Sample code provided with documentation of box-function \alib{boxing;FIsLess}.
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. Uses a combination of \c operator< and \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 ALIB_DLL
1095 bool operator<=(Box const& rhs) const;
1096
1097 /// Comparison operator. Uses a combination of \c operator< and \c operator==.
1098 ///
1099 /// @param rhs The right-hand side argument of the comparison.
1100 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1101 ALIB_DLL
1102 bool operator> (Box const& rhs) const;
1103
1104 /// Comparison operator. Returns the negated result of \c operator<.
1105 ///
1106 /// @param rhs The right-hand side argument of the comparison.
1107 /// @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1108 bool operator>= (Box const& rhs) const { return !( (*this) < rhs); }
1109
1110 /// Explicit cast operator to \c bool. Returns the result of built-in box-function
1111 /// \alib{boxing;FIsTrue}.
1112 ///
1113 /// @return \c true if the boxed value <em>represents value true</em>, \c false otherwise.
1114 ALIB_DLL
1115 explicit operator bool() const;
1116
1117
1118 /// Returns the result of a call to built-in boxing function \alib{boxing;FIsNotNull}.
1119 ///
1120 /// @return \c false if this object represents a \e nulled object, \c true otherwise.
1121 ALIB_DLL
1122 bool IsNotNull() const;
1123
1124 /// Returns the negated result of a call to built-in boxing function
1125 /// \alib{boxing;FIsNotNull}.
1126 ///
1127 /// @return \c true if this object represents a \e nulled object, \c false otherwise.
1128 bool IsNull() const { return !IsNotNull(); }
1129
1130 /// Returns the result of invocation of built-in boxing function \alib{boxing;FHashcode}.
1131 ///
1132 /// @return A hashcode for the boxed type and value.
1133 ALIB_DLL size_t Hashcode() const;
1134
1135 #if ALIB_MONOMEM
1136 /// Returns the result of invocation of built-in boxing function \alib{boxing;FHashcode}.
1137 ///
1138 /// \par Availability
1139 /// This method is available only if the module \alib_monomem is included in the \alibbuild.
1140 /// @param memory A monotonic allocator used for storing cloned data.
1142 #endif
1143
1144}; // class Box
1145
1146} // namespace alib[::boxing]
1147
1148/// Type alias in namespace \b alib.
1150} // namespace [alib]
1151
1154
1155#include "ALib.Lang.CIFunctions.H"
1156ALIB_EXPORT namespace alib::boxing {
1157//==================================================================================================
1158/// Registers \ref alib_boxing_functions "box-function" \p{function} of type \p{TFDecl} for
1159/// boxes of mapped type \p{TMapping}.
1160///
1161/// \attention
1162/// Function registration and function invocation are not protected against racing conditions
1163/// of multithreaded access. For this reason, it is advised to invoke this function exclusively
1164/// while \ref alib_mod_bs "bootstrapping" software, when no threads are started,
1165/// yet. Registrations can be made before bootstrapping \alib, respectively during or after
1166/// phase \alib{BootstrapPhases::PrepareResources}.
1167///
1168/// \attention
1169/// If for any reason registration is performed \b after bootstrapping \alib and module
1170/// \alib_monomem is included in the \alibbuild, and this function is invoked after
1171/// \alib was bootstrapped, then before an invocation of this method, mutex
1172/// \alib{monomem;GLOBAL_ALLOCATOR_LOCK} has to be acquired. This can be done with:
1173/// \snippet "ut_monomem.cpp" DOX_MONOMEM_LOCK_GLOBALALLOCATOR
1174///
1175/// \attention
1176/// Note that even when this lock is set, still multithreaded access to registration and/or
1177/// box-function invocations is <b>not allowed</b>.
1178///
1179/// @tparam TFDecl The \ref alib_boxing_functions_concepts_decl "type of function" to register.
1180/// @tparam TMapped The mapped type that boxes store, which are to be equipped with a specialized
1181/// function implementation.
1182/// @tparam TIsArray Denotes whether array-boxing is applied. Defaults to \c false.
1183/// @param function Pointer to the function implementation.
1184//==================================================================================================
1185template<typename TFDecl, typename TMapped, bool TIsArray= false>
1186inline
1187void BootstrapRegister( typename TFDecl::Signature function ) {
1190 ->Functions.template Get<TFDecl>(false),
1191 "BOXING", "Doubly defined function" )
1192
1194 ->Functions.template Set<TFDecl>( function );
1195}
1196
1197//==================================================================================================
1198/// Registers a default implementation of a \ref alib_boxing_functions "box-function", which
1199/// is invoked if no type-specific implementation is registered for a mapped type.
1200///
1201/// \attention
1202/// Function registration and function invocation are not protected against racing conditions
1203/// of multithreaded access. For this reason, it is advised to invoke this function exclusively
1204/// while \ref alib_mod_bs "bootstrapping" software, when no threads are started,
1205/// yet. Registrations can be made before bootstrapping \alib, respectively during or after
1206/// phase \alib{BootstrapPhases::PrepareResources}.
1207///
1208/// \attention
1209/// If for any reason registration is performed \b after bootstrapping \alib and module
1210/// \alib_monomem is included in the \alibbuild, and this function is invoked after
1211/// \alib was bootstrapped, then, before an invocation of this method, mutex
1212/// \alib{monomem;GLOBAL_ALLOCATOR_LOCK} has to be acquired. This can be done with:
1213/// \snippet "ut_monomem.cpp" DOX_MONOMEM_LOCK_GLOBALALLOCATOR
1214///
1215/// \attention
1216/// Note that even when this lock is set, still multithreaded access to registration and/or
1217/// box-function invocations is <b>not allowed</b>.
1218///
1219/// @tparam TFDecl The \ref alib_boxing_functions_concepts_decl "type of function" to register.
1220/// @param function Pointer to the function's default implementation.
1221//==================================================================================================
1222template<typename TFDecl>
1223inline
1224void BootstrapRegisterDefault( typename TFDecl::Signature function )
1225{ detail::DEFAULT_FUNCTIONS.Set<TFDecl>( function ); }
1226} // namespace [alib::boxing]
detail::VTable * vtable
Definition box.inl:37
ALIB_DLL bool operator>(Box const &rhs) const
Definition box.cpp:181
TElementType & UnboxElement(integer idx) const
Definition box.inl:859
uinteger UnboxUnsignedIntegral() const
Definition box.inl:483
const detail::VTable * DbgGetVTable() const
Definition box.inl:381
uinteger TypeCode
The type of type codes received with ExportType.
Definition box.inl:219
bool IsUnsignedIntegral() const
Definition box.inl:459
const std::remove_pointer_t< TPointer > * Unbox() const
Definition box.inl:662
ALIB_DLL double UnboxFloatingPoint() const
Definition box.cpp:150
ALIB_DLL bool IsNotNull() const
Placeholder data
The data that we encapsulate.
Definition box.inl:40
const std::type_info & ElementTypeID() const
Definition box.inl:792
Box(TypeCode typeCode, const Placeholder &placeholder) noexcept
Definition box.inl:230
integer UnboxSignedIntegral() const
Definition box.inl:471
bool operator!=(const Box &rhs) const
Definition box.inl:1077
bool IsFloatingPoint() const
Definition box.cpp:139
TypeCode ExportType() const
Definition box.inl:731
void Import(TypeCode typeCode)
Definition box.inl:747
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:1008
bool IsSameType(const Box &other) const
Definition box.inl:580
ALIB_DLL void Clone(MonoAllocator &memory)
bool operator>=(Box const &rhs) const
Definition box.inl:1108
bool IsArrayOf() const
Definition box.inl:557
bool IsPointer() const
Definition box.inl:565
Placeholder ExportValue() const
Definition box.inl:742
bool IsEnum() const
Definition box.inl:572
void Import(TypeCode typeCode, const Placeholder &placeholder)
Definition box.inl:758
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.inl:985
constexpr Box(const TBoxable &src) noexcept
TPointer UnboxMutable() const
Definition box.inl:684
bool IsType() const
TValue Unbox() const
Definition box.inl:595
size_t ArrayElementSize() const
Definition box.inl:801
const std::type_info & TypeID() const
Definition box.inl:780
bool IsArray() const
Definition box.inl:549
const Placeholder & Data() const
Definition box.inl:692
ALIB_DLL bool operator<(Box const &rhs) const
Definition box.cpp:179
TValue Unbox() const
Definition box.inl:632
bool IsCharacter() const
Definition box.inl:503
TElementType * UnboxArray() const
Definition box.inl:817
static constexpr detail::VTable * getVTable()
Definition box.inl:194
integer UnboxLength() const
Definition box.inl:842
ALIB_DLL bool operator==(Box const &rhs) const
Definition box.cpp:178
bool IsSignedIntegral() const
Definition box.inl:446
ALIB_DLL bool operator<=(Box const &rhs) const
Definition box.cpp:180
unsigned GetPlaceholderUsageLength() const
Definition box.inl:722
Placeholder & Data()
Definition box.inl:706
wchar UnboxCharacter() const
Definition box.inl:515
TFDecl::Signature GetFunction(Reach searchScope, bool isInvocation=false) const
Box() noexcept
Definition box.inl:224
bool IsNull() const
Definition box.inl:1128
ALIB_DLL size_t Hashcode() const
#define ALIB_DLL
Definition alib.inl:503
#define ALIB_TVALUE(T)
Definition alib.inl:1003
#define ALIB_EXPORT
Definition alib.inl:497
#define ALIB_DBG(...)
Definition alib.inl:853
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1066
ALIB_DLL 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:1224
void BootstrapRegister(typename TFDecl::Signature function)
Definition box.inl:1187
Reach
Denotes the reach of something.
@ Global
Denotes global reach.
characters::wchar wchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.inl:149
monomem::TMonoAllocator< lang::HeapAllocator > MonoAllocator
characters::nchar nchar
Type alias in namespace alib.
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1149
characters::xchar xchar
Type alias in namespace alib.
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.inl:152
static std::conditional_t<!std::is_abstract< TBoxable >::value, TBoxable, TBoxable & > Read(const Placeholder &box)
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