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