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