jaulib v1.3.0
Jau Support Library (C++, Java, ..)
cpp_lang_util.hpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Gothel Software e.K.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *
23 */
24
25#ifndef JAU_CPP_LANG_EXT_HPP_
26#define JAU_CPP_LANG_EXT_HPP_
27
28#include <type_traits>
29#include <typeinfo>
30#include <string>
31#include <cstring>
32
33namespace jau {
34
35 /** @defgroup CppLang C++ Language Utilities
36 * C++ language utilities, language feature alignment, type trails, data alignment and intrinsics.
37 *
38 * Used predefined `__cplusplus` macro identifier for C++ language specs:
39 * - `199711L`: pre C++11
40 * - `201103L`: C++11
41 * - `201402L`: C++14
42 * - `201703L`: C++17
43 * - `202002L`: C++20
44 * - `202302L`: C++23
45 * - `??????L`: C++26 ??
46 *
47 * Used predefined macros denoting the compiler:
48 * - `__clang__` : LLVM's clang, clang++
49 * - `__GNUC__` : GNU Compiler Collection (GCC)'s gcc, g++
50 * - `_MSC_VER` : Microsoft Compiler
51 * - `__MINGW32__` : MinGW 32
52 * - `__MINGW64__` : MinGW 64
53 * - `__EMSCRIPTEN__`: emscripten for asm.js and WebAssembly
54 *
55 * Further infos:
56 * - [Unix standards](https://sourceforge.net/p/predef/wiki/Standards/)
57 * - [GNU glibc](https://sourceforge.net/p/predef/wiki/Libraries/)
58 * - [glibc 1.3.4 Feature Test Macros](https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html)
59 * - [Architectures](https://sourceforge.net/p/predef/wiki/Architectures/)
60 *
61 * @{
62 */
63
64 /**
65 * `consteval` qualifier replacement for C++20 `consteval`.
66 *
67 * > A `consteval` specifier implies `inline`.
68 * > At most one of the `constexpr`, `consteval`, and `constinit` specifiers is allowed to appear within the same sequence of declaration specifiers.
69 * > ...
70 * > An immediate function is a `constexpr` function,
71 * > and must satisfy the requirements applicable to `constexpr` functions or `constexpr` constructors, as the case may be.
72 *
73 * <p>
74 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
75 * as it is almost contained within `consteval` but lacks the `immediate function` constraint.
76 * </p>
77 * <p>
78 * Evaluated as `consteval` for C++20.
79 * </p>
80 */
81#if __cplusplus > 201703L
82 #define consteval_cxx20 consteval
83#else
84 #define consteval_cxx20 constexpr
85#endif
86
87 /** Returns true if compiled with >= C++17 */
88 consteval_cxx20 bool is_cxx17() noexcept {
89 #if __cplusplus > 201402L
90 return true;
91 #else
92 return false;
93 #endif
94 }
95 /** Returns true if compiled with >= C++20 */
96 consteval_cxx20 bool is_cxx20() noexcept {
97 #if __cplusplus > 201703L
98 return true;
99 #else
100 return false;
101 #endif
102 }
103 /** Returns true if compiled with >= C++23 */
104 consteval_cxx20 bool is_cxx23() noexcept {
105 #if __cplusplus > 202002L
106 return true;
107 #else
108 return false;
109 #endif
110 }
111 /** Returns true if compiled with >= C++26 */
112 consteval_cxx20 bool is_cxx26() noexcept {
113 #if __cplusplus > 202302L
114 return true;
115 #else
116 return false;
117 #endif
118 }
119
120 /**
121 * `constinit` qualifier replacement for C++20 `constinit`.
122 *
123 * > `constinit` cannot be used together with `constexpr` or `consteval`.
124 * > When the declared variable is a reference, `constinit` is equivalent to `constexpr`.
125 * > When the declared variable is an object,
126 * > `constexpr` mandates that the object must have static initialization and constant destruction
127 * > and makes the object const-qualified, however, `constinit` does not mandate constant destruction and const-qualification.
128 *
129 * <p>
130 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
131 * as it is almost contained within `constinit` but lacks the loosening of not mandating constant destruction and const-qualification.<br>
132 * FIXME: Due to the above, this replacement might not be suitable: TBD!
133 * </p>
134 * <p>
135 * Evaluated as `constinit` for C++20.
136 * </p>
137 */
138#if __cplusplus > 201703L
139 #define constinit_cxx20 constinit
140#else
141 #define constinit_cxx20 constexpr
142#endif
143
144 /**
145 * `constexpr` qualifier replacement for C++20 `constexpr`.
146 *
147 * > A `constexpr` specifier used in a function or static member variable (since C++17) declaration implies `inline`.
148 *
149 * <p>
150 * Evaluated using the alternative qualifier `inline` for C++ < 20,
151 * as it is implied for `constexpr` functions or static member variables, see above.
152 * </p>
153 * <p>
154 * Evaluated as `constexpr` for C++20, i.e. std::string literals, virtual functions, etc.
155 * </p>
156 */
157#if __cplusplus > 201703L
158 #define constexpr_cxx20 constexpr
159#else
160 #define constexpr_cxx20 inline
161#endif
162
163#if __cplusplus > 202002L
164 #define constexpr_cxx23 constexpr
165#else
166 #define constexpr_cxx23 inline
167#endif
168
169#if __cplusplus > 202302L
170 #define constexpr_cxx26 constexpr
171#else
172 #define constexpr_cxx26 inline
173#endif
174
175
176 /**
177 * Used when designed to declare a function `constexpr`,
178 * but prohibited by its specific implementation.
179 * <p>
180 * Evaluated using the alternative qualifier `inline` for C++ < 20,
181 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx20.
182 * </p>
183 * <p>
184 * Here it but uses non-literal variables, such as std::lock_guard etc.
185 * As these can't be evaluated at compile time, the standard does
186 * not allow using `constexpr` here.
187 * </p>
188 * <p>
189 * Empty until standard defines otherwise.
190 * </p>
191 * @see constexpr_cxx20
192 */
193 #define constexpr_non_literal_var inline
194
195 /**
196 * Used when designed to declare a function `constexpr`,
197 * but prohibited by its specific implementation.
198 * <p>
199 * Evaluated using the alternative qualifier `inline` for C++ < 20,
200 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx20.
201 * </p>
202 * <p>
203 * Here it uses thread-safety related measures like atomic storage
204 * or mutex locks, which are non-literal variables and hence
205 * prohibit the use of `constexpr`.
206 * </p>
207 * @see constexpr_cxx20
208 * @see constexpr_non_literal_var
209 */
210 #define constexpr_atomic inline
211
212 /**
213 * Wrap C++ extension `__restrict__` covering C99's `restrict` feature keyword.
214 */
215#if defined(__clang__)
216 #define __restrict_cxx__ __restrict__
217#elif defined(__GNUC__) && !defined(__clang__)
218 #define __restrict_cxx__ __restrict__
219#elif defined(_MSC_VER)
220 #define __restrict_cxx__ __restrict
221#else
222 #define __restrict_cxx__
223#endif
224
225 #if defined(__clang__)
226 #if __has_feature(cxx_rtti)
227 /**
228 * Set define if RTTI is enabled during compilation,
229 * implying its runtime availability.
230 * <pre>
231 * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
232 * - g++ ('__GNUC__') may have '__GXX_RTTI'
233 * - msvc (_MSC_VER) may have: '_CPPRTTI'
234 * </pre>
235 */
236 #define __cxx_rtti_available__ 1
237 #endif
238 #else
239 #if defined(__GXX_RTTI) || defined(_CPPRTTI)
240 /**
241 * Set define if RTTI is enabled during compilation,
242 * implying its runtime availability.
243 * <pre>
244 * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
245 * - g++ ('__GNUC__') may have '__GXX_RTTI'
246 * - msvc (_MSC_VER) may have: '_CPPRTTI'
247 * </pre>
248 */
249 #define __cxx_rtti_available__ 1
250 #endif
251 #endif
252
253#if defined(__cxx_rtti_available__)
254 /**
255 * Template type trait evaluating std::true_type{} if RTTI is available, otherwise std::false_type{}
256 * @tparam _Dummy unused dummy type to satisfy SFINAE
257 */
258 template<typename _Dummy> struct is_rtti_available_t : std::true_type {};
259#else
260 /**
261 * Template type trait evaluating std::true_type{} if RTTI is available, otherwise std::false_type{}
262 * @tparam _Dummy unused dummy type to satisfy SFINAE
263 */
264 template<typename _Dummy> struct is_rtti_available_t : std::false_type {};
265#endif
266
267 /**
268 * Template type trait helper evaluating true if RTTI is available, otherwise false
269 * @tparam _Dummy unused dummy type to satisfy SFINAE
270 */
271 template <typename _Dummy> inline constexpr bool is_rtti_available_v = is_rtti_available_t<_Dummy>::value;
272
273 /** Returns true if compiled with RTTI available */
275 #if defined(__cxx_rtti_available__)
276 return true;
277 #else
278 return false;
279 #endif
280 }
281
282 #if defined(__clang__)
283 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
284 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
285 #elif defined(__GNUC__) && !defined(__clang__)
286 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
287 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
288 #elif defined(_MSC_VER)
289 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
290 #define JAU_PRETTY_FUNCTION __FUNCSIG__
291 #else
292 #error "JAU_PRETTY_FUNCTION not available"
293 #endif
294
295 /**
296 * @anchor ctti_name_type
297 * Returns the type name of given type `T`
298 * using template *Compile Time Type Information (CTTI)* only
299 * with static constant storage duration.
300 *
301 * @tparam T the type
302 * @return instance of jau::type_info
303 * @see @ref make_ctti_type "jau::make_ctti<T>"
304 * @see @ref ctti_name_lambda
305 */
306 template<typename T>
307 constexpr const char* ctti_name() noexcept {
308 return JAU_PRETTY_FUNCTION;
309 }
310
311 /**
312 * @anchor ctti_name_lambda
313 * Returns the type name of given function types `R(*L)(A...)`
314 * using template *Compile Time Type Information (CTTI)* only
315 * with static constant storage duration.
316 *
317 * @anchor ctti_name_lambda_limitations
318 * #### Limitations
319 *
320 * ##### Non unique function pointer type names with same prototype
321 * With RTTI or wihout, c-alike function pointer type names like `int(*)(int)` do not expose their
322 * source location like lambda functions do.
323 * Hence they can't be used to compare code identity, but lambda functions can be used.
324 *
325 * ##### Non unique lambda type names without RTTI using `gcc` or non `clang` compiler
326 * Due to the lack of standardized *Compile-Time Type Information (CTTI)*,
327 * we rely on the non-standardized macro extensions
328 * - `__PRETTY_FUNCTION__`
329 * - `clang` produces a unique tag using filename and line number, compatible.
330 * - `gcc` produces a non-unique tag using the parent function of the lambda location and its too brief signature, not fully compatible.
331 * - `__FUNCSIG__`
332 * - `msvc++` not tested
333 * - Any other compiler is not supported yet
334 *
335 * Due to these restrictions, *not using RTTI on `gcc` or non `clang` compiler* will *erroneously mistake* different lambda
336 * *functions defined within one function and using same function prototype `R<A...>`* to be the same.
337 *
338 * jau::type_info::limited_lambda_id exposes the potential limitation.
339 *
340 * @tparam R function return type
341 * @tparam L main function type, e.g. a lambda type.
342 * @tparam A function argument types
343 * @return instance of jau::type_info
344 * @see @ref make_ctti_lambda "jau::make_ctti<R, L, A...>"
345 * @see @ref ctti_name_type
346 * @see jau::type_info::limited_lambda_id
347 */
348 template<typename R, typename L, typename...A>
349 constexpr const char* ctti_name() noexcept {
350 return JAU_PRETTY_FUNCTION;
351 }
352
353 /**
354 * Returns the demangled given mangled_name if successful,
355 * otherwise the mangled_name.
356 *
357 * Implementation utilizes the [cross-vendor C++ ABI abi::__cxa_demangle()](https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
358 * as supported at least on on `gcc` and `clang`.
359 *
360 * May be used to demangle the result of jau::type_name() or jau::type_info::name() if jau::type_info::rtti_available == true,
361 * i.e. RTTI typeif(T) symbols are being used.
362 *
363 * See also [gcc libstdc++ FAQ, Chapter 28](https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html).
364 *
365 * Further, implementation also checks whether the mangled_name results from [jau::ctti_name<T>()](@ref ctti_name_type)
366 * and cleans up the known `gcc` and `clang` variant of JAU_PRETTY_FUNCTION.
367 *
368 * @param mangled_name mangled name
369 */
370 std::string demangle_name(const char* mangled_name) noexcept;
371
372 /**
373 * Generic type information using either *Runtime type information* (RTTI) or *Compile time type information* (CTTI)
374 *
375 * @anchor type_info jau::type_info exposes same properties as RTTI std::type_index,
376 * i.e. can be used as index in associative and unordered associative containers
377 * and is CopyConstructible and CopyAssignable.
378 *
379 * jau::type_info is compatible with std::type_index operations.
380 *
381 * jau::type_info can be utilized w/o RTTI using
382 * *Compile time type information* (CTTI) information, i.e. JAU_PRETTY_FUNCTION via [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda).
383 *
384 * Consider using [jau::make_ctti<R, L, A...>()](@ref make_ctti_lambda) for construction,
385 * as it removes the RTTI and CTTI code path differences.
386 *
387 * ### RTTI and Compile time type information (CTTI) Natures
388 *
389 * If RTTI is being used, see __cxx_rtti_available__,
390 * jau::type_info may be instantiated with a std::type_info reference as returned from typeid(T).
391 *
392 * Without RTTI jau::type_info may be instantiated using JAU_PRETTY_FUNCTION.
393 * Hence utilizes Compile time type information (CTTI) only.
394 *
395 * In both cases, jau::type_info will solely operate on the `const char* signature`
396 * and its hash value, aligning memory footprint and operations.
397 *
398 * Use [jau::make_ctti<R, L, A...>()](@ref make_ctti_lambda) for construction,
399 * as it removes the RTTI and CTTI code path differences.
400 *
401 * @anchor type_info_identity
402 * ### Notes about lifecycle and identity
403 *
404 * #### Prologue
405 * We assume block scope and static storage duration (runtime lifecycle) of
406 * - (1) [typeid(T)]((https://en.cppreference.com/w/cpp/language/typeid)
407 * - (1.1) The typeid expression is an lvalue expression which refers to an object with static storage duration.
408 * - (1.2) There is no guarantee that the same std::type_info instance will be referred to by all evaluations
409 * of the typeid expression on the same type, although they would compare equal.
410 * - (2) JAU_PRETTY_FUNCTION, aka __PRETTY_FUNCTION__ with properties of [__func__](https://en.cppreference.com/w/cpp/language/function)
411 * - (2.1) This variable has block scope and static storage duration.
412 *
413 * #### Equality Comparison
414 *
415 * - compare the static name storage references (pointer) and return `true` if equal (fast path)
416 * - due to (1.2), see above, the static name storage strings must be compared
417 * - compare the names' hash value and return `false` if not matching (fast path)
418 * - compare the static names' string and return the result (slow `strcmp()` equality)
419 * - this avoids a potential hash collision.
420 *
421 * @anchor type_info_limitations
422 * #### Limitations
423 *
424 * ##### Non unique lambda type names without RTTI using `gcc` or non `clang` compiler
425 *
426 * Due to [limitations of jau::make_ctti<R, L, A...>()](@ref ctti_name_lambda_limitations),
427 * *not using RTTI on `gcc` or non `clang` compiler* will *erroneously mistake* different lambda
428 * *functions defined within one function and using same function prototype `R<A...>`* to be the same.
429 *
430 * jau::type_info::limited_lambda_id exposes the potential limitation.
431 *
432 * @see @ref type_info_identity "Identity"
433 * @see @ref make_ctti_lambda "jau::make_ctti<R, L, A...>"
434 */
435 class type_info {
436 private:
437 const char* signature;
438 size_t hash_value;
439
440 public:
441 /**
442 * Static constexpr boolean indicating whether resulting type_info
443 * uniqueness is limited for lambda function types.
444 *
445 * Always is `false` if rtti_available == `true`,
446 * i.e. lambda function types are always unique using RTTI.
447 *
448 * May return `true` if:
449 * - no RTTI and using `gcc`
450 * - no RTTI and not using `clang`
451 *
452 * @see @ref ctti_name_lambda_limitations "CTTI lambda name limitations"
453 */
454 static constexpr const bool limited_lambda_id =
455 #if defined(__cxx_rtti_available__)
456 false;
457 #else
458 #if defined(__clang__)
459 false;
460 #elif defined(__GNUC__) && !defined(__clang__)
461 true;
462 #else
463 true; // unknown
464 #endif
465 #endif
466
467 /** Returns true if given signature is not nullptr and has a string length > 0, otherwise false. */
468 static constexpr bool is_valid(const char* signature) noexcept {
469 return nullptr != signature && 0 < ::strlen(signature);
470 }
471
472 /** Aborts program execution if given signature is nullptr or has a string length == 0. */
473 static void abort_invalid(const char* signature) noexcept {
474 if( nullptr == signature ) {
475 fprintf(stderr, "ABORT @ %s:%d %s: CTTI signature nullptr\n", __FILE__, __LINE__, __func__);
476 ::abort();
477 } else if( 0 == ::strlen(signature) ) {
478 fprintf(stderr, "ABORT @ %s:%d %s: CTTI signature zero sized\n", __FILE__, __LINE__, __func__);
479 ::abort();
480 }
481 }
482
483 /**
484 * Constructor for an empty type_info instance, i.e. empty name() signature.
485 */
486 type_info() noexcept
487 : signature(""), hash_value( std::hash<std::string_view>{}(std::string_view(signature)) )
488 { }
489
490 /**
491 * Constructor using an RTTI std::type_info reference, i.e. typeid(T) result.
492 *
493 * Consider using [jau::make_ctti<R, L, A...>()](@ref make_ctti_lambda) for construction,
494 * as it removes the RTTI and CTTI code path differences.
495 *
496 * @param info_ RTTI std::type_info reference
497 *
498 * @see @ref make_ctti_lambda "jau::make_ctti<R, L, A...>"
499 */
500 type_info(const std::type_info& info_) noexcept
501 : signature(info_.name()), hash_value( info_.hash_code() )
502 { }
503
504 /**
505 * Constructor using a `const char*` signature with a static storage duration
506 *
507 * Aborts program execution if given signature is nullptr or has a string length == 0.
508 *
509 * @param signature_ valid string signature of type with length > 0 with static storage duration.
510 *
511 * @see @ref make_ctti_lambda "jau::make_ctti<R, L, A...>"
512 */
513 type_info(const char* signature_) noexcept
514 : signature( signature_ ), hash_value( nullptr != signature ? std::hash<std::string_view>{}(std::string_view(signature)) : 0 )
515 { abort_invalid(signature); }
516
517 /**
518 * Return true if both instances are equal.
519 *
520 * @param rhs
521 * @return
522 * @see @ref type_info_identity "Identity"
523 */
524 constexpr bool operator==(const type_info& rhs) const noexcept {
525 if( &rhs == this ) {
526 return true;
527 }
528 return signature == rhs.signature || // fast: pointer comparison, which may fail on same types, _or_
529 (
530 hash_value == rhs.hash_value && // fast: wrong hash value -> false, otherwise avoid hash collision case ...
531 0 == ::strcmp(signature, rhs.signature) // slow: string comparison
532 );
533 }
534
535 bool operator!=(const type_info& rhs) const noexcept
536 { return !operator==(rhs); }
537
538 /**
539 * Returns an unspecified hash code of this instance.
540 *
541 * @anchor type_info_hash_code
542 * Properties
543 * - for all type_info objects referring to the same type, their hash code is the same.
544 * - type_info objects referring to different types may have the same hash code, i.e. due to hash collision.
545 *
546 * Compatible with std::type_info definition.
547 *
548 * @return Unspecified hash code of this instance.
549 * @see @ref type_info_identity "Identity"
550 */
551 size_t hash_code() const noexcept { return hash_value; }
552
553 /** Returns the type name, compiler implementation specific. */
554 const char* name() const noexcept
555 { return signature; }
556
557 /** Return the demangle_name() of name(). */
558 std::string demangled_name() const noexcept {
559 return demangle_name( signature );
560 }
561 };
562
563 /**
564 * Constructs a jau::type_info instance based on given type `T`
565 * using template *Compile Time Type Information (CTTI)* only.
566 *
567 * @anchor make_ctti_type
568 * This construction function either uses `typeid(T)` if jau::type_info::rtti_available == true
569 * or [jau::ctti_name<T>()](@ref ctti_name_type) otherwise.
570 *
571 * @tparam T type for which the type_info is generated
572 * @return instance of jau::type_info
573 * @see @ref ctti_name_type "jau::ctti_name<T>"
574 */
575 template<typename T>
577#if defined(__cxx_rtti_available__)
578 return jau::type_info( typeid(T) );
579#else
580 return jau::type_info(ctti_name<T>());
581#endif
582 }
583
584 /**
585 * Constructs a jau::type_info instance based on given function types `R(*L)(A...)`
586 * using template *Compile Time Type Information (CTTI)* only
587 * via RTTI's `typeid(L) if available or [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda) otherwise.
588 *
589 * @anchor make_ctti_lambda
590 * This construction function either uses `typeid(L)` if jau::type_info::rtti_available == true
591 * or [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda) otherwise.
592 *
593 * @tparam R function return type used for type_info in case of jau::type_info::rtti_available == false
594 * @tparam L main function type for which the type_info is generated, e.g. a lambda type.
595 * @tparam A function argument types used for type_info in case of jau::type_info::rtti_available == false
596 * @return instance of jau::type_info
597 * @see @ref ctti_name_lambda "jau::ctti_name<R, L, A...>"
598 */
599 template<typename R, typename L, typename...A>
601#if defined(__cxx_rtti_available__)
602 return jau::type_info( typeid(L) );
603#else
604 return jau::type_info(ctti_name<R, L, A...>());
605#endif
606 }
607
608 /**
609 * Returns the type name of given type `T`
610 * using template *Compile Time Type Information (CTTI)* only
611 * via RTTI's `typeid(T).name()` if available or [jau::ctti_name<T>()](@ref ctti_name_type) otherwise.
612 *
613 * @tparam T type for which the type_info is generated
614 * @return type name
615 * @see @ref ctti_name_type "jau::ctti_name<T>"
616 */
617 template<typename T>
618 const char* type_name() noexcept {
619#if defined(__cxx_rtti_available__)
620 return typeid(T).name();
621#else
622 return ctti_name<T>();
623#endif
624 }
625
626 /**
627 * Returns the type name of given function types `R(*L)(A...)`
628 * using template *Compile Time Type Information (CTTI)* only
629 * via RTTI's `typeid(L).name()` if available or [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda) otherwise.
630 *
631 * @tparam R function return type used for type_info in case of jau::type_info::rtti_available == false
632 * @tparam L main function type for which the type_info is generated, e.g. a lambda type.
633 * @tparam A function argument types used for type_info in case of jau::type_info::rtti_available == false
634 * @return type name
635 * @see @ref ctti_name_lambda "jau::ctti_name<R, L, A...>"
636 */
637 template<typename R, typename L, typename...A>
638 const char* type_name() noexcept {
639#if defined(__cxx_rtti_available__)
640 return typeid(L).name();
641#else
642 return ctti_name<R, L, A...>();
643#endif
644 }
645
646 /**
647 // *************************************************
648 // *************************************************
649 // *************************************************
650 */
651
652 #if defined __has_builtin
653 #if __has_builtin(__builtin_bit_cast)
654 #define __has_builtin_bit_cast 1
655 #endif
656 #endif
657
658 /**
659 * Convenience type trait for `__has_builtin(__builtin_bit_cast)`.
660 * @tparam Dummy_type just to make template `SFINAE` happy
661 * @see jau::is_builtin_bit_cast_available()
662 * @see jau::bit_cast()
663 * @see jau::pointer_cast()
664 */
665 template <typename Dummy_type>
667 #if defined __has_builtin_bit_cast
668 : std::true_type
669 #else
670 : std::false_type
671 #endif
672 {};
673 /**
674 * Value access of has_builtin_bit_cast type trait for convenience ..
675 * @tparam Dummy_type just to make template `SFINAE` happy
676 * @see has_builtin_bit_cast
677 */
678 template <typename Dummy_type> constexpr bool has_builtin_bit_cast_v = has_builtin_bit_cast<Dummy_type>::value;
679
680 #if !defined __has_builtin_bit_cast
681 /**
682 * Dummy definition in the absence of this builtin function
683 * as required to have this compilation unit compile clean.
684 * @param Dest_type the target type
685 * @param Value_arg the source value argument
686 */
687 #define __builtin_bit_cast(Dest_type,Value_arg) 0
688 #endif
689
690 namespace impl {
691 template<class Dummy_type>
693 std::enable_if_t< has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
694 {
695 return true;
696 }
697
698 template<class Dummy_type>
700 std::enable_if_t< !has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
701 {
702 return false;
703 }
704 }
705
706 /**
707 * Query whether `__builtin_bit_cast(Dest_type, arg)` is available, using jau::has_builtin_bit_cast.
708 *
709 * - - - - - - - - - - - - - - -
710 *
711 * Availability of `__builtin_bit_cast(Dest_type, arg)`
712 *
713 * Reflecting my manual platform tests using `test_basictypeconv.cpp`
714 *
715 * Compiler | Version | Architecture | Available |
716 * :--------- | -------: | :------------------ | :-------- |
717 * GCC | 8.3.0 | amd64, arm64, arm32 | no |
718 * GCC | 10.2.1 | amd64 | no |
719 * GCC | 12.2.0 | amd64 | yes |
720 * clang | 9.0.1 | amd64, arm64 | yes |
721 * clang | 11.0.1 | amd64 | yes |
722 *
723 * @return `true` if query subject is available, otherwise not.
724 * @see has_builtin_bit_cast
725 * @see bit_cast()
726 * @see pointer_cast()
727 */
729 return impl::has_builtin_bit_cast_impl<bool>();
730 }
731
732 /**
733 * C++20 `bit_cast<>(arg)` implementation for C++17.
734 * <p>
735 * Functional if is_builtin_bit_cast_available() evaluates `true`.
736 * </p>
737 * @tparam Dest the target type
738 * @tparam Source the source argument type
739 * @param src the value to convert to Dest type
740 * @return the converted Dest type value
741 * @see jau::has_builtin_bit_cast
742 * @see is_builtin_bit_cast_available()
743 * @see pointer_cast()
744 */
745 template <class Dest, class Source>
746 constexpr
747 typename std::enable_if_t<
748 sizeof(Dest) == sizeof(Source) &&
749 std::is_trivially_copyable_v<Dest> &&
750 std::is_trivially_copyable_v<Source>,
751 Dest>
752 bit_cast(const Source& src) noexcept
753 {
754 if constexpr ( is_builtin_bit_cast_available() ) {
755 return __builtin_bit_cast(Dest, src);
756 } else {
757 (void)src;
758 return 0;
759 }
760 }
761
762 /**
763 * A `constexpr` pointer cast implementation for C++17,
764 * inspired by C++20 `bit_cast<>(arg)`.
765 * <p>
766 * If is_builtin_bit_cast_available() evaluates `true`,
767 * implementation uses `__builtin_bit_cast(Dest, src)`.<br>
768 *
769 * Otherwise a simple `reinterpret_cast<Dest>(src)` is utilized,
770 * which officially is questionable to deliver a `constexpr`.
771 * </p>
772 * @tparam Dest the target pointer type
773 * @tparam Source the source pointer argument type
774 * @param src the pointer to convert to Dest pointer type
775 * @return the converted Dest pointer type value
776 * @see jau::has_builtin_bit_cast
777 * @see is_builtin_bit_cast_available()
778 * @see bit_cast()
779 */
780 template <class Dest, class Source>
781 constexpr
782 typename std::enable_if_t<
783 sizeof(Dest) == sizeof(Source) &&
784 std::is_pointer_v<Source> &&
785 std::is_pointer_v<Dest>,
786 Dest>
787 pointer_cast(const Source& src) noexcept
788 {
789 if constexpr ( is_builtin_bit_cast_available() ) {
790 return __builtin_bit_cast(Dest, src);
791 } else {
792 // not 'really' constexpr .. oops, working though
793 return reinterpret_cast<Dest>( const_cast< std::remove_const_t< std::remove_pointer_t<Source> >* >( src ) );
794 }
795 }
796
798 #if defined(__SIZEOF_INT128__)
799 return true;
800 #else
801 return false;
802 #endif
803 }
804
805 #if defined(__SIZEOF_INT128__)
806 // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode
807 #if defined(__GNUG__)
808 typedef int int128_t __attribute__((mode(TI)));
809 typedef unsigned int uint128_t __attribute__((mode(TI)));
810 #else
811 typedef __int128 int128_t;
812 typedef unsigned __int128 uint128_t;
813 #endif
814 #endif
815
816 /** Returns true if compiled with debug information and w/o optimization, i.e. not `defined(NDEBUG) && !defined(DEBUG)`. */
818 #if defined(NDEBUG) && !defined(DEBUG)
819 return false;
820 #else
821 return true;
822 #endif
823 }
824
825 /**@}*/
826
827} // namespace jau
828
829#endif /* JAU_CPP_LANG_EXT_HPP_ */
Generic type information using either Runtime type information (RTTI) or Compile time type informatio...
static constexpr bool is_valid(const char *signature) noexcept
Returns true if given signature is not nullptr and has a string length > 0, otherwise false.
static void abort_invalid(const char *signature) noexcept
Aborts program execution if given signature is nullptr or has a string length == 0.
type_info() noexcept
Constructor for an empty type_info instance, i.e.
size_t hash_code() const noexcept
Returns an unspecified hash code of this instance.
type_info(const char *signature_) noexcept
Constructor using a const char* signature with a static storage duration.
static constexpr const bool limited_lambda_id
Static constexpr boolean indicating whether resulting type_info uniqueness is limited for lambda func...
const char * name() const noexcept
Returns the type name, compiler implementation specific.
std::string demangled_name() const noexcept
Return the demangle_name() of name().
constexpr bool operator==(const type_info &rhs) const noexcept
Return true if both instances are equal.
bool operator!=(const type_info &rhs) const noexcept
type_info(const std::type_info &info_) noexcept
Constructor using an RTTI std::type_info reference, i.e.
consteval_cxx20 bool is_rtti_available() noexcept
Returns true if compiled with RTTI available.
jau::type_info make_ctti() noexcept
Constructs a jau::type_info instance based on given type T using template Compile Time Type Informati...
consteval_cxx20 bool is_builtin_int128_available() noexcept
consteval_cxx20 bool is_cxx23() noexcept
Returns true if compiled with >= C++23.
consteval_cxx20 bool is_cxx20() noexcept
Returns true if compiled with >= C++20.
constexpr bool has_builtin_bit_cast_v
Value access of has_builtin_bit_cast type trait for convenience .
consteval_cxx20 bool is_cxx17() noexcept
Returns true if compiled with >= C++17.
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_trivially_copyable_v< Dest > &&std::is_trivially_copyable_v< Source >, Dest > bit_cast(const Source &src) noexcept
C++20 bit_cast<>(arg) implementation for C++17.
consteval_cxx20 bool is_debug_enabled() noexcept
Returns true if compiled with debug information and w/o optimization, i.e.
constexpr const char * ctti_name() noexcept
Returns the type name of given type T using template Compile Time Type Information (CTTI) only with s...
constexpr bool is_rtti_available_v
Template type trait helper evaluating true if RTTI is available, otherwise false.
std::string demangle_name(const char *mangled_name) noexcept
Returns the demangled given mangled_name if successful, otherwise the mangled_name.
Definition: debug.cpp:57
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_pointer_v< Source > &&std::is_pointer_v< Dest >, Dest > pointer_cast(const Source &src) noexcept
A constexpr pointer cast implementation for C++17, inspired by C++20 bit_cast<>(arg).
#define __builtin_bit_cast(Dest_type, Value_arg)
Dummy definition in the absence of this builtin function as required to have this compilation unit co...
#define consteval_cxx20
consteval qualifier replacement for C++20 consteval.
const char * type_name() noexcept
Returns the type name of given type T using template Compile Time Type Information (CTTI) only via RT...
consteval_cxx20 bool is_builtin_bit_cast_available() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available, using jau::has_builtin_bit_cast.
consteval_cxx20 bool is_cxx26() noexcept
Returns true if compiled with >= C++26.
consteval_cxx20 bool has_builtin_bit_cast_impl(std::enable_if_t< has_builtin_bit_cast_v< Dummy_type >, bool >=true) noexcept
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
STL namespace.
Convenience type trait for __has_builtin(__builtin_bit_cast).
Template type trait evaluating std::true_type{} if RTTI is available, otherwise std::false_type{}.