ALib C++ Library
Library Version: 2510 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
boxingtraits.inl
Go to the documentation of this file.
1//==================================================================================================
2/// \file
3/// This header-file is part of module \alib_boxing of the \aliblong.
4///
5/// \emoji :copyright: 2013-2025 A-Worx GmbH, Germany.
6/// Published under \ref mainpage_license "Boost Software License".
7//==================================================================================================
8ALIB_EXPORT namespace alib { namespace boxing {
9
10/// This is an empty type used to denote that default boxing is active. The type is
11/// used with the default implementation of the type trait \alib{boxing;BoxTraits}.
12/// Providing this type in custom specializations, makes such specialization in-effective.
13/// \see Templated struct \alib{boxing;BoxTraits} for more information.
15
16/// This is an empty type used to denote that a type must not be boxed.
17/// To disable \alib_boxing_nl for a custom type, a specialization of type-traits
18/// struct \alib{boxing;BoxTraits} must use this type to define type alias
19/// \alib{boxing;BoxTraits::Mapping}.
20///
21/// \see
22/// Templated struct \alib{boxing;BoxTraits} for more information.
23struct NotBoxableTag {};
24
25
26//==================================================================================================
27/// This template struct is used to define customized behavior for boxing C++ type
28/// \p{TBoxable}.
29///
30/// ### Default Boxing: ###
31/// If this struct is \b not specialized for template type \p{TBoxable},
32/// default boxing applies.
33/// With that, values \b and pointers of a type are boxed in the same way:
34/// - They are both boxed to a pointer of \p{TBoxable} if a value of the type does not "fit" into
35/// a box's \alib{boxing;Placeholder} or if the type is not copy-constructible or not
36/// trivially destructible.
37/// - Otherwise, both are boxed as values, hence if a pointer is given to the constructor or
38/// assign \c operator= of class \alib{boxing;Box}, indirection \c operator* is applied.
39///
40/// <br><p>
41/// ###Custom Boxing With Specializations Of This Struct: ###
42/// The default boxing briefly described above, can be manipulated by providing a specialization
43/// of this struct.
44/// All three entities of this default implementation have to be provided with such specializations:
45///
46/// 1. <b>Type alias #Mapping:</b><br>
47/// This alias defines the type that a value of \p{TBoxable} is converted to when boxed.
48///
49/// If special type \alib{boxing;NotBoxableTag} is given, then boxing is disallowed for
50/// type \p{TBoxed}.
51/// In this case, only declarations of functions #Write and #Read need to be provided, as they
52/// are never invoked.
53///
54/// The default implementation of this struct uses a second special type available,
55/// \alib{boxing;DefaultBoxingTag} which denotes default boxing.
56///
57/// 2. <b>Boolean constexpr value #IsArray:</b><br>
58/// If set to \c true, array-boxing is performed. In this case #Mapping denotes the element
59/// type of the boxed C++ array.
60///
61/// 3. <b>Static Method #Write:</b><br>
62/// This method is invoked for converting source values to mapped types.
63/// Often the default implementation given in the default version of this struct is
64/// applicable. In this case it can simply be copied to the specialization.
65///
66/// Custom implementations may use one of the overloads of method
67/// \alib{boxing;Placeholder::Write} or alternatively write to the \c union members of the
68/// placeholder directly.
69///
70/// 4. <b>Static Method #Read:</b><br>
71/// This method is invoked for converting the placeholder data back to the boxed source type.
72/// Often the default implementation given in the default version of this struct is
73/// well suited. In this case it can simply be copied to the specialization.<br>
74/// Custom implementations may use one of the overloads of method \alib{boxing;Placeholder::Read}
75/// or alternatively read the \c union members of the placeholder directly.
76///
77/// A type becomes \alib{boxing;IsUnboxable;not unboxable} at the moment this function
78/// returns a different type than \p{TBoxable}.<br>
79/// This may well be intended, and thus the specialized version of this struct
80/// may declare this method to return \c void.
81/// In this case a declaration of the method is enough, as it will never be invoked.<br>
82/// With conditional specializations of this struct (see Programmer's Manual
83/// chapter \ref alib_boxing_customizing_conditional), the return type might be likewise
84/// conditionally set.
85/// Such a return type then decides which of the types are unboxable and which are not.
86///
87/// \note
88/// If a specialization uses default type mapping by providing<br>
89///
90/// using Mapping= DefaultBoxingTag;
91/// \note
92/// in theory, a mixture of default and custom boxing is in place!
93/// Note, that the authors of this library and documentation have not seen a use case for this,
94/// yet.
95///
96/// <br><p>
97/// ### Helper Macros: ###
98///
99/// A set of macros for defining specializations exist.
100/// The use of the macro is recommended, as besides being less error-prone, their use makes the code
101/// more readable. Finally, chances are good that code that uses the macros remains compatible
102/// with future versions of module \alib_boxing_nl.
103///
104/// All macros expect this struct's template type \p{TBoxable} as the first parameter, and most
105/// expect the mapped type as the second parameter.
106///
107/// For more information, see the reference documentation of the macros, which are:
108///
109/// - \ref ALIB_BOXING_CUSTOMIZE
110/// - \ref ALIB_BOXING_CUSTOMIZE_TYPE_MAPPING
111/// - \ref ALIB_BOXING_CUSTOMIZE_NOT_UNBOXABLE
112/// - \ref ALIB_BOXING_CUSTOMIZE_ARRAY_TYPE
113/// - \ref ALIB_BOXING_CUSTOMIZE_ARRAY_TYPE_NON_UNBOXABLE
114/// - \ref ALIB_BOXING_CUSTOMIZE_DENY_BOXING
115///
116/// <br><p>
117/// ### Value Boxing and Nulled Pointers: ###
118/// If a type is boxed as value (either with default boxing or custom boxing) and a \e nulled
119/// pointer to that type is boxed, method \alib{boxing;Placeholder::Clear} is invoked
120/// instead of this struct's method #Write.
121///
122/// <br><p>
123/// ### Avoiding Seldom Compilation Errors: ###
124/// For technical reasons, namely to avoid compilation problems, some conditional specialization
125/// is internally made, that declare method #Read \c void. This is sometimes needed if a type is
126/// not returnable, even if that becomes never be boxed or unboxed.
127/// Such a situation might happen, for example, if class \b Box is part of a \c union.<br>
128/// The specialization is made for the following types of \p{TBoxable}:
129/// - C++ array types<br>
130/// Those types are fetched by an overloaded constructor that does not (because it cannot)
131/// leverage this struct. Likewise, they cannot be unboxed in the usual fashion.
132/// - Function types (selected by <c>std::is_function<TBoxable>::value</c>).
133///
134/// If a dubious error message about method #Read not being able to return a certain type occurs,
135/// even one that a user's code even "actively" tries to box or unbox, then it might be helpful
136/// to specialize this struct for such type, without providing implementations of \b Write and
137/// \b Read and with the latter to return \c void.
138///
139/// <br><p>
140/// \see More explanation and sample code is given in chapter
141/// \ref alib_boxing_customizing "7. Customizing Boxing" of the
142/// \ref alib_mod_boxing "Programmer's Manual" of module \alib_boxing_nl.
143///
144/// @tparam TBoxable The source type to customize boxing for.
145//==================================================================================================
146template<typename TBoxable>
148{
149 /// Defines the mapped type.
150 /// Special designator types \alib{boxing;DefaultBoxingTag} and
151 /// \alib{boxing;NotBoxableTag} may be given to denote corresponding behavior.
152 /// The default implementation specifies designator type \b DefaultBoxingTag, which
153 /// disables custom boxing.
155
156 /// Denotes whether type \p{TBoxable} is boxed as an array-type or not.
157 static constexpr bool IsArray= false;
158
159 /// Used for boxing a value, precisely writing the boxable portion of a type into
160 /// field \alib{boxing;Box::data}, which is given with parameter \p{box}.<br>
161 /// The default implementation of this struct implements this method as follows:
162 /// \snippet "boxing/boxingtraits.inl" DOX_BOXING_T_BOXER_WRITE
163 ///
164 /// This implementation leverages the overloads \alib{boxing;Placeholder::Write}
165 /// and is often all that is needed with custom specializations.
166 /// @param box The placeholder of the destination box.
167 /// @param value The value to that is to be boxed.
168 DOX_MARKER([DOX_BOXING_T_BOXER_WRITE])
169 static constexpr void Write( Placeholder& box, const TBoxable& value ) {
170 box.Write( value );
171 }
172 DOX_MARKER([DOX_BOXING_T_BOXER_WRITE])
173
174 /// Used for unboxing a value, precisely reading the contents of field \alib{boxing;Box::data},
175 /// which is given with output parameter \p{box} and creating a value of type \p{TBoxable} from
176 /// that.<br>
177 /// The default implementation of this struct implements this method as follows:
178 /// \snippet "boxing/boxingtraits.inl" DOX_BOXING_T_BOXER_READ
179 ///
180 /// This implementation leverages the overloaded method \alib{boxing;Placeholder::Read}
181 /// and is often all that is needed with custom specializations.
182 ///
183 /// If a different type than \p{TBoxable} is returned, then that source type is not unboxable.
184 /// To intend such behavior, for example, because \p{TBoxable} is mapped to a reduced type
185 /// and therefore unboxing is not possible, specializations may declare the return type to be
186 /// \c void and omit a definition of this method.<br>
187 /// With conditional customizations, also other return types may be given, which likewise denote
188 /// an unboxable source type. A sample of that is given with Programmer's Manual chapter
189 /// \ref alib_boxing_customizing_conditional.
190 ///
191 /// @param box The Placeholder to unbox the data from
192 /// @return \c The unboxed object.
193 static
194 std::conditional_t<!std::is_abstract<TBoxable>::value, TBoxable, TBoxable&>
195 Read( const Placeholder& box)
196 {
197DOX_MARKER([DOX_BOXING_T_BOXER_READ])
198return box.Read<TBoxable>();
199DOX_MARKER([DOX_BOXING_T_BOXER_READ])
200 }
201
202}; // BoxTraits
203
204// ####################### critical specializations of BoxTraits ###########################
205#if !DOXYGEN
206
207// This is necessary for types that can't be used as return type in any way, for example
208// types with extents, functions, etc.
209template<typename TBoxable>
210requires( std::is_array_v<TBoxable> || std::is_function<TBoxable>::value )
211struct BoxTraits<TBoxable>
212{
213 using Mapping= DefaultBoxingTag;
214 static constexpr bool IsArray= std::is_array_v<TBoxable>;
215
216 static void Write( Placeholder& box, TBoxable& value );
217 static void Read ( const Placeholder& box);
218};
219
220// void (needed to pass TMP stuff)
221template<>
222struct BoxTraits<void>
223{
224 using Mapping= DefaultBoxingTag;
225 static constexpr bool IsArray= false;
226 static void Write( Placeholder& box, const void* value );
227 static void* Read ( const Placeholder& box);
228};
229
230#endif
231
232//==================================================================================================
233/// This specializable \c constexpr must be set for custom types, if the following applies:
234/// - A custom boxing implements \alib{boxing;BoxTraits::Write} in a way that a different number
235/// of bytes are used in union \alib{boxing;Placeholder} than the \c sizeof() operator reports
236/// on the mapped type's size.
237/// - if the standard copy constructor (used with default boxing) writes a different size.
238/// - One of the above and no specialized version of both box-functions \alib{boxing;FHashcode}
239/// or \alib{boxing;FEquals} are set.
240///
241/// <b>Background:</b><br>
242/// The default implementations of \alib{boxing;FHashcode} and \alib{boxing;FEquals}
243/// must use the first N "relevant" bytes of the placeholder only. The non-relevant bytes are
244/// not written and therefore must not be taken into account.<br>
245/// To receive the number of relevant bytes, they invoke
246/// \alib{boxing;Box::GetPlaceholderUsageLength} (at run-time).
247/// This value is set at compile-time with the creation of a mapped type's \e vtable.
248/// While for array types, the value is set to the overall size of union \alib{boxing;Placeholder},
249/// for non-array types, the value of this type trait is used.
250///
251/// It might be surprising, but a built-in specialization exists for even a C++ fundamental type
252/// <c>long double</c>, which is dependent on the compiler/platform.
253/// For example, on GNU/Linux 64-bit, GCC reports \c 16 with <c>sizeof(long double)</c>.
254/// However, if a <c>long double</c> value is copied, e.g with:
255///
256/// *pointerToLongDouble= 3.14L;
257///
258/// then only 10 bytes are written. The reason for this is that <c>sizeof</c> reports the size
259/// needed for alignment when placed in an array of that type.
260/// In the case of \alib_boxing_nl, 6 bytes of the placeholder remain random and therefore
261/// must not be used for hashing or testing values on equality.
262///
263/// @tparam TMappedPlain The mapped type to modify relevant placeholder length for \b FHashcode
264/// and \b FEquals implementation.
265//==================================================================================================
266template<typename TMappedPlain>
267inline constexpr unsigned int SizeTraits= sizeof(TMappedPlain);
268
269/// Specialization of traits-expression for type <c>long double</c>.
270/// The implementation of this type is platform-dependent and may be adopted to a certain
271/// compiler/processor combination by passing the compiler-symbol
272/// \ref ALIB_SIZEOF_LONGDOUBLE_WRITTEN.
273template<>
275
277//==================================================================================================
278/// A concept that is satisfied for types which boxing is customized for, hence for types for which
279/// a specialization of the type trait \alib{boxing;BoxTraits} exists.
280///
281/// \see
282/// Concepts \alib{boxing;IsUnboxable}, \alib{boxing;IsLocked} and
283/// \alib{boxing;IsNotBoxable}.
284///
285/// @tparam T The type to check.
286//==================================================================================================
287template<typename T>
289= ( std::is_pointer_v<T> || !std::same_as<DefaultBoxingTag, typename BoxTraits< T >::Mapping> )
290 && ( !std::is_pointer_v<T> || !std::same_as<DefaultBoxingTag, typename BoxTraits<ALIB_TVALUE(T)*>::Mapping>);
291
292// Note: besides checking BoxTraits<T>, in the case a pointer is given, we also have to check
293// BoxTraits for the type that results when
294// - the pointer is removed and then
295// - a const is removed and finally
296// - the pointer is added again. Otherwise "const T*" is not deferred to "T*"
297
298/// This concept is for internal use. It is satisfied if the given type \p{T} fits into the
299/// placeholder, is copy-constructible and trivially destructible.
300/// @tparam T The type to test.
301/// @tparam TVal Decayed version of \p{T}. Deduced by the compiler, must not be given.
302template<typename T, typename TVal= ALIB_TVALUE(T)>
303concept IsStdPH= sizeof(std::conditional_t<std::same_as<void, TVal>, void*, TVal>)
304 <= sizeof(Placeholder)
305 && std::is_copy_constructible <TVal>::value
306 && std::is_trivially_destructible<TVal>::value;
307
308/// This concept is for internal use. It is satisfied if the given type \p{T}
309/// has customized boxing with a \c constexpr version of the method <b>BoxTraits<T>::Write</b>
310/// which takes only one parameter, namely an instance of \p{T}.
311/// @tparam T The type to test.
312template<typename T>
314 requires(T& t) { { BoxTraits<T>::Write(t) } -> std::same_as<Placeholder>; };
315
316
317/// This type trait by default inherits \c std::false_type. If specialized for
318/// template type \p{TCharArray} to inherit \c std::true_type, then boxing that type will not be
319/// customized automatically with a corresponding specialization of \alib{characters;ArrayTraits}.
320/// This keeps the customization of boxing open to be performed in a different way.
321///
322/// \see
323/// See manual chapter \ref alib_boxing_strings "10. Boxing Character Strings" of the
324/// Programmer's Manual of module \alib_boxing_nl.
325///
326/// @tparam TCharArray The type that \alib{characters;ArrayTraits} is specialized for but still no
327/// character array boxing should be performed.
328template<typename TCharArray> struct SuppressCharArrayBoxingTraits : std::false_type {};
329
330
331template<typename T>
334 && ( characters::ArrayTraits <std::remove_cv_t<T>, nchar>::Access == characters::Policy::Implicit
335 || characters::ArrayTraits <std::remove_cv_t<T>, wchar>::Access == characters::Policy::Implicit
336 || characters::ArrayTraits <std::remove_cv_t<T>, xchar>::Access == characters::Policy::Implicit
337 );
338
339template<typename T>
344 ;
345
346
347//==================================================================================================
348/// A concept that is satisfied for types for which boxing is customized to disable unboxing.
349/// In other words, types for which a specialization of the type trait \b %BoxTraits
350/// exists which declares method \alib{boxing;BoxTraits::Read} to have a different return type
351/// than \p{T} or \p{T&}.
352///
353/// \see
354/// \alib{boxing;IsUnboxable} for an alternative concept that satisfied if a type can be
355/// unboxed and methods \alib{boxing;Box::IsType} and \alib{boxing;Box::Unbox} do not fail to
356/// compile with that type.
357///
358/// @tparam T The type to check.
359//==================================================================================================
360template<typename T>
361concept IsLocked =
362 !std::same_as<T, std::remove_reference_t<decltype(BoxTraits<T>::Read(std::declval<Placeholder>()))> >;
363
364//==================================================================================================
365/// A concept that is satisfied if:
366///
367/// - boxing was customized for the given type and \alib{boxing;NotBoxableTag} was given as
368/// mapped type, or
369/// - given type is a value type, no customization is given for it, while the corresponding
370/// pointer type has customized boxing with mapped type being \alib{boxing;NotBoxableTag}, or
371/// - given type is a pointer type, no customization is given for it, while the corresponding
372/// value type has customized boxing with mapped type being \alib{boxing;NotBoxableTag}.
373///
374/// If a type is not boxable, it can be neither boxed nor unboxed.
375///
376/// \see
377/// Concepts \alib{boxing;IsCustomized}, \alib{boxing;IsLocked} and
378/// \alib{boxing;IsUnboxable}.
379///
380/// @tparam T The type to check.
381//==================================================================================================
382template<typename T>
384 std::same_as<NotBoxableTag, typename BoxTraits<T>::Mapping>
385 || ( !IsCustomized<T>
386 && ( ( !std::is_pointer_v<T>
387 && std::same_as<NotBoxableTag,
388 typename BoxTraits< T*>::Mapping> )
389 || ( std::is_pointer_v<T>
390 && std::same_as<NotBoxableTag,
391 typename BoxTraits<std::remove_pointer_t<T>>::Mapping> ) ) )
392 ;
393
394
395
396
397//==================================================================================================
398/// This concept is satisfied if a type can be unboxed and methods \alib{boxing;Box::IsType}
399/// and \alib{boxing;Box::Unbox} will not fail to compile with that type.
400///
401/// With default boxing, one of the types \b T and \b T* are unboxable (depending on value type
402/// size and whether the type is copy-constructible and trivially destructible).
403///
404/// If custom boxing for either or both of types \b T and \b T* is in place, then the given type is
405/// not unboxable if:
406/// - customization is not in place for the version passed (value or pointer).
407/// - customization is in place for the given type but concept \alib{boxing;IsLocked} is satisfied.
408/// - The type is mapped to \alib{boxing;NotBoxableTag}.
409///
410/// \see
411/// Concepts \alib{boxing;IsCustomized}, \alib{boxing;IsLocked} and
412/// \alib{boxing;IsNotBoxable}.
413///
414/// @tparam T The type to check.
415//==================================================================================================
416template<typename T>
418 // default boxing
421 && bool( std::is_pointer_v<T> )
422 == bool( ( sizeof(Placeholder) < sizeof(ALIB_TVALUE(T)) )
423 || !std::is_copy_constructible <ALIB_TVALUE(T)>::value
424 || !std::is_trivially_destructible<ALIB_TVALUE(T)>::value ) )
425 || // custom boxing
427 && !IsLocked <T>
428 && !IsNotBoxable<T> )
429
430 || // string type
432;
433
435
436
437}} // namespace [alib::boxing]
438
439
440
441
#define ALIB_WARNINGS_RESTORE
Definition alib.inl:705
#define ALIB_TVALUE(T)
Definition alib.inl:986
#define ALIB_WARNINGS_IGNORE_DOCS
Definition alib.inl:688
#define ALIB_EXPORT
Definition alib.inl:488
#define ALIB_SIZEOF_LONGDOUBLE_WRITTEN
Definition prepro.md:27
constexpr unsigned int SizeTraits
characters::wchar wchar
Type alias in namespace alib.
characters::nchar nchar
Type alias in namespace alib.
characters::xchar xchar
Type alias in namespace alib.
static std::conditional_t<!std::is_abstract< TBoxable >::value, TBoxable, TBoxable & > Read(const Placeholder &box)
DefaultBoxingTag Mapping
static constexpr void Write(Placeholder &box, const TBoxable &value)
static constexpr bool IsArray
Denotes whether type TBoxable is boxed as an array-type or not.
static constexpr Policy Construction