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