ALib C++ Library
Library Version: 2412 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
functions.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_FUNCTIONS
9#define HPP_ALIB_BOXING_FUNCTIONS 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
15namespace alib { namespace boxing {
16
17//==================================================================================================
18/// This built-in \ref alib_boxing_functions "box function" constitutes the concept of
19/// "nullable types". Nullable types are pointer types, array types and custom types that are
20/// nullable. Arithmetical types are never \e nulled, even if they contain value \c 0 or \c 0.0.
21///
22/// A default implementation is given, which returns \c false (not <em>nulled</em>!) if the first word in
23/// the placeholder is not \c 0. Hence this works for array and pointer types.
24///
25/// A constant function return \c true is given with static method #ConstantTrue. This function
26/// is set as the specific implementation for all arithmetical types, as well as for type \c bool.
27///
28/// \note
29/// The reason why this function is not declared as \b FIsNull, but instead is negated, is that
30/// if any function is called on a \ref alib_boxing_more_void_void "void box", a
31/// default value is returned. The default value of \c bool is \c false, which probably better
32/// fits - even if conceptually a void box is undefined and therefore neither \e nulled or not.
33//==================================================================================================
35{
36 /// Signature of the invokable function.
37 ///
38 /// @param self The box that the function was invoked on.
39 /// @return Return \c false if a boxed value is \e nulled, \c true otherwise.
40 using Signature = bool (*) ( const Box& self );
41
42 /// This implementation of the function signature returns constant \c true.
43 /// It may be registered with custom types that do not provide the concept of being \e nulled.
44 /// \ref alib_manual_bootstrapping "Bootstrapping" function
45 /// \alib{boxing::Bootstrap} registers this implementation with type \c bool and all integral,
46 /// floating point and character types.
47 ///
48 /// @return Constant \c true.
50 static bool ConstantTrue( const Box& );
51};
52
53
54//==================================================================================================
55/// This function returns a hashcode on contents of the box. This is useful if boxes are to
56/// be used as key-values of containers like \c std::unordered_map or
57/// \alib{containers;HashTable}.
58///
59/// Its default implementation creates a hash code using the raw placeholder values and
60/// in case of array types over the array memory used.
61///
62/// A templated version that compares the first N-bytes is given with #UsePlaceholderBytes.
63/// Because the number of bytes to use are given with the template parameter, the method compiles
64/// to shortest code. It is registered with all fundamental types.
65///
66/// \note
67/// Compatibility header \alibheader{compatibility/std_boxing_functional.hpp} specializes
68/// functors \c std::hash, \c std::equal_to and \c std::less for use with containers of the
69/// C++ standard library.
70///
71/// \see
72/// Method \alib{boxing;Box::Hashcode}, which calls this function.
73//==================================================================================================
75{
76 /// Signature of the invokable function.
77 ///
78 /// @param self The box that the hash code is to be calculated for.
79 /// @return The hash code.
80 using Signature = size_t (*) ( const Box& self );
81
82 /// Templated hash function usable with types boxed as values.
83 /// For pointer types, a custom variant that collects type-specific hashable data is recommended.
84 ///
85 /// @tparam N The number of bytes to check.
86 /// @param self The box to calculate a hash code for.
87 /// @return The hash code.
88 template<size_t N>
89 static size_t UsePlaceholderBytes( const Box& self );
90
91};
92
93
94//==================================================================================================
95/// This function compares two boxes.
96///
97/// A default implementation is \alib{boxing;BootstrapRegisterDefault;registered} that compares the types
98/// (\alib{boxing;Box::IsSameType}) and if equal, with arrays compares the array's length,
99/// \e nulled state and finally the contents using \c memcmp.<br>
100/// For non-array types, it compares the relevant bytes in the placeholder.
101/// The number of leading relevant bytes is available with method
102/// \alib{boxing;Box::GetPlaceholderUsageLength}.
103///
104/// Type-specific implementations are given and registered for fundamental types. Integrals
105/// of different sizes and floating point values will be compared by using
106/// \alib{boxing;Box::UnboxSignedIntegral}, \alib{boxing;Box::UnboxUnsignedIntegral} and
107/// \alib{boxing;Box::UnboxFloatingPoint} and appropriate casting.
108/// In the case of floating point comparison, an epsilon distance is duly taken into account.
109///
110/// For custom types, with #ComparableTypes, a templated implementation is suggested: Rather than
111/// implementing a specific box-function, the custom type should implement \c operator== and register
112/// an instantiation of the templated function.
113///
114/// \see
115/// Method \alib{boxing;Box::operator==}, which calls this function.
116//==================================================================================================
118{
119 /// Signature of the invokable function.
120 ///
121 /// @param self The box that the function was invoked on.
122 /// @param rhs The box to compare.
123 /// @return Return value and type is implementation specific.
124 using Signature = bool (*) ( const Box& self, const Box& rhs);
125
126
127 #if DOXYGEN
128 /// Templated implementation of the function signature, usable with boxable types which have
129 /// <c>operator==</c> implemented.
130 ///
131 /// \note
132 /// This method interally is provide twice, once for types boxed as pointers and one for
133 /// types boxed as values, and selected using TMP.<br>
134 /// If a type is boxed as pointer, then \p{TComparable} has to be given as such pointer type.
135 /// For comparison, the unboxed pointers will be dereferenced. If one is \e nulled, \c false
136 /// is returned, if both are \e nulled, true.
137 ///
138 /// \see
139 /// Macro \ref ALIB_BOXING_DEFINE_FEQUALS_FOR_COMPARABLE_TYPE.
140 ///
141 /// @tparam TComparable The mapped type that can be compared using <c>operator==</c>.
142 /// @param self The box that the function was invoked on.
143 /// @param rhs The boxed value to compare.
144 ///
145 /// @return \c true if \p{self} equals \p{rhs}, \c false otherwise.
146 template<typename TComparable>
147 static
148 bool ComparableTypes( const Box& self, const Box& rhs );
149
150 #else
151
152 template<typename TComparable>
153 static
154 ATMP_T_IF(bool, !ATMP_IS_PTR(TComparable) )
155 ComparableTypes( const Box& self, const Box& rhs );
156
157 template<typename TComparable>
158 static
159 ATMP_T_IF(bool, ATMP_IS_PTR(TComparable) )
160 ComparableTypes( const Box& self, const Box& rhs );
161 #endif
162};
163
164#define ALIB_BOXING_DEFINE_FEQUALS_FOR_COMPARABLE_TYPE( TComparable ) \
165alib::boxing::BootstrapRegister< FEquals, \
166 alib::boxing::TMappedTo<TComparable >>(FEquals::ComparableTypes<TComparable>); \
167
168
169//==================================================================================================
170/// This function provides a relational comparison of two boxes.
171///
172/// A default implementation is \alib{boxing;BootstrapRegisterDefault;registered} that compares the types.
173/// If they are equal, the first \c uinteger values in the placeholders are compared.
174/// Specifics for array types are \b not implemented with that default version.
175///
176/// If the types are not the same, the result of the comparison of the run-time type information
177/// object is returned. For this, method \alib{boxing;Box::TypeID} is invoked on both boxes
178/// and to allow <c>operator<</c> on those, \c std::type_index is applied.
179/// This leads to a "nested" sort order, with the type information being the outer order and
180/// the boxed data being the inner.<br>
181/// To keep this overall order intact, type-specific implementations should use the following
182/// implementation scheme:
183///
184/// if( rhs.IsType<AComparableType1>() )
185/// return MyCompare( self.Unbox<MyType>, rhs.Unbox<AComparableType1>();
186///
187/// if( rhs.IsType<AComparableType2>() )
188/// return MyCompare( self.Unbox<MyType>, rhs.Unbox<AComparableType2>();
189///
190/// if( ...
191/// return ...
192///
193/// return std::type_index( self.TypeID() ) < std::type_index( rhs.TypeID() );
194///
195/// With this scheme in place, for example \c std::sort will work properly on containers of boxes of
196/// mixed types. The following sample demonstrates this. It uses a specialization of
197/// \c std::less<T> for type \b Box. This is found in a compatibility header:
198///
199/// \snippet "DOX_BOXING.cpp" DOX_BOXING_FISLESS_INCLUDES
200///
201/// With that, the following code compiles fine:
202/// \snippet "DOX_BOXING.cpp" DOX_BOXING_FISLESS
203///
204/// It generates the following output:
205///
206/// \snippet "DOX_BOXING_FISLESS.txt" OUTPUT
207///
208/// As can be seen from the result, a proper "outer" sorting is in place. Nevertheless,
209/// floating-point and integral values follow the inner sorting.
210/// This is because specific implementations of the functions are registered for all arithmetic
211/// types, which allow comparisons of mixed types.
212/// The same is true for the different C++ character types.
213///
214/// \note
215/// It is a matter of the compiler (and cannot be determined by the user code) how the
216/// types are sorted (outer sorting).<br>
217/// Furthermore, the default implementation that simply compares the first \b uinteger of the
218/// placeholder is unlikely to produce "reasonable" results.
219///
220/// Type-specific implementations are given and registered for fundamental types. Integrals
221/// of different sizes and floating point values will be compared by using
222/// \alib{boxing;Box::UnboxSignedIntegral}, \alib{boxing;Box::UnboxUnsignedIntegral} and
223/// \alib{boxing;Box::UnboxFloatingPoint} and appropriate casting.
224///
225/// If module \alib_strings is included in the distribution, an implementation for
226/// arrays of \alib{characters;nchar}, \alib{characters;wchar} and \alib{characters;xchar} is given.
227///
228/// For custom types, with #ComparableTypes, a templated implementation is suggested: Rather than
229/// implementing a specific box-function, the custom type should implement \c operator< and register
230/// an instantiation of the templated function.
231///
232/// \see
233/// Method \alib{boxing;Box::operator<}, which calls this function.
234//==================================================================================================
236{
237 /// Signature of the invokable function.
238 ///
239 /// @param self The box that the function was invoked on.
240 /// @param rhs The box to compare.
241 /// @return Return value and type is implementation specific.
242 using Signature = bool (*) ( const Box& self, const Box& rhs);
243
244
245 #if DOXYGEN
246 /// Templated implementation for function \alib{boxing;FIsLess}, usable with boxable types
247 /// which have <c>operator<</c> implemented.
248 ///
249 /// \note
250 /// This method interally is provide twice, once for types boxed as pointers and one for
251 /// types boxed as values, and selected using TMP.<br>
252 /// If a type is boxed as pointer, then \p{TComparable} has to be given as such pointer type.
253 /// For comparison, the unboxed pointers will be dereferenced. If both are \e nulled, \c false
254 /// is returned, if only \p{self} is \e nulled, \c true and if only \p{rhs} is \e nulled,
255 /// then \c false.
256 ///
257 /// \see
258 /// Macro \ref ALIB_BOXING_DEFINE_FISLESS_FOR_COMPARABLE_TYPE.
259 ///
260 /// @tparam TComparable The mapped type that can be compared using <c>operator<</c>.
261 /// @param self The box that the function was invoked on.
262 /// @param rhs The boxed value to compare.
263 ///
264 /// @return \c true if \p{self} equals \p{rhs}, \c false otherwise.
265 template<typename TComparable>
266 static
267 bool ComparableTypes( const Box& self, const Box& rhs );
268
269 #else
270 template<typename TComparable> static ATMP_T_IF(bool, !ATMP_IS_PTR(TComparable) )
271 ComparableTypes( const Box& self, const Box& rhs );
272
273 template<typename TComparable> static ATMP_T_IF(bool, ATMP_IS_PTR(TComparable) )
274 ComparableTypes( const Box& self, const Box& rhs );
275 #endif
276};
277
278#define ALIB_BOXING_DEFINE_FISLESS_FOR_COMPARABLE_TYPE( TComparable ) \
279alib::boxing::BootstrapRegister< FIsLess, \
280 alib::boxing::TMappedTo<TComparable >>(FIsLess::ComparableTypes<TComparable>); \
281
282
283#if ALIB_MONOMEM
284} namespace monomem { template<typename TAllocator> class TMonoAllocator;; }
285namespace boxing {
286
287
288//==================================================================================================
289/// This type declares a built-in \ref alib_boxing_functions "box-function".<br>
290/// Besides mandatory parameter \p{self}, implementations expect a reference to an allocator of type
291/// \alib{MonoAllocator}. With that, a deep copy of the boxed object can be allocated.
292///
293/// The function is provided for use-cases where boxes have to "survive" the end of
294/// the life-cycle of the original object.
295///
296/// A default implementation of this function is provided. While this just does nothing
297/// for non-array types, with array types, the complete contents of the array is cloned.
298/// With this in place, all boxed character arrays (strings) are cloned.
299/// This is done regardless if it is necessary or not. For example, if the boxed string
300/// was created from a C++ string literal, a deep copy is unnecessary.
301/// While this imposes a little overhead, there is no way to avoid this because the origin of a
302/// boxed array cannot be determined.
303///
304/// \attention
305/// Only objects that do not need to be destructed are allowed to be cloned using the
306/// monotonic allocator given. This is because \b no destructor will be invoked for boxed objects
307/// (which is true in general for \alib_boxing).<br>
308/// Of course a custom implementation could create and allocate the object in a custom place,
309/// that allows later destruction. Alternatively, a custom method could just ensure that
310/// an object will not be deleted, e.g., by increasing a usage counter and leave the given box
311/// untouched.
312///
313/// \note
314/// Today, this is the only box-function type found within \alib, that requires a
315/// mutable "this" pointer (aka a non constant parameter \p{self}).<br>
316/// Consequently, if the function is called, the compiler selects the non-constant version of
317/// method \alib{boxing;Box::Call}.<br>
318/// Furthermore it has to be noted, that an invocation of this function might change the type
319/// together with the contents of \p{self}. Therefore, results of any already performed
320/// type-guessing are not valid after an invocation.
321///
322/// \attention
323/// If a mapped type has no specialization for this function, there are three possibilities:
324/// 1. The original value is not deleted during the life-cycle of the box.
325/// 2. The type was boxed as a value type (or, very unlikely, otherwise is safe to be unboxed,
326/// even after the deletion of the original value).
327/// 3. Undefined behavior (crash) due to unboxing the value after deletion of the original
328/// object.
329///
330/// \par Availability
331/// This box-function is available only if the module \alib_monomem is included in the
332/// \alibdist.
333//==================================================================================================
334struct FClone
335{
336 /// Signature of the box-function.
337 ///
338 /// @param self The mutable box that the function was invoked on.
339 /// @param allocator A monotonic allocator that may be used for cloning.
340 using Signature = void (*) ( boxing::Box& self, MonoAllocator& allocator );
341};
342#endif
343
344//==================================================================================================
345/// This is one of the built-in \ref alib_boxing_functions "box-functions" of \alib_boxing_nl.
346/// This function is used to give an answer to the question if a boxed value represents a boolean
347/// value \c true or \c false. This is useful if "yes/no" decisions should be taken based on
348/// arbitrary boxed values.
349///
350/// A default implementation is registered which for non-array types just interprets the first
351/// integral value in the \alib{boxing;Placeholder}: If it is not \c 0, \c true is returned, \c false
352/// otherwise.<br>
353/// For array types, the default implementation returns \c true if method
354/// \alib{boxing;Box::UnboxLength} returns a value different to \c 0, otherwise \c false is returned.
355//==================================================================================================
357{
358 /// Signature of the invokable function.
359 ///
360 /// @param self The box that the function was invoked on.
361 /// @return Return value and type is implementation specific.
362 using Signature = bool (*) ( const Box& self);
363};
364
365
366
367#if ALIB_STRINGS
368//==================================================================================================
369/// Implementations of this \ref alib_boxing_functions "box-function" write the content of the
370/// data stored in the box to the given \b %AString object.
371///
372/// A default implementation is registered. This writes out the raw value of the first
373/// \c uinteger field of the boxes' \alib{boxing;Placeholder} in hexadecimal format.
374/// For pointer types, such raw value reflects the memory address of the boxable.
375/// In debug-compilations, in addition, the type name of the boxed value is written.
376///
377/// Templated static method #Appendable can be used to avoid implementations for those mapped types
378/// that specialized type traits functor \alib{strings;T_Append} that makes values of the type
379/// usable with \alib{strings;TAString::Append;AString::Append} already.
380///
381/// \note
382/// This is a templated (!) function declaration that defines three different box-functions at
383/// once, namely \b FAppend<character>, \b FAppend<complementChar> and \b FAppend<strangeChar>.
384///
385/// This box-function is usually invoked only indirectly, by "appending" a box to an \b AString,
386/// as shown here:
387///
388/// Box box= 42;
389/// AString text;
390///
391/// text << "The answer is: "; // appends a string literal
392/// text << box; // translates to: box.Call<FAppend<character>>( text )
393///
394/// \par Availability
395/// This box-function is available only if the module \alib_strings is included in the \alibdist.
396///
397/// \see
398/// - Manual chapter \ref alib_boxing_strings_fappend "10.3 Box-Function FAppend"
399/// - Chapter \ref alib_basecamp_format_custom_types "4.3. Formatting Custom Types" of
400/// the Programmer's Manual of \alib_basecamp, which gives
401/// a sample implementation of this function, and introduces a more powerful
402/// box-function \alib{lang::format;FFormat}.
403///
404/// @tparam TChar The character type of the destination \alib{strings;TAString;AString} given with
405/// parameter \p{target}.
406/// @tparam TAllocator The allocator type, as prototyped with \alib{lang;Allocator}.
407//==================================================================================================
408template<typename TChar, typename TAllocator>
410{
411 /// Signature of the invokable function.
412 ///
413 /// @param self The box that the function was invoked on.
414 /// @param target The target \b %AString of character type \p{TChar}.
415 using Signature = void (*) ( const Box& self, strings::TAString<TChar, TAllocator>& target );
416
417
418 #if DOXYGEN
419 /// Static templated implementation of \ref FAppend for boxed types which are appendable.
420 ///
421 /// Once a type is made \e appendable by specializing type traits functor
422 /// \alib{strings;T_Append}, then this static templated function can be used "as is"
423 /// and registered with the corresponding mapped type.
424 ///
425 /// \note
426 /// This method interally is provide twice, once for types boxed as pointers and one for
427 /// types boxed as values, and selected using TMP.<br>
428 /// If a type is boxed as pointer, then \p{TComparable} has to be given as such pointer type.
429 /// For comparison, the unboxed pointers will be dereferenced. This means, that
430 /// it is believed that \alib{strings;T_Append} is specialized for the non-pointer type.
431 /// If this is not the case, then two options exists:
432 /// 1. Specialize functor \alib{strings;T_Append} for the non-pointer type in parallel.
433 /// 2. Do not use this inlined implementation, but rather provide a custom one that
434 /// does not dereference unboxed pointers.
435 ///
436 /// \see
437 /// Macros
438 /// - ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE
439 /// - ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_N
440 /// - ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_W
441 /// - ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_X
442 ///
443 /// @tparam TAppendable The "appendable" mapped box type that the function is to be implemented
444 /// for.
445 /// @param self The box that the function was invoked on.
446 /// @param target The target \b %AString of character type \p{TChar}.
447 template<typename TAppendable>
448 inline static
450 #else
451
452 template<typename TAppendable> inline static ATMP_VOID_IF( !ATMP_IS_PTR(TAppendable) )
454
455 template<typename TAppendable> inline static ATMP_VOID_IF( ATMP_IS_PTR(TAppendable) )
457
458 #endif
459
460
461 /// Implementation template for box-function \alib{boxing;FAppend} for appendable types wrapped in
462 /// \c std::reference_wrapper to \ref alib_boxing_customizing_identity "bypass custom boxing".
463 ///
464 /// This static function template can be used for any type \p{TAppendable} that has a
465 /// specialization of functor \alib{strings;T_Append} defined and that becomes boxed in the
466 /// wrapper type.
467 ///
468 /// @tparam TAppendable The "appendable" wrapped mapped box type that the function is to be
469 /// implemented for.
470 /// @param self The box that the function was invoked on.
471 /// @param target The target \b %BoxedAs<AString> object.
472 template<typename TAppendable>
473 inline static
475};
476
477
478#define ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE(TAppendable) \
479alib::boxing::BootstrapRegister<FAppend<character, alib::lang::HeapAllocator>, alib::boxing::TMappedTo<TAppendable>> \
480 (alib::boxing::FAppend<character, alib::lang::HeapAllocator>::Appendable<TAppendable>);
481
482#define ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_N(TAppendable) \
483alib::boxing::BootstrapRegister<FAppend<nchar , alib::lang::HeapAllocator>, alib::boxing::TMappedTo<TAppendable>> \
484 (alib::boxing::FAppend<nchar , alib::lang::HeapAllocator>::Appendable<TAppendable>);
485
486#define ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_W(TAppendable) \
487alib::boxing::BootstrapRegister<FAppend<wchar , alib::lang::HeapAllocator>, alib::boxing::TMappedTo<TAppendable>> \
488 (alib::boxing::FAppend<wchar , alib::lang::HeapAllocator>::Appendable<TAppendable>);
489
490#define ALIB_BOXING_BOOTSTRAP_REGISTER_FAPPEND_FOR_APPENDABLE_TYPE_X(TAppendable) \
491alib::boxing::BootstrapRegister<FAppend<xchar , alib::lang::HeapAllocator>, alib::boxing::TMappedTo<TAppendable>> \
492 (alib::boxing::FAppend<xchar , alib::lang::HeapAllocator>::Appendable<TAppendable>);
493
494#endif //ALIB_STRINGS
495
496}} // namespace [alib::boxing]
497
498#endif // HPP_ALIB_BOXING_FUNCTIONS
499
#define ATMP_VOID_IF(Cond)
Definition tmp.hpp:47
#define ALIB_API
Definition alib.hpp:639
#define ATMP_IS_PTR(T)
Definition tmp.hpp:22
#define ATMP_T_IF(T, Cond)
Definition tmp.hpp:49
Definition alib.cpp:69
static void WrappedAppendable(const Box &self, strings::TAString< TChar, TAllocator > &target)
void(*)(const Box &self, strings::TAString< TChar, TAllocator > &target) Signature
static void Appendable(const Box &self, strings::TAString< TChar, TAllocator > &target)
void(*)(boxing::Box &self, MonoAllocator &allocator) Signature
bool(*)(const Box &self, const Box &rhs) Signature
static bool ComparableTypes(const Box &self, const Box &rhs)
size_t(*)(const Box &self) Signature
Definition functions.inl:80
static size_t UsePlaceholderBytes(const Box &self)
bool(*)(const Box &self, const Box &rhs) Signature
static bool ComparableTypes(const Box &self, const Box &rhs)
static ALIB_API bool ConstantTrue(const Box &)
Definition boxing.cpp:669
bool(*)(const Box &self) Signature
Definition functions.inl:40
bool(*)(const Box &self) Signature