ALib C++ Library
Library Version: 2402 R1
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-2024 A-Worx GmbH, Germany.
6 * Published under \ref mainpage_license "Boost Software License".
7 **************************************************************************************************/
8#ifndef HPP_ALIB_BOXING_BOX
9#define HPP_ALIB_BOXING_BOX 1
10
11#if !defined(HPP_ALIB_BOXING_BOXING)
12# error "ALib sources with ending '.inl' must not be included from outside."
13#endif
14
15#if ALIB_DEBUG && !defined(HPP_ALIB_LANG_DBGTYPEDEMANGLER)
17#endif
18
19namespace alib { namespace boxing {
20
21/** ************************************************************************************************
22 * This is the central class of \alib_boxing_nl . By using template meta programming, an object
23 * of this class can be created by passing just any C++ type to the constructor. The passed
24 * value will be "boxed" within the instance of this class.
25 *
26 * Then, the instances of this class support type checking, value extraction ("unboxing") and the
27 * invocation of "virtual methods". All features are customizable in detail per "boxable type".
28 *
29 * A thorough introduction to and documentation of all aspects of \alib_boxing_nl is given
30 * with Programmer's Manual \alib_boxing.
31 *
32 * ## Functors In Namespace std ##
33 * Functors <c>std::hash</c>, <c>std::equal_to</c> and <c>std::less</c> are specialized for
34 * this type with the inclusion of header file \alibheader{compatibility/std_boxing_functional.hpp}
35 * as documented with namespace #alib::compatibility::std.
36 **************************************************************************************************/
37class Box
38{
39 // #############################################################################################
40 // protected fields and methods
41 // #############################################################################################
42 protected:
43
44 /**
45 * The singleton of a class derived from class \b %VTable which defines our type and
46 * behavior.
47 */
49
50 /** The data that we encapsulate. */
52
53
54 // #########################################################################################
55 // Two local macro that check whether TBoxable is a valid type to box, respectively unbox.
56 // For this, various different cases are (redundantly) checked to produce compiler
57 // errors that provide all necessary information about why the operation can not be
58 // performed.
59 // Note: Using an empty templated method for this, produced the static assertion only after
60 // other compiler errors. Therefore, a macro is used.
61 // #########################################################################################
62
63#if !defined(ALIB_DOX)
64 #define ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING(TBoxable, TClean) \
65 using TVal = typename std::remove_pointer<ATMP_RCVR(TBoxable)>::type; \
66 using TPtr = TVal*; \
67 constexpr bool valueBoxing = !ATMP_IS_PTR(TClean); \
68 constexpr bool isVolatile = std::is_volatile<ATMP_RP(TBoxable)>::value; \
69 constexpr bool isPointer = std::is_pointer<TBoxable>::value; \
70 constexpr bool isValue = !isPointer; \
71 constexpr bool isCustomizedTV= TT_IsCustomized<TVal>::value; \
72 constexpr bool isCustomizedTP= TT_IsCustomized<TPtr>::value; \
73 constexpr bool isBlockedTV = ATMP_EQ( detail::TNotBoxable, typename T_Boxer<TVal>::Mapping::Type ); \
74 constexpr bool isBlockedTP = ATMP_EQ( detail::TNotBoxable, typename T_Boxer<TPtr>::Mapping::Type ); \
75 \
76 ALIB_STATIC_DENY( GeneralBoxingRule1, !valueBoxing && isVolatile, \
77 "Types boxed as pointers can not be boxed if volatile." ); \
78 \
79 ALIB_STATIC_DENY( CustomBoxingRule3, isBlockedTV && isValue, \
80 "Customized boxing forbids boxing this value type: " \
81 "'T_Boxer<T>::Type == NotBoxable'!" ); \
82 \
83 ALIB_STATIC_DENY( CustomBoxingRule4, isBlockedTP && isPointer, \
84 "Customized boxing forbids boxing this pointer type: " \
85 "'T_Boxer<T*>::Type == NotBoxable'!" ); \
86 \
87 ALIB_STATIC_DENY( CustomBoxingRule5, isBlockedTV && !isCustomizedTP && isPointer, \
88 "Customized boxing forbids boxing value type T (T_Boxer<T>::Type == NotBoxable), while " \
89 "no customization for this pointer type T* was given." ); \
90 \
91 ALIB_STATIC_DENY( CustomBoxingRule6, isBlockedTP && !isCustomizedTV && isValue, \
92 "Customized boxing forbids boxing pointer type T* " \
93 "(T_Boxer<T*>::Type == NotBoxable), while no customization for this value type T was " \
94 "given. " ); \
95 \
96
97 // check IsType/Unbox
98 #define ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING(TUnboxable) \
99 using T = ATMP_RCVR(TUnboxable); \
100 using TVal = typename std::remove_pointer<T>::type; \
101 using TPtr = TVal*; \
102 constexpr bool isConst = std::is_const <ATMP_RP(TUnboxable)>::value; \
103 constexpr bool isVolatile = std::is_volatile<ATMP_RP(TUnboxable)>::value; \
104 constexpr bool isPointer = std::is_pointer<TUnboxable>::value; \
105 constexpr bool isValue = !isPointer; \
106 constexpr bool valuesFit = sizeof(ATMP_IF_T_F(ATMP_EQ(void,TVal), void*,TVal)) \
107 <= sizeof(Placeholder); \
108 constexpr bool isConstructible= std::is_copy_constructible<TVal>::value; \
109 constexpr bool isTriviallyDest= std::is_trivially_destructible<TVal>::value; \
110 constexpr bool isCustomizedTV = TT_IsCustomized<TVal>::value; \
111 constexpr bool isCustomizedTP = TT_IsCustomized<TPtr>::value; \
112 constexpr bool isDefault = !(isCustomizedTV || isCustomizedTP); \
113 constexpr bool isBlockedTV = ATMP_EQ( detail::TNotBoxable, typename T_Boxer<TVal>::Mapping::Type ); \
114 constexpr bool isBlockedTP = ATMP_EQ( detail::TNotBoxable, typename T_Boxer<TPtr>::Mapping::Type ); \
115 constexpr bool isLockedTV = TT_IsLocked<TVal>::value; \
116 constexpr bool isLockedTP = TT_IsLocked<TPtr>::value; \
117 \
118 /* Redundant type qualifiers */ \
119 ALIB_STATIC_DENY( GeneralBoxingRule2, isConst, \
120 "Type qualifier 'const' not allowed with template type TUnboxable. Types boxed as values"\
121 " are always unboxed mutable, types boxed as pointers are always unboxed constant." ); \
122 \
123 ALIB_STATIC_DENY( GeneralBoxingRule3, isVolatile, \
124 "Type qualifier 'volatile' not allowed with template type TUnboxable" ); \
125 \
126 /* Default boxing */ \
127 ALIB_STATIC_DENY( DefaultBoxingRule1, isDefault && isValue && !valuesFit, \
128 "This type can not be unboxed by value: " \
129 "By default, values that do not fit into boxes are boxed as pointers." ); \
130 \
131 ALIB_STATIC_DENY( DefaultBoxingRule2, \
132 isDefault && isValue && (!isConstructible || !isTriviallyDest), \
133 "This type can not be unboxed by value: " \
134 "By default, types that are not copy constructible or not trivially destructible, " \
135 "are boxed as pointers." ); \
136 \
137 ALIB_STATIC_DENY( DefaultBoxingRule3, \
138 isDefault && isPointer && valuesFit && isConstructible && isTriviallyDest, \
139 "This type can not be unboxed as pointer: Default boxing of types that fit " \
140 "into boxes and are copy constructible and trivially destructible, " \
141 "is performed by value." ); \
142 \
143 \
144 /* Custom boxing */ \
145 ALIB_STATIC_DENY( CustomBoxingRule1, isCustomizedTV && !isCustomizedTP && isPointer, \
146 "This pointer type T* can not be unboxed, because custom boxing is defined for " \
147 "value type T, while no custom boxing is defined for pointer type T*." ); \
148 \
149 ALIB_STATIC_DENY( CustomBoxingRule2, !isCustomizedTV && isCustomizedTP && isValue, \
150 "This value type T can not be unboxed, because custom boxing is defined for " \
151 "pointer type T*, while no custom boxing is defined for value type T." ); \
152 \
153 \
154 /* Boxing blocked */ \
155 ALIB_STATIC_DENY( CustomBoxingRule3, isBlockedTV && isValue, \
156 "Customized boxing forbids unboxing (and even boxing) this value type: " \
157 "'T_Boxer<T>::Type == NotBoxable'!" ); \
158 \
159 ALIB_STATIC_DENY( CustomBoxingRule4, isBlockedTP && isPointer, \
160 "Customized boxing forbids unboxing (and even boxing) this pointer type: " \
161 "'T_Boxer<T*>::Type == NotBoxable'!" ); \
162 \
163 ALIB_STATIC_DENY( CustomBoxingRule5, isBlockedTV && !isCustomizedTP && isPointer, \
164 "Customized boxing forbids unboxing (and even boxing) value type T " \
165 "(T_Boxer<T>::Type == NotBoxable), while no customization for this pointer type T* " \
166 "was given." ); \
167 \
168 ALIB_STATIC_DENY( CustomBoxingRule6, isBlockedTP && !isCustomizedTV && isValue, \
169 "Customized boxing forbids unboxing (and even boxing) pointer type T* " \
170 "(T_Boxer<T*>::Type == NotBoxable), while no customization for this value type T was" \
171 "given." ); \
172 \
173 /* Unboxing locked */ \
174 ALIB_STATIC_DENY( CustomBoxingRule7, isLockedTV && isValue, \
175 "Customized boxing forbids unboxing this value type: " \
176 "'T_Boxer<T>::Read' returns a different type." ); \
177 \
178 ALIB_STATIC_DENY( CustomBoxingRule8, isLockedTP && isPointer, \
179 "Customized boxing forbids unboxing this pointer type: " \
180 "'T_Boxer<T*>::Read' returns a different type." ); \
181 \
182 ALIB_STATIC_DENY( CustomBoxingRule9, isLockedTV && !isCustomizedTP && isPointer, \
183 "Customized boxing forbids unboxing value type T " \
184 "('T_Boxer<T>::Read' returns a different type), while no customization for this pointer "\
185 "type T* was given." ); \
186 \
187 ALIB_STATIC_DENY( CustomBoxingRule10, isLockedTP && !isCustomizedTV && isValue, \
188 "Customized boxing forbids unboxing pointer type T* " \
189 "('T_Boxer<T*>::Read' returns a different type), while no customization for this value " \
190 "type T was given." ); \
191
192#endif // !defined(ALIB_DOX)
193
194 #if defined(ALIB_DOX)
195 /**
196 * Shortcut inline method to retrieve the vtable singleton for the template type.
197 * In debug-compilations, the received \e vtable is checked for being registered.
198 *
199 * @tparam TBoxable The source type to receive the vtable for.
200 * @return The vtable singleton.
201 */
202 template<typename TBoxable, bool NoStaticAsserts= false>
203 static inline
205 #else
206
207
208 template<typename TBoxable>
210 static
211 constexpr
213 {
218 >::Get();
219 }
220
221 #endif // defined(ALIB_DOX)
222
223 // #############################################################################################
224 // Constructors
225 // #############################################################################################
226 public:
227
228 /** ****************************************************************************************
229 * Default constructor.<br>
230 * After creation with this constructor, a call to #IsType<void> returns true.
231 * To reset an instance previously used, assign keyword \c nullptr.
232 ******************************************************************************************/
233 constexpr
235 : vtable( nullptr )
236 , data()
237 {}
238
239
240 /** ****************************************************************************************
241 * Trivial default copy constructor.
242 ******************************************************************************************/
243 Box( const Box& ) noexcept = default;
244
245 /** ****************************************************************************************
246 * Trivial default move constructor.
247 ******************************************************************************************/
249
250 /** ****************************************************************************************
251 * Trivial default copy assign operator.
252 * @return A reference to \c this.
253 ******************************************************************************************/
255
256 /** ****************************************************************************************
257 * Trivial default move assign operator.
258 * @return A reference to \c this.
259 ******************************************************************************************/
261
262 /** ****************************************************************************************
263 * Trivial default destructor.
264 ******************************************************************************************/
266
267
268
269 #if defined(ALIB_DOX)
270 /** ****************************************************************************************
271 * Constructor using template meta programming to fetch any type of C++ value.<br>
272 * Internally, this constructor is implemented using a set of different constructors
273 * which are selected by the compiler using \c std::enable_if conditions.
274 *
275 * Types derived from class \b %Box itself are boxed by coping the internal values
276 * of the box. This means, that boxing objects of derived types is similar to
277 * "downcasting" the object to class \b %Box.
278 *
279 * @tparam TBoxable Any C++ type to be boxed.
280 * @param src The src value or pointer type \c T.
281 ******************************************************************************************/
282 template <typename TBoxable>
283 inline constexpr Box(const TBoxable& src ) noexcept;
284 #else
285 // ################################## Special types #######################################
286
287 // Keyword 'nullptr'
288 ATMP_SELECT_IF_1TP( typename TNullptr, std::is_same<std::nullptr_t, TNullptr>::value )
289 constexpr
290 Box(const TNullptr& ) noexcept
291 : vtable(nullptr)
292 , data ()
293 {}
294
295
296 // C++ arrays
297 ATMP_SELECT_IF_1TP( typename T, ATMP_IS_ARR(ATMP_RCV(T)) )
298 constexpr
299 Box( T& src ) noexcept
301 , data ( &src, static_cast<integer>( std::is_same<ATMP_RECVP(T), char >::value
302 || std::is_same<ATMP_RECVP(T), wchar_t >::value
303 || std::is_same<ATMP_RECVP(T), char16_t>::value
304 || std::is_same<ATMP_RECVP(T), char32_t>::value
305 ? std::extent<ATMP_RCVP(T)>::value - 1
306 : std::extent<ATMP_RCVP(T)>::value ) )
307 {}
308
309
310 // Derived Box value types (Box itself uses built-in copy constructor)
311 // note: references to Box are fetched with copy/move constructors
312 ATMP_SELECT_IF_1TP( typename T, !std::is_same <Box, ATMP_RCV(T)>::value
313 && std::is_base_of<Box, ATMP_RCV(T)>::value )
314 constexpr
315 Box(const T& src ) noexcept
316 : vtable( src.vtable )
317 , data ( src.data )
318 {}
319
320 // ######################## Boxing with T_Boxer #####################################
321
322 // 1) Value remains value
323 // 1.1) Customized with constexpr T_Boxer::Write
324 ATMP_SELECT_IF_1TP( typename T,
325 !ATMP_IS_PTR(T)
326 && ATMP_EQ(Placeholder, decltype( T_Boxer<ATMP_RCV(T)>::Write( std::declval<const ATMP_RCV(T)&>() ))) )
328 : vtable( getVTable<ATMP_RCV(T)>() )
329 , data ( T_Boxer <ATMP_RCV(T)>::Write( const_cast<ATMP_RCV(T) const &>( src ) ) )
330 {}
331
332 // 1.2) Default or customized with standard T_Boxer::Write
333 ATMP_SELECT_IF_1TP( typename T,
334 !ATMP_IS_PTR(T)
335 && !ATMP_EQ(std::nullptr_t,T)
336 && !ATMP_ISOF(T, Box)
337 && ( ( !TT_IsCustomized<ATMP_RCVR(T)*>::value
338 && sizeof(Placeholder) >= sizeof(ATMP_RCVP(T))
339 && std::is_copy_constructible <ATMP_RCVP(T)>::value
340 && std::is_trivially_destructible<ATMP_RCVP(T)>::value )
341 || TT_IsCustomized<ATMP_RCVR(T) >::value )
342 && ATMP_EQ(void, decltype( T_Boxer<ATMP_RCV(T)>::Write(data, std::declval<const ATMP_RCV(T)&>()) )))
343 Box(const T& src ) noexcept
344 : vtable( getVTable<ATMP_RCV(T)>() )
345 , data ()
346 {
348 T_Boxer<ATMP_RCV(T)>::Write( data, const_cast<ATMP_RCV(T) const &>( src ) );
349 }
350
351 // 2) Value converted to pointer
352 // 2.1) Default boxing as pointer (constexpr)
353 ATMP_SELECT_IF_1TP( typename T,
354 !ATMP_IS_PTR(T)
355 && !ATMP_EQ(std::nullptr_t,T)
356 && !ATMP_ISOF(T, Box)
357 && !TT_IsCustomized <ATMP_RCVR(T) >::value
358 && !TT_IsCustomized <ATMP_RCVR(T)*>::value
359 && !ATMP_IS_ARR(T)
360 && ( (sizeof(Placeholder) < sizeof(ATMP_RCVP(T)))
361 || !std::is_copy_constructible <ATMP_RCVP(T)>::value
362 || !std::is_trivially_destructible<ATMP_RCVP(T)>::value ) )
363 constexpr
364 Box(const T& src ) noexcept
365 : vtable( getVTable<ATMP_RCV(T)*>() )
366 , data ( Placeholder( &src ) )
367 {}
368
369 // 2.2) Customized pointer type with constexpr T_Boxer::Write
370 ATMP_SELECT_IF_1TP( typename T,
371 !ATMP_IS_PTR(T)
372 && !TT_IsCustomized <ATMP_RCVR(T) >::value
373 && ATMP_EQ(Placeholder, decltype( T_Boxer<ATMP_RCV(T)*>::Write( std::declval<ATMP_RCV(T)* const &>() ))) )
375 : vtable( getVTable<ATMP_RCV(T)*>() )
376 , data ( T_Boxer <ATMP_RCV(T)*>::Write( const_cast<ATMP_RCV(T)* const&>( &src ) ) )
377 {}
378
379 // 2.3) Customized with constexpr T_Boxer::Write
380 ATMP_SELECT_IF_1TP( typename T,
381 !ATMP_IS_PTR(T)
382 && !TT_IsCustomized <ATMP_RCVR(T) >::value
383 && TT_IsCustomized <ATMP_RCVR(T)*>::value
384 && ATMP_EQ(void, decltype( T_Boxer<ATMP_RCV(T)*>::Write(data, std::declval<ATMP_RCV(T)* const &>()) )))
385 Box(const T& src ) noexcept
386 : vtable( getVTable<ATMP_RCV(T)*>() )
387 , data ()
388 {
390 T_Boxer<ATMP_RCV(T)*>::Write( data, const_cast<ATMP_RCV(T)*>( &src ) );
391 }
392
393
394 // 3) Pointer remains pointer
395
396 // 3.1) No customization
398 ATMP_IS_PTR(T)
399 && !ATMP_ISOF(ATMP_RCVP(T), Box)
400 && !TT_IsCustomized<ATMP_RCVP(T)>::value
401 && !TT_IsCustomized<ATMP_RCVR(T)>::value
402 && ( (sizeof(Placeholder) < sizeof(ATMP_RCVP(T)))
403 || !std::is_copy_constructible <ATMP_RCVP(T)>::value
404 || !std::is_trivially_destructible<ATMP_RCVP(T)>::value ) )
406 : vtable( getVTable<ATMP_RCVP(T)*>() )
407 , data ( Placeholder( srcP ) )
408 {}
409
410 // 3.2) Customized with constexpr T_Boxer::Write, mutable pointer type
411 ATMP_SELECT_IF_1TP( typename T,
412 ATMP_IS_PTR(T)
413 && !std::is_const<T>::value
414 && ATMP_EQ(Placeholder, decltype( T_Boxer<ATMP_RCVP(T)*>::Write( std::declval<ATMP_RCVP(T)* const&>() ))) )
416 : vtable( getVTable<ATMP_RCVP(T)*>() )
417 , data ( T_Boxer <ATMP_RCVP(T)*>::Write( const_cast<ATMP_RCVP(T)* const &>( srcP ) ) )
418 {}
419
420
421 // 3.3) Customized with constexpr T_Boxer::Write, constant pointer type
422 ATMP_SELECT_IF_1TP( typename T,
423 ATMP_IS_PTR(T)
424 && std::is_const<ATMP_RP(T)>::value
425 && ATMP_EQ(Placeholder, decltype( T_Boxer<T>::Write( std::declval<T&>() ))) )
427 : vtable( getVTable<T>() )
428 , data ( T_Boxer <T>::Write( srcP ) )
429 {}
430
431 // 3.4) Customized with normal T_Boxer::Write
432 ATMP_SELECT_IF_1TP( typename T,
433 ATMP_IS_PTR(T)
434 && TT_IsCustomized <ATMP_RCVR(T)>::value
435 && ATMP_EQ(void, decltype( T_Boxer<ATMP_RCVP(T)*>::Write(data, std::declval<ATMP_RCVP(T)* const&>()) )))
437 : vtable( getVTable<ATMP_RCVP(T)*>() )
438 , data ()
439 {
441 T_Boxer<ATMP_RCVP(T)*>::Write( data, reinterpret_cast<ATMP_RCVP(T)*>( const_cast<ATMP_RCVP(T)*>(srcP) ) );
442 }
443
444
445
446 // 4) Pointer dereferenced to value
447 // 4.1) Customized with constexpr T_Boxer::Write
449 ATMP_IS_PTR(T)
450 && ( !std::is_const<ATMP_RP(T)>::value
451 || !ATMP_EQ(void, decltype( T_Boxer<ATMP_RCVP(T)*>::Write(data, std::declval<ATMP_RCVP(T)* const&>()) )) )
452 && ATMP_EQ(Placeholder, decltype( T_Boxer<ATMP_RCVP(T)>::Write( std::declval<const ATMP_RCVP(T)&>() ))) )
454 : vtable( getVTable<ATMP_RCVP(T)>() )
455 , data ( srcP ? T_Boxer <ATMP_RCVP(T)>::Write( const_cast<ATMP_RCVP(T) const &>( *srcP ) )
456 : (sizeof(ATMP_RCVP(T)) <= sizeof(integer) )
457 ? Placeholder( 0 )
458 : Placeholder( static_cast<integer>(0), static_cast<integer>(0) ) )
459 {}
460
461 // 4.2) Default or customized with normal T_Boxer::Write
462 ATMP_SELECT_IF_1TP( typename T,
463 ATMP_IS_PTR(T)
464 && !ATMP_ISOF(ATMP_RCVP(T), Box)
465 && !TT_IsCustomized<ATMP_RCVR(T) >::value
466 && ( TT_IsCustomized<ATMP_RCVP(T) >::value
467 || ( sizeof(Placeholder) >= sizeof( ATMP_RCVP(T) )
468 && std::is_copy_constructible <ATMP_RCVP(T)>::value
469 && std::is_trivially_destructible<ATMP_RCVP(T)>::value ) )
470 && ATMP_EQ(void, decltype( T_Boxer<ATMP_RCVP(T)>::Write(data, std::declval<const ATMP_RCVP(T)&>()) )))
472 : vtable( getVTable<ATMP_RCVP(T)>() )
473 , data ()
474 {
476
477 // cast needed to remove volatile, as allowed with values
478 if( srcP ) T_Boxer<ATMP_RCVP(T)>::Write( data, const_cast<ATMP_RCVP(T) const &>(*srcP) );
479 else data.Clear< ATMP_EQ( typename T_Boxer<ATMP_RCVP(T)>::Mapping::PlainOrArray, detail::TArrayOf )
480 ? sizeof(Placeholder)
481 : T_SizeInPlaceholder< ATMP_IF_T_F( ATMP_EQ( typename T_Boxer<ATMP_RCVP(T)>::Mapping::Type , detail::TDefaultBoxing )
482 , ATMP_RCVP(T)
483 , typename T_Boxer<ATMP_RCVP(T)>::Mapping::Type)
484 >::value
485 >();
486 }
487
488
489 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_BOXING
490 #undef ALIB_TM_IS_DEFAULT_BOXING
491
492 #endif // defined(ALIB_DOX)
493
494 // #############################################################################################
495 // Interface
496 // #############################################################################################
497 public:
498 #if ALIB_DEBUG
499 /**
500 * Returns the \e vtable of this instance that is associated with the currently boxed
501 * type.<br>
502 * Available only with debug builds.
503 *
504 * \see
505 * Manual chapter \ref alib_boxing_more_debug of the Programmer's Manual.
506 *
507 * @return The \e vtable of this instance.
508 */
510 {
511 return vtable;
512 }
513
514 #endif
515
516 #if defined(ALIB_DOX)
517 /** ****************************************************************************************
518 * Checks if this box stores a value of type \p{TBoxable}.
519 *
520 * If template parameter \p{TBoxable} it is not unboxable, a compile-time assertion
521 * is given, with specific guidance why the type must not be unboxed and for that
522 * reason must not even be tested for.
523 *
524 * Special type \c void may be given to test if this box does contain a value at all.
525 * A box does not contain a value, after
526 * - default construction,
527 * - construction with keyword \c nullptr, or
528 * - assignment of keyword \c nullptr.
529 *
530 * For more information on the "void state" of boxes, see manual chapter
531 * \ref alib_boxing_more_void.
532 *
533 *
534 * @tparam TBoxable The boxable type guessed.
535 * @return \c true if this box stores a value that is convertible to type \p{TBoxable},
536 * \c false otherwise.
537 ******************************************************************************************/
538 template<typename TBoxable>
539 inline
540 bool IsType() const;
541
542 #else
543
544 template<typename TBoxable>
545 ATMP_T_IF(bool, ATMP_EQ(TBoxable, void) )
546 IsType() const
547 {
548 return vtable == nullptr;
549 }
550
551 template<typename TBoxable>
552 ATMP_T_IF(bool, !ATMP_EQ(TBoxable, void))
553 IsType() const
554 {
556
557 return vtable == getVTable<TBoxable>();
558 }
559 #endif
560
561 #if !ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS || defined(ALIB_DOX)
562 /** ************************************************************************************
563 * Tests if this this box contains a signed integral type (one of the C++ fundamental
564 * types of different sizes).
565 *
566 * With compilation that disables
567 * \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
568 * simply returns <c>IsType<integer>()</c>.<br>
569 * Otherwise this method will not be inlined and tests for the five different
570 * integer sizes (\c int8_t, \c int16_t, \c int32_t, \c int64_t and \alib{intGap_t}).
571 *
572 * @return \c true if this box contains a signed integral type, \c false otherwise.
573 **************************************************************************************/
574 bool IsSignedIntegral() const
575 {
576 return IsType<integer >();
577 }
578
579 /** ************************************************************************************
580 * Tests if this this box contains an unsigned integral type (one of the C++ fundamental
581 * type of different sizes).
582 *
583 * With default library compilation that disables
584 * \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
585 * simply returns <c>IsType<uinteger>()</c>.<br>
586 * Otherwise this method will not be inlined and tests for the five different
587 * integer sizes (\c uint8_t, \c uint16_t, \c uint32_t, \c uint64_t and
588 * \alib{uintGap_t}).
589 *
590 * @return \c true if this box contains an unsigned integral type, \c false otherwise.
591 **************************************************************************************/
593 {
594 return IsType<uinteger>();
595 }
596
597 /** ************************************************************************************
598 * Unboxes a signed integral.
599 *
600 * With default library compilation that disables
601 * \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
602 * simply returns <c>Unbox<integer>()</c>.<br>
603 * Otherwise this method will not be inlined and tests for the five different
604 * integer sizes (1, 2, 4 and 8 bytes size and the #alib::intGap_t) prior to
605 * unboxing.
606 *
607 * @return The boxed signed integral value.
608 **************************************************************************************/
610 {
611 return Unbox<integer >();
612 }
613
614 /** ************************************************************************************
615 * Unboxes an unsigned integral.
616 *
617 * With default library compilation that disables
618 * \ref ALIB_FEAT_BOXING_BIJECTIVE_INTEGRALS, this method will be inlined and
619 * simply returns <c>Unbox<uinteger>()</c>.<br>
620 * Otherwise this method will not be inlined and tests for the five different
621 * integer sizes (1, 2, 4 and 8 bytes size and the #alib::uintGap_t) prior to
622 * unboxing.
623 *
624 * @return The boxed unsigned integral value.
625 **************************************************************************************/
627 {
628 return Unbox<uinteger >();
629 }
630 #else
631 ALIB_API bool IsSignedIntegral() const;
632 ALIB_API bool IsUnsignedIntegral() const;
635 #endif
636
637
638 #if !ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS || defined(ALIB_DOX)
639 /** ************************************************************************************
640 * Tests if this this box contains one of types \c char, \c wchar_t, \c char16_t or
641 * \c char32_t.
642 *
643 * With default library compilation that disables symbol
644 * \ref ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS, this method will be inlined and
645 * simply returns <c>IsType<wchar>()</c>.<br>
646 * Otherwise this method will not be inlined and tests for all four different
647 * character types.
648 *
649 * @return \c true if this box contains a character type, \c false otherwise.
650 **************************************************************************************/
651 bool IsCharacter() const
652 {
653 return IsType<wchar>();
654 }
655
656 /** ************************************************************************************
657 * Unboxes one of the types \c char, \c wchar_t, \c char16_t or \c char32_t
658 * and converts it to \alib{characters;wchar}.
659 *
660 * With default library compilation that disables
661 * \ref ALIB_FEAT_BOXING_BIJECTIVE_CHARACTERS, this method will be inlined and
662 * simply returns <c>Unbox<wchar>()</c>.<br>
663 * Otherwise this method will not be inlined and tests for the four different
664 * character types prior to unboxing.
665 *
666 * @return The stored character.
667 **************************************************************************************/
669 {
670 return Unbox<wchar>();
671 }
672
673 #else
674 ALIB_API bool IsCharacter() const;
676 #endif
677
678
679 /** ****************************************************************************************
680 * Tests if this this box contains a floating point type.
681 *
682 * \note
683 * If \ref ALIB_FEAT_BOXING_BIJECTIVE_FLOATS is not set, this method will
684 * test against \c double and <c>long double</c>. If it is set, in addition
685 * type \c float is tested.
686 *
687 * @return \c true if this box contains a floating point type, \c false otherwise.
688 ******************************************************************************************/
689 bool IsFloatingPoint() const;
690
691 /** ****************************************************************************************
692 * Unboxes a floating point value as \c double.
693 *
694 * \note
695 * If \ref ALIB_FEAT_BOXING_BIJECTIVE_FLOATS is not set, this method will
696 * test against \c double and <c>long double</c> and convert the latter.
697 * If it is set, in addition type \c float is tested.
698 *
699 * @return \c true if this box contains a floating point type, \c false otherwise.
700 ******************************************************************************************/
702 double UnboxFloatingPoint() const;
703
704 /** ****************************************************************************************
705 * Returns \c true if this box represents an array of objects.
706 * In this case, method #UnboxLength (usually) will return the length of the array and
707 * #UnboxElement may be used to access elements of the array.
708 *
709 * @return \c true if this box represents an array, \c false otherwise.
710 ******************************************************************************************/
711 bool IsArray() const
712 {
713 return vtable && vtable->IsArray();
714 }
715
716 /** ****************************************************************************************
717 * Returns \c true if this objects represents an array and the element type
718 * equals template parameter \p{TElementType}.
719 *
720 * @tparam TElementType The array element type to compare our element type with.
721 * @return \c true if this box represents an array of given type, \c false otherwise.
722 ******************************************************************************************/
723 template<typename TElementType>
724 bool IsArrayOf() const
725 {
726 return vtable && typeid(TElementType) == vtable->ElementType;
727 }
728
729 /** ****************************************************************************************
730 * Returns \c true if this box uses pointer-boxing, otherwise \c false.
731 * The default boxing of pointers will store the pointer to the boxed object
732 * in union \alib{boxing;Placeholder::Pointers}.
733 *
734 * @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
735 ******************************************************************************************/
736 bool IsPointer() const
737 {
738 return vtable && vtable->IsPointer();
739 }
740
741 /** ****************************************************************************************
742 * Returns \c true if this box contains an element of a scoped or non-scoped enum type.
743 * Enum element values are always boxed as type \alib{integer} stored in
744 * union field \alib{boxing;Placeholder}.
745 *
746 * @return \c true if this box contains an object boxed as pointer type, \c false otherwise.
747 ******************************************************************************************/
748 bool IsEnum() const
749 {
750 return vtable && vtable->IsEnum();
751 }
752
753 /** ****************************************************************************************
754 * Returns \c true if \p{other} and this object share the same boxed type.
755 * Note, if this box has void state (no value boxed), then this method returns
756 * \c false, even if given \p{other} is void state as well.
757 *
758 * @param other The box to compare our type with.
759 * @return \c true if this box has the same type like \p{other}, \c false otherwise.
760 ******************************************************************************************/
761 bool IsSameType(const Box& other) const
762 {
763 return vtable && vtable == other.vtable;
764 }
765
766 #if defined(ALIB_DOX)
767 /** ****************************************************************************************
768 * Returns the contents of this box converted to type \p{TBoxable}.
769 * By default this is done by invoking template method \alib{boxing;Placeholder::Read}
770 * on field #data.
771 * This behavior might be customized by specializing struct\alib{boxing;T_Boxer}".
772 *
773 * With debug builds, the actual type of this object is
774 * \ref ALIB_ASSERT_ERROR "asserted" to equal the templated return type.
775 *
776 * \note
777 * With debug builds, it is \ref ALIB_ASSERT_ERROR "asserted" that given \p{TBoxable}
778 * is mapped to the type stored, so that #IsType returned \c true for \p{TBoxable}.
779 * In release compilations, no checks are performed!
780 *
781 * @tparam TUnboxable The type to unbox. If it is not unboxable, a compile-time
782 * assertion is given.
783 * @return The unboxed value of type \p{TUnboxable} .
784 ******************************************************************************************/
785 template<typename TUnboxable>
786 inline
787 const TUnboxable Unbox() const;
788 #else
789
790 template <typename TUnboxable>
793 ATMP_RP(TUnboxable) const * )
794 Unbox() const
795 {
797
798 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior." )
800 "Can not unbox type <" , lang::DbgTypeDemangler(typeid(TUnboxable)).Get(),
801 "> from mapped type <" , lang::DbgTypeDemangler(vtable->Type ).Get(),
802 ">." )
803
804 detail::DbgCheckRegistration( vtable, true );
806 }
807
808 #undef ALIB_TEMPINTERNAL_STATIC_TYPE_CHECKS_UNBOXING
809 #endif
810
811 #if defined(ALIB_DOX)
812 /** ****************************************************************************************
813 * Convenient method to unbox types boxed as pointers, as a non-<c>const</c> pointer type.
814 *
815 * \see Refer to manual chapter \ref alib_boxing_classes_constant for more information.
816 *
817 * @tparam TUnboxable The type to unbox. If it is not unboxable, a compile-time
818 * assertion is given.
819 * @return The unboxed value of type \p{TUnboxable} casted to a non-<c>const</c> object.
820 ******************************************************************************************/
821 template<typename TUnboxable>
822 inline
824 #else
825
826 template <typename TUnboxable>
829 UnboxMutable() const
830 {
831 return const_cast<ATMP_RC(TUnboxable)>( Unbox<TUnboxable>() );
832 }
833 #endif
834
835 /** ****************************************************************************************
836 * Returns the "raw" placeholder of this box.
837 *
838 * In some special situations, this method might be used inspect into the boxed data and
839 * "reinterpret" its contents in a custom way.
840 *
841 * @return The raw contents of this box.
842 ******************************************************************************************/
843 const Placeholder& Data() const
844 {
845 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Can nt access placeholder." )
846 return data;
847 }
848
849 /** ****************************************************************************************
850 * Non-constant variant of #Data, that allows write access to the internal
851 * memory of this box.
852 *
853 * A use case for non-constant access could be the implementation of a
854 * \ref alib_boxing_functions_mutable "non-constant box-function".
855 * In fact, this is the only occasion where within any \alibmod_nl this method was
856 * needed.
857 *
858 * @return The raw contents of this box.
859 ******************************************************************************************/
861 {
862 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Can't access placeholder." )
863 return data;
864 }
865
866 /** ****************************************************************************************
867 * Returns the number of relevant bytes used in the placeholder.
868 *
869 * This method is used with default implementations of box-functions \alib{boxing;FHashcode}
870 * and \alib{boxing;FEquals}.
871 *
872 * \see
873 * The documentation of TMP struct \alib{boxing;T_SizeInPlaceholder} provides details on
874 * and rationals for the existence of this method.
875 *
876 * @return The raw contents of this box.
877 ******************************************************************************************/
878 unsigned int GetPlaceholderUsageLength() const
879 {
880 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized." )
881 return vtable->PlaceholderUsage;
882 }
883
884 /** ****************************************************************************************
885 * Returns the \c std::type_info struct describing the boxed type.
886 * To get the element type of boxed arrays, use #ElementTypeID.
887 *
888 * \note
889 * This method is provided for "completeness" and only be used in special situations.<br>
890 *
891 * \note
892 * If a box is not initialized (or has \c nullptr assigned, <c>typeid(void)</c> is
893 * returned.
894 *
895 * \note
896 * In case of arrays, the a \c std::type_info reference is returned that corresponds
897 * to an array of the element type of size \c 1. For example, if an array of type
898 * \c double of arbitrary size was boxed, then <c>typeid(double[1])</c>is returned.
899 *
900 * @return The \c std::type_info of the mapped type.
901 ******************************************************************************************/
902 const std::type_info& TypeID() const
903 {
905 return vtable ? vtable->Type : typeid(void);
906 }
907
908 /** ****************************************************************************************
909 * Returns the \c std::type_info struct describing the element type of mapped array types.
910 *
911 * \note
912 * This method is provided for "completeness" and only be used in special situations.<br>
913 * In case this box is not of array type, <c>typeid(void)</c> is returned.
914 *
915 * @return The \c std::type_info of the mapped type.
916 ******************************************************************************************/
917 const std::type_info& ElementTypeID() const
918 {
919 ALIB_ASSERT_ERROR( vtable , "BOXING", "Box not initialized. Can not get type information." )
920 return vtable->ElementType;
921 }
922
923 /** ****************************************************************************************
924 * Returns the size in bytes of on element of the stored array.
925 * For non-array types, \c 0 is returned.
926 *
927 * @return The size of elements in the array.
928 ******************************************************************************************/
929 size_t ArrayElementSize() const
930 {
931 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior." )
932 return vtable->Mapping > 0 ? static_cast<size_t>( vtable->Mapping )
933 : 0;
934 }
935
936 /** ****************************************************************************************
937 * Returns the pointer to the first array element.
938 *
939 * \note
940 * With debug builds, it is \ref ALIB_ASSERT_ERROR "asserted" that #IsArray
941 * returns \c true and the stored type is the same as requested.
942 * In release compilations, no checks are performed!
943 *
944 * @tparam TElementType The type of array elements
945 * @return A pointer to the first array element.
946 ******************************************************************************************/
947 template <typename TElementType>
949 {
950 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Unboxing is undefined behavior." )
951 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
952 "Box::UnboxArray() invoked on box of non-array type <",
954
956 "BOXING: Can not unbox array type<" , lang::DbgTypeDemangler(typeid(TElementType*)).Get(),
957 "[]> from mapped type<" , lang::DbgTypeDemangler(vtable->ElementType ).Get(),
958 "[]>." )
959
961
962 return data.Pointer<TElementType>();
963 }
964
965 /** ****************************************************************************************
966 * Returns the length of a boxed Array. While in theory, the length applies only to
967 * arrays, in debug-compilations, \b no run-time type check is performed.
968 * This way, mapped types that use the second "word" of the placeholder to store a
969 * value of type \c integer, may also use this function.<br>
970 * In the latter case, the name of this method might be misleading and therefore, it is
971 * recommended to use <b>Data().integer[1]</b> to denote that a custom interpretation of the
972 * placeholder is performed. The compilation result is the same.
973 *
974 * Some quick rational for why \alib is generally using signed types for array lengths,
975 * is given \ref alib_strings_details_signedlength "here".
976 *
977 * @return The length of the boxed object.
978 ******************************************************************************************/
980 {
981 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box not initialized. Can not access placeholder." )
982 return data.Length();
983 }
984
985 /** ****************************************************************************************
986 * Returns a reference to element \p{idx} of the boxed array.
987 *
988 * \note
989 * With debug builds, it is \ref ALIB_ASSERT_ERROR "asserted" that #IsArray returns
990 * \c true, that the stored type is the same as the requested type and the provided
991 * \p{idx} is between \c 0 and the length of the array.
992 * In release compilations, no checks are performed!
993 *
994 * @tparam TElementType The type of array elements
995 * @param idx The index of the element to receive.
996 * @return The value of the element at \p{idx}.
997 ******************************************************************************************/
998 template <typename TElementType>
1000 {
1001 ALIB_ASSERT_ERROR( vtable, "BOXING", "Box is void (no contents). Unboxing is undefined behavior." )
1002 ALIB_ASSERT_ERROR( IsArray(), "BOXING",
1003 "Box::UnboxElement() invoked on box of non-array type <",
1005
1007 "BOXING: Can not unbox array element type <" , lang::DbgTypeDemangler(typeid(TElementType)).Get(),
1008 "> from mapped type <" , lang::DbgTypeDemangler(vtable->ElementType ).Get(),
1009 "[]>." )
1010
1011 ALIB_ASSERT_ERROR( idx >= 0 && idx < UnboxLength(), "BOXING",
1012 "Box::UnboxElement<", lang::DbgTypeDemangler(typeid(TElementType)).Get(),
1013 ">(): Index out of bounds.")
1014
1016
1018 return * ( data.Pointer<TElementType>() + idx );
1020 }
1021
1022 #if defined(ALIB_DOX)
1023 /** ****************************************************************************************
1024 * Searches an implementation of a box-function identified by template parameter
1025 * \p{TFDecl}, which has to be implemented according the rules of
1026 * \ref alib_boxing_functions_concepts_decl "function declarations".<br>
1027 * If found, a <em>non-nulled</em> function pointer is returned, otherwise a \e nulled one.
1028 *
1029 * On success, the function can be invoked by passing the returned pointer to method
1030 * #CallDirect.
1031 * This approach avoids further searches that are otherwise to be performed with multiple
1032 * invocations of method #Call.
1033 *
1034 * If parameter \p{defaults} equals \alib{lang;Reach::Local}, functions specific to the mapped
1035 * type of this box (registered using \alib{boxing;BootstrapRegister}) are searched.
1036 * If \alib{lang;Reach::Global} is given, then a defaulted function (registered using
1037 * \alib{boxing;BootstrapRegisterDefault}) is searched, if no specific function was found.
1038 *
1039 * \note
1040 * \alib{lang;Reach::Local} can be used to detect specific behavior and to avoid the use
1041 * of default functions. This can be useful if the default implementation of a function
1042 * is just not applicable in a certain situation.
1043 *
1044 * \note
1045 * A second use case of this method are situations where multiple invocations of the
1046 * same function are to be done, on just one or on several boxes of the same mapped type:
1047 *
1048 * assert( box1.IsSameType( box2 ) );
1049 *
1050 * auto* func= box1.GetFunction<FMyFunc>( Reach::Global );
1051 * if( func != nullptr )
1052 * for( int i= 0; i< 10; ++i )
1053 * {
1054 * box1.CallDirect<FMyFunc>( func, i );
1055 * box2.CallDirect<FMyFunc>( func, i );
1056 * }
1057 *
1058 * @tparam TFDecl The \ref alib_boxing_functions_concepts_decl "function declaration"
1059 * to search for.
1060 * @param searchScope \alib{lang;Reach::Local} chooses type-specific functions only, while.
1061 * \alib{lang;Reach::Global} includes default functions in the search.
1062 * @param isInvocation Available only in debug compilations. If \c true, a counter
1063 * associated with an implementation found is increaed to provide
1064 * statistics. Defaults to false and should not be given.
1065 * @return The function implementation.
1066 * \c nullptr in case that no function is available.
1067 ******************************************************************************************/
1068 template <typename TFDecl>
1069 inline
1070 typename TFDecl::Signature GetFunction( Reach searchScope
1071 , bool isInvocation = false ) const;
1072 #else
1073 template <typename TFDecl>
1074 typename TFDecl::Signature GetFunction( lang::Reach searchScope
1075 ALIB_DBG( , bool isInvocation = false) ) const
1076 {
1077 if( !vtable )
1078 return nullptr;
1079
1081
1083 return result
1084 ? result
1087 : nullptr;
1088 }
1089 #endif //ALIB_DOX
1090
1091
1092
1093 /** ****************************************************************************************
1094 * Invokes a function registered for boxes of the mapped type.
1095 * The \ref alib_boxing_functions_concepts_decl "function declaration" is provided with the
1096 * first template parameter \p{TFDecl}.
1097 * The variadic further template parameters do not need to be specified.
1098 * They specify the types of the called function's parameters and are matched against
1099 * the function signature given with the declaration.
1100 * If the types of the given function arguments do not correspond to the types of
1101 * the box-function called, a compile-time error is raised.
1102 *
1103 * \note
1104 * Precisely, the variadic template types denote the function arguments starting from the
1105 * second, as the first argument is always a reference to the box that this method was
1106 * invoked on.
1107 *
1108 * If no corresponding function \alib{boxing;BootstrapRegister;was registered} for the mapped
1109 * type, then a \alib{boxing;BootstrapRegisterDefault;default function}, that is applicable
1110 * to any mapped type is searched.
1111 * If neither is found, a default value of the return type of the function is returned.
1112 *
1113 * With debug builds, an assertion is raised if the function type is not known at all
1114 * to \alib_boxing_nl. This is true, if an implementation was neither registered with
1115 * any other mapped type, nor registered as a default.
1116 *
1117 * \see
1118 * Description of method #GetFunction to implement two use cases:
1119 * - Repetitive invocation of the same function.
1120 * - Avoidance of default functions
1121 *
1122 * \see
1123 * A non-constant overload exists, for the seldom case the reference to this box that is
1124 * passed to the function, needs to be of non-constant type.
1125 *
1126 * @tparam TFDecl The function type to call. Has to be explicitly specified.
1127 * @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1128 * @param args Variadic arguments forwarded to the function.
1129 * @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1130 * respectively <c>TReturn()</c> if the requested function type was not found for
1131 * this \b %Box.
1132 ******************************************************************************************/
1133 template <typename TFDecl, typename... TArgs>
1134 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1135 Call(TArgs&&... args) const
1136 {
1138 if( func != nullptr )
1139 return reinterpret_cast<typename TFDecl::Signature>(func)
1140 ( *this, std::forward<TArgs>(args)... );
1141
1142
1143 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
1144 std::declval<TArgs>()... )) ();
1145 }
1146
1147 /** ****************************************************************************************
1148 * Alternative version of method #Call, which accepts the function's pointer as a first
1149 * argument. Such pointer can be received upfront with method #GetFunction.
1150 *
1151 * @tparam TFDecl The function type to call. Has to be explicitly specified.
1152 * @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1153 * @param args Variadic arguments forwarded to the function.
1154 * @param function The function to invoke.
1155 * @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1156 * respectively <c>TReturn()</c> if the requested function type was not found for
1157 * this \b %Box.
1158 ******************************************************************************************/
1159 template <typename TFDecl, typename... TArgs>
1160 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1162 {
1163 ALIB_ASSERT_ERROR( vtable, "BOXING",
1164 "Box not initialized (does not contain value). Function call not allowed." )
1165 return reinterpret_cast<typename TFDecl::Signature>(function)
1166 ( *this, std::forward<TArgs>(args)... );
1167 }
1168
1169 /** ****************************************************************************************
1170 * Same as method #Call, but usable with interfaces that only accept a mutable
1171 * (aka not constant) box. Technically, the only difference between this method and \b Call
1172 * is that the latter is declared \c const.
1173 *
1174 * \note
1175 * The only built-in boxing function that requires a mutable reference
1176 * to a box, is function \alib{boxing;FClone}. This modifies the contents
1177 * of a box by performing deep copies, with the goal to
1178 * \ref alib_boxing_more_iclone "extent the lifecylce of boxes".
1179 *
1180 * @tparam TFDecl The function type to call. Has to be explicitly specified.
1181 * @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1182 * @param args Variadic arguments forwarded to the function.
1183 * @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1184 * respectively <c>TReturn()</c> if the requested function type was not found for
1185 * this \b %Box.
1186 ******************************************************************************************/
1187 template <typename TFDecl, typename... TArgs>
1188 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1190 {
1191 ALIB_ASSERT_ERROR( vtable, "BOXING",
1192 "Box not initialized (does not contain value). Function call not allowed." )
1194 if( func != nullptr )
1195 return reinterpret_cast<typename TFDecl::Signature>(func)
1196 ( *this, std::forward<TArgs>(args)... );
1197
1198 return decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(),
1199 std::declval<TArgs>()... )) ();
1200 }
1201
1202 /** ****************************************************************************************
1203 * Alternative version of non-constant version of method #Call, which accepts the function's
1204 * pointer as a first argument.
1205 * Such pointer can be received upfront with method #GetFunction.
1206 *
1207 * @tparam TFDecl The function type to call. Has to be explicitly specified.
1208 * @tparam TArgs Types of the variadic arguments \p{args}. Do not need to be specified.
1209 * @param args Variadic arguments forwarded to the function.
1210 * @param function The function to invoke.
1211 * @return Nothing in case that \p{TReturn} is void, otherwise the result of the invocation,
1212 * respectively <c>TReturn()</c> if the requested function type was not found for
1213 * this \b %Box.
1214 ******************************************************************************************/
1215 template <typename TFDecl, typename... TArgs>
1216 decltype( std::declval<typename TFDecl::Signature>()( std::declval<Box&>(), std::declval<TArgs>()... ) )
1218 {
1219 ALIB_ASSERT_ERROR( vtable, "BOXING",
1220 "Box not initialized (does not contain value). Function call not allowed." )
1221 return reinterpret_cast<typename TFDecl::Signature>( function )
1222 ( *this, std::forward<TArgs>(args)... );
1223 }
1224
1225 /** ****************************************************************************************
1226 * Comparison operator. Returns the result of invocation of built-in boxing function
1227 * \alib{boxing;FEquals}.
1228 *
1229 * @param rhs The right hand side argument of the comparison.
1230 * @return \c true if this object equals \p{rhs}, \c false otherwise.
1231 ******************************************************************************************/
1232 ALIB_API
1233 bool operator==(Box const& rhs) const;
1234
1235 /** ****************************************************************************************
1236 * Comparison operator. Returns the negated result of #operator==.
1237 *
1238 * @param rhs The right hand side argument of the comparison.
1239 * @return \c true if this object equals \p{rhs}, \c false otherwise.
1240 ******************************************************************************************/
1241 bool operator!=(const Box& rhs) const
1242 {
1243 return ! ((*this) == rhs);
1244 }
1245
1246 /** ****************************************************************************************
1247 * Comparison operator. Returns the result of invocation of built-in box-function
1248 * \alib{boxing;FIsLess}.
1249 *
1250 * \see
1251 * Sample code provided with documentation of box-function \alib{boxing;FIsLess}.
1252 *
1253 * @param rhs The right hand side argument of the comparison.
1254 * @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1255 ******************************************************************************************/
1256 ALIB_API
1257 bool operator< (Box const& rhs) const;
1258
1259 /** ****************************************************************************************
1260 * Comparison operator. Uses a combination of \c operator< and \c operator==.
1261 *
1262 * @param rhs The right hand side argument of the comparison.
1263 * @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1264 ******************************************************************************************/
1265 ALIB_API
1266 bool operator<=(Box const& rhs) const;
1267
1268 /** ****************************************************************************************
1269 * Comparison operator. Uses a combination of \c operator< and \c operator==.
1270 *
1271 * @param rhs The right hand side argument of the comparison.
1272 * @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1273 ******************************************************************************************/
1274 ALIB_API
1275 bool operator> (Box const& rhs) const;
1276
1277 /** ****************************************************************************************
1278 * Comparison operator. Returns the negated result of \c operator<.
1279 *
1280 * @param rhs The right hand side argument of the comparison.
1281 * @return \c true if this object is smaller than \p{rhs}, otherwise \c false.
1282 ******************************************************************************************/
1283 bool operator>= (Box const& rhs) const
1284 {
1285 return !( (*this) < rhs);
1286 }
1287
1288 /** ****************************************************************************************
1289 * Explicit cast operator to \c bool. Returns the result of built-in box-function
1290 * \alib{boxing;FIsTrue}.
1291 *
1292 * @return \c true if the boxed value <em>represents value true</em>, \c false otherwise.
1293 ******************************************************************************************/
1294 ALIB_API
1295 explicit operator bool() const;
1296
1297
1298 /** ****************************************************************************************
1299 * Returns the result of a call to built-in boxing function \alib{boxing;FIsNotNull}.
1300 *
1301 * @return \c false if this object represents a \e nulled object, \c true otherwise.
1302 ******************************************************************************************/
1303 ALIB_API
1304 bool IsNotNull() const;
1305
1306 /** ****************************************************************************************
1307 * Returns the negated result of a call to built-in boxing function
1308 * \alib{boxing;FIsNotNull}.
1309 *
1310 * @return \c true if this object represents a \e nulled object, \c false otherwise.
1311 ******************************************************************************************/
1312 bool IsNull() const
1313 {
1314 return !IsNotNull();
1315 }
1316
1317 /** ****************************************************************************************
1318 * Returns the result of invocation of built-in boxing function \alib{boxing;FHashcode}.
1319 *
1320 * @return A hashcode for the boxed type and value.
1321 ******************************************************************************************/
1322 ALIB_API size_t Hashcode() const;
1323
1324 #if ALIB_MONOMEM
1325 /** ****************************************************************************************
1326 * Returns the result of invocation of built-in boxing function \alib{boxing;FHashcode}.
1327 *
1328 * \par Availability
1329 * This method is available only if module \alib_monomem is included in the \alibdist.
1330 * @param memory A monotonic allocator used for storing cloned data.
1331 ******************************************************************************************/
1333 #endif
1334
1335}; // class Box
1336
1337}} // namespace [alib::boxing]
1338
1339
1340// For documentation, all operators are faked into namespace alib::boxing
1341#if defined(ALIB_DOX)
1342namespace alib { namespace boxing {
1343#endif
1344
1345
1346#if defined(ALIB_DOX)
1347}} // namespace [alib::boxing]
1348#endif
1349
1350#endif // HPP_ALIB_BOXING_BOX
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) CallDirect(typename TFDecl::Signature function, TArgs &&... args) const
Definition box.inl:1161
uinteger UnboxUnsignedIntegral() const
Definition box.inl:626
Box(Box &&) noexcept=default
ALIB_API bool operator<(Box const &rhs) const
Definition boxing.cpp:204
size_t ArrayElementSize() const
Definition box.inl:929
TElementType * UnboxArray() const
Definition box.inl:948
detail::VTable * vtable
Definition box.inl:48
ALIB_API bool IsNotNull() const
Definition boxing.cpp:194
bool IsPointer() const
Definition box.inl:736
constexpr Box(const TBoxable &src) noexcept
wchar UnboxCharacter() const
Definition box.inl:668
constexpr Box() noexcept
Definition box.inl:234
bool operator>=(Box const &rhs) const
Definition box.inl:1283
integer UnboxLength() const
Definition box.inl:979
TElementType & UnboxElement(integer idx) const
Definition box.inl:999
bool IsFloatingPoint() const
Definition boxing.cpp:168
bool IsSameType(const Box &other) const
Definition box.inl:761
TFDecl::Signature GetFunction(Reach searchScope, bool isInvocation=false) const
TUnboxable UnboxMutable() const
bool IsUnsignedIntegral() const
Definition box.inl:592
ALIB_API size_t Hashcode() const
Definition boxing.cpp:195
bool IsSignedIntegral() const
Definition box.inl:574
bool IsType() const
unsigned int GetPlaceholderUsageLength() const
Definition box.inl:878
ALIB_API bool operator<=(Box const &rhs) const
Definition boxing.cpp:205
Box(const Box &) noexcept=default
bool IsEnum() const
Definition box.inl:748
ALIB_API double UnboxFloatingPoint() const
Definition boxing.cpp:180
Placeholder data
Definition box.inl:51
bool operator!=(const Box &rhs) const
Definition box.inl:1241
bool IsNull() const
Definition box.inl:1312
decltype(std::declval< typename TFDecl::Signature >()(std::declval< Box & >(), std::declval< TArgs >()...)) Call(TArgs &&... args) const
Definition box.inl:1135
const detail::VTable * DbgGetVTable() const
Definition box.inl:509
const std::type_info & TypeID() const
Definition box.inl:902
const std::type_info & ElementTypeID() const
Definition box.inl:917
bool IsArrayOf() const
Definition box.inl:724
const Placeholder & Data() const
Definition box.inl:843
integer UnboxSignedIntegral() const
Definition box.inl:609
ALIB_API bool operator>(Box const &rhs) const
Definition boxing.cpp:206
ALIB_API bool operator==(Box const &rhs) const
Definition boxing.cpp:203
Placeholder & Data()
Definition box.inl:860
const TUnboxable Unbox() const
bool IsArray() const
Definition box.inl:711
static detail::VTable * getVTable()
bool IsCharacter() const
Definition box.inl:651
ALIB_API void Clone(monomem::MonoAllocator &memory)
ALIB_API const char * Get()
#define ATMP_IF_T_F( Cond, T, F)
Definition tmp.hpp:54
#define ATMP_IS_ARR(T)
Definition tmp.hpp:28
#define ATMP_RECVP( T)
Definition tmp.hpp:46
#define ATMP_RP( T)
Definition tmp.hpp:38
#define ATMP_RCV( T)
Definition tmp.hpp:40
#define ATMP_ISOF( T, TBase)
Definition tmp.hpp:33
#define ALIB_WARNINGS_RESTORE
Definition alib.hpp:715
#define ALIB_FORCE_INLINE
Definition alib.hpp:549
#define ALIB_API
Definition alib.hpp:538
#define ATMP_RCVP( T)
Definition tmp.hpp:43
#define ATMP_RC( T)
Definition tmp.hpp:36
#define ATMP_RCVR( T)
Definition tmp.hpp:41
#define ATMP_EQ( T, TEqual)
Definition tmp.hpp:32
#define ATMP_IS_PTR(T)
Definition tmp.hpp:27
#define ALIB_ASSERT_ERROR(cond,...)
Definition alib.hpp:984
#define ALIB_WARNINGS_ALLOW_UNSAFE_BUFFER_USAGE
Definition alib.hpp:644
#define ALIB_DBG(...)
Definition alib.hpp:457
#define ATMP_SELECT_IF_1TP(TParam, ...)
Definition tmp.hpp:57
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:53
ALIB_API void DbgCheckRegistration(detail::VTable *vtable, bool increaseUsageCounter)
Definition boxing.cpp:1130
FunctionTable DEFAULT_FUNCTIONS
Definition vtable.cpp:128
const alib::boxing::Box & Type
@ Global
Denotes global reach.
Definition alib.cpp:57
lang::uinteger uinteger
Type alias in namespace alib.
Definition integers.hpp:289
characters::wchar wchar
Type alias in namespace alib.
lang::integer integer
Type alias in namespace alib.
Definition integers.hpp:286
static void Write(Placeholder &target, const TBoxable &value)
TFDecl::Signature Get(bool isInvocation) const
const std::type_info & Type
Definition vtable.inl:194
const unsigned int PlaceholderUsage
Definition vtable.inl:214
const MappingType Mapping
Definition vtable.inl:205
const std::type_info & ElementType
Definition vtable.inl:198
constexpr TReturn * Pointer() const
constexpr integer Length() const
ALIB_WARNINGS_RESTORE constexpr void Clear()