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