jaulib v1.5.0
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
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 <climits>
29#include <cstdint>
30#include <string_view>
31#include <type_traits>
32#include <exception>
33#include <string>
34#include <cstring>
35#include <ostream>
36#if __cplusplus > 201703L
37 // C++20
38 #include <bit>
39#endif
40#if __cplusplus > 202002L
41 // C++23
42 #include <stdbit>
43#endif
44
46
47namespace jau {
48
49 /** @defgroup CppLang C++ Language Utilities
50 * C++ language utilities, language feature alignment, type trails, data alignment and intrinsics.
51 *
52 * Used predefined `__cplusplus` macro identifier for C++ language specs:
53 * - `199711L`: pre C++11
54 * - `201103L`: C++11
55 * - `201402L`: C++14
56 * - `201703L`: C++17
57 * - `202002L`: C++20
58 * - `202302L`: C++23
59 * - `??????L`: C++26 ??
60 *
61 * Used predefined macros denoting the compiler:
62 * - `__clang__` : LLVM's clang, clang++
63 * - `__GNUC__` : GNU Compiler Collection (GCC)'s gcc, g++
64 * - `_MSC_VER` : Microsoft Compiler
65 * - `__MINGW32__` : MinGW 32
66 * - `__MINGW64__` : MinGW 64
67 * - `__EMSCRIPTEN__`: emscripten for asm.js and WebAssembly
68 *
69 * Further infos:
70 * - [Unix standards](https://sourceforge.net/p/predef/wiki/Standards/)
71 * - [GNU glibc](https://sourceforge.net/p/predef/wiki/Libraries/)
72 * - [glibc 1.3.4 Feature Test Macros](https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html)
73 * - [Architectures](https://sourceforge.net/p/predef/wiki/Architectures/)
74 *
75 * @{
76 */
77
78 /**
79 * `consteval` qualifier replacement for C++20 `consteval`.
80 *
81 * > A `consteval` specifier implies `inline`.
82 * > At most one of the `constexpr`, `consteval`, and `constinit` specifiers is allowed to appear within the same sequence of declaration specifiers.
83 * > ...
84 * > An immediate function is a `constexpr` function,
85 * > and must satisfy the requirements applicable to `constexpr` functions or `constexpr` constructors, as the case may be.
86 *
87 * <p>
88 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
89 * as it is almost contained within `consteval` but lacks the `immediate function` constraint.
90 * </p>
91 * <p>
92 * Evaluated as `consteval` for C++20.
93 * </p>
94 */
95#if __cplusplus > 201703L
96 #define consteval_cxx20 consteval
97#else
98 #define consteval_cxx20 constexpr
99#endif
100
101 /** Returns true if compiled with >= C++17 */
102 consteval_cxx20 bool is_cxx17() noexcept {
103 #if __cplusplus > 201402L
104 return true;
105 #else
106 return false;
107 #endif
108 }
109 /** Returns true if compiled with >= C++20 */
110 consteval_cxx20 bool is_cxx20() noexcept {
111 #if __cplusplus > 201703L
112 return true;
113 #else
114 return false;
115 #endif
116 }
117 /** Returns true if compiled with >= C++23 */
118 consteval_cxx20 bool is_cxx23() noexcept {
119 #if __cplusplus > 202002L
120 return true;
121 #else
122 return false;
123 #endif
124 }
125 /** Returns true if compiled with >= C++26 */
126 consteval_cxx20 bool is_cxx26() noexcept {
127 #if __cplusplus > 202302L
128 return true;
129 #else
130 return false;
131 #endif
132 }
133
134 /**
135 * `constinit` qualifier replacement for C++20 `constinit`.
136 *
137 * > `constinit` cannot be used together with `constexpr` or `consteval`.
138 * > When the declared variable is a reference, `constinit` is equivalent to `constexpr`.
139 * > When the declared variable is an object,
140 * > `constexpr` mandates that the object must have static initialization and constant destruction
141 * > and makes the object const-qualified, however, `constinit` does not mandate constant destruction and const-qualification.
142 *
143 * <p>
144 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
145 * as it is almost contained within `constinit` but lacks the loosening of not mandating constant destruction and const-qualification.<br>
146 * FIXME: Due to the above, this replacement might not be suitable: TBD!
147 * </p>
148 * <p>
149 * Evaluated as `constinit` for C++20.
150 * </p>
151 */
152#if __cplusplus > 201703L
153 #define constinit_cxx20 constinit
154#else
155 #define constinit_cxx20 constexpr
156#endif
157
158 /**
159 * `constexpr` qualifier replacement for C++20 `constexpr`.
160 *
161 * > A `constexpr` specifier used in a function or static member variable (since C++17) declaration implies `inline`.
162 *
163 * <p>
164 * Evaluated using the alternative qualifier `inline` for C++ < 20,
165 * as it is implied for `constexpr` functions or static member variables, see above.
166 * </p>
167 * <p>
168 * Evaluated as `constexpr` for C++20, i.e. std::string literals, virtual functions, etc.
169 * </p>
170 */
171#if __cplusplus > 201703L
172 #define constexpr_cxx20 constexpr
173#else
174 #define constexpr_cxx20 inline
175#endif
176
177#if __cplusplus > 202002L
178 #define constexpr_cxx23 constexpr
179#else
180 #define constexpr_cxx23 inline
181#endif
182
183#if __cplusplus > 202302L
184 #define constexpr_cxx26 constexpr
185#else
186 #define constexpr_cxx26 inline
187#endif
188
189
190 /**
191 * Used when designed to declare a function `constexpr`,
192 * but prohibited by its specific implementation.
193 * <p>
194 * Evaluated using the alternative qualifier `inline` for C++ < 23,
195 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx23.
196 * </p>
197 * <p>
198 * Here it but uses non-literal variables, such as std::lock_guard etc.
199 * As these can't be evaluated at compile time, the standard does
200 * not allow using `constexpr` here.
201 * </p>
202 * <p>
203 * Empty until standard defines otherwise.
204 * </p>
205 * @see constexpr_cxx23
206 */
207 #define constexpr_non_literal_var constexpr_cxx23
208
209 /**
210 * Used when designed to declare a function `constexpr`,
211 * but prohibited by its specific implementation.
212 * <p>
213 * Evaluated using the alternative qualifier `inline` for C++ < 23,
214 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx23.
215 * </p>
216 * <p>
217 * Here it uses thread-safety related measures like atomic storage
218 * or mutex locks, which are non-literal variables and hence
219 * prohibit the use of `constexpr`.
220 * </p>
221 * @see constexpr_cxx23
222 * @see constexpr_non_literal_var
223 */
224 #define constexpr_atomic constexpr_cxx23
225
226 /**
227 * Wrap C++ extension `__restrict__` covering C99's `restrict` feature keyword.
228 */
229 #if defined(__clang__)
230 #define __restrict_cxx__ __restrict__
231 #elif defined(__GNUC__) && !defined(__clang__)
232 #define __restrict_cxx__ __restrict__
233 #elif defined(_MSC_VER)
234 #define __restrict_cxx__ __restrict
235 #else
236 #define __restrict_cxx__
237 #endif
238
239 #if defined(__clang__)
240 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
241 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
242 #elif defined(__GNUC__) && !defined(__clang__)
243 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
244 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
245 #elif defined(_MSC_VER)
246 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
247 #define JAU_PRETTY_FUNCTION __FUNCSIG__
248 #else
249 #error "JAU_PRETTY_FUNCTION not available"
250 #endif
251
252 /**
253 * Returns the demangled given mangled_name if successful,
254 * otherwise the mangled_name.
255 *
256 * Implementation utilizes the [cross-vendor C++ ABI abi::__cxa_demangle()](https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
257 * as supported at least on on `gcc` and `clang`.
258 *
259 * May be used to demangle the result of jau::type_name() or jau::type_info::name() if jau::type_info::rtti_available == true,
260 * i.e. RTTI typeif(T) symbols are being used.
261 *
262 * See also [gcc libstdc++ FAQ, Chapter 28](https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html).
263 *
264 * Further, implementation also checks whether the mangled_name results from [jau::ctti_name<T>()](@ref ctti_name_type)
265 * and cleans up the known `gcc` and `clang` variant of JAU_PRETTY_FUNCTION.
266 *
267 * @param mangled_name mangled name
268 */
269 std::string demangle_name(const char* mangled_name) noexcept;
270
271 #if defined(__clang__)
272 /** Optional generic usage of final keyword w/o negative performance impact. (Disabled) */
273 #define final_opt
274 #elif defined(__GNUC__) && !defined(__clang__)
275 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled) */
276 #define final_opt final
277 #elif defined(_MSC_VER)
278 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled, OK?) */
279 #define final_opt final
280 #else
281 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled, OK?) */
282 #define final_opt final
283 #endif
284
285 /**
286 // *************************************************
287 // *************************************************
288 // *************************************************
289 */
290
291 /**
292 * Convenience type trait for `__has_builtin(__builtin_bit_cast)`.
293 * @tparam Dummy_type just to make template `SFINAE` happy
294 * @see jau::has_builtin_bit_cast()
295 * @see jau::bit_cast()
296 * @see jau::pointer_cast()
297 */
298 template <typename Dummy_type>
300 #if defined __has_builtin && __has_builtin(__builtin_bit_cast)
301 : std::true_type
302 #else
303 : std::false_type
304 #endif
305 {};
306 /**
307 * Value access of has_builtin_bit_cast type trait for convenience ..
308 * @tparam Dummy_type just to make template `SFINAE` happy
309 * @see has_builtin_bit_cast
310 */
311 template <typename Dummy_type> constexpr bool has_builtin_bit_cast_v = has_builtin_bit_cast_t<Dummy_type>::value;
312
313 /**
314 * Query whether `__builtin_bit_cast(Dest_type, arg)` is available
315 * via `__has_builtin(__builtin_bit_cast)`.
316 *
317 * - - - - - - - - - - - - - - -
318 *
319 * Availability of `__builtin_bit_cast(Dest_type, arg)`
320 *
321 * Reflecting my manual platform tests using `test_basictypeconv.cpp`
322 *
323 * Compiler | Version | Architecture | Available |
324 * :--------- | -------: | :------------------ | :-------- |
325 * GCC | 8.3.0 | amd64, arm64, arm32 | no |
326 * GCC | 10.2.1 | amd64 | no |
327 * GCC | 12.2.0 | amd64 | yes |
328 * clang | 9.0.1 | amd64, arm64 | yes |
329 * clang | 11.0.1 | amd64 | yes |
330 *
331 * @return `true` if query subject is available, otherwise not.
332 * @see has_builtin_bit_cast_t
333 * @see bit_cast()
334 * @see pointer_cast()
335 */
337 #if defined __has_builtin && __has_builtin(__builtin_bit_cast)
338 return true;
339 #else
340 return false;
341 #endif
342 }
343
344 /**
345 * A `constexpr` pointer cast implementation for C++17,
346 * inspired by C++20 `bit_cast<>(arg)`.
347 * <p>
348 * If is_builtin_bit_cast_available() evaluates `true`,
349 * implementation uses `__builtin_bit_cast(Dest, src)`.<br>
350 *
351 * Otherwise a simple `reinterpret_cast<Dest>(src)` is utilized,
352 * which officially is questionable to deliver a `constexpr`.
353 * </p>
354 * @tparam Dest the target pointer type
355 * @tparam Source the source pointer argument type
356 * @param src the pointer to convert to Dest pointer type
357 * @return the converted Dest pointer type value
358 * @see jau::has_builtin_bit_cast
359 * @see is_builtin_bit_cast_available()
360 * @see bit_cast()
361 */
362 template <class Dest, class Source>
363 constexpr
364 typename std::enable_if_t<
365 sizeof(Dest) == sizeof(Source) && // NOLINT(bugprone-sizeof-expression): Intended, same pointer size
366 std::is_pointer_v<Source> &&
367 std::is_pointer_v<Dest>,
368 Dest>
369 pointer_cast(const Source& src) noexcept
370 {
371 if constexpr ( is_cxx20() ) {
372 return std::bit_cast<Dest, Source>(src); // NOLINT(bugprone-bitwise-pointer-cast): intentional
373 } else if constexpr ( has_builtin_bit_cast() ) {
374 return __builtin_bit_cast(Dest, src);
375 } else {
376 // not 'really' constexpr .. oops, working though
377 return reinterpret_cast<Dest>( const_cast< std::remove_const_t< std::remove_pointer_t<Source> >* >( src ) );
378 }
379 }
380
381 /**
382 * C++20 `bit_cast<>(arg)` implementation for C++17.
383 * <p>
384 * Utilizing native bit_cast if is_builtin_bit_cast_available(), otherwise `pointer_cast<const packed_t<Dest>*>( &src )->store`.
385 * </p>
386 * @tparam Dest the target type
387 * @tparam Source the source argument type
388 * @param src the value to convert to Dest type
389 * @return the converted Dest type value
390 * @see jau::has_builtin_bit_cast
391 * @see is_builtin_bit_cast_available()
392 * @see pointer_cast()
393 */
394 template <class Dest, class Source>
395 constexpr
396 typename std::enable_if_t<
397 sizeof(Dest) == sizeof(Source) &&
398 std::is_trivially_copyable_v<Dest> &&
399 std::is_trivially_copyable_v<Source>,
400 Dest>
401 bit_cast(const Source& src) noexcept
402 {
403 if constexpr ( is_cxx20() ) {
404 return std::bit_cast<Dest, Source>(src);
405 } else if constexpr ( has_builtin_bit_cast() ) {
406 return __builtin_bit_cast(Dest, src);
407 } else {
408 return pointer_cast<const packed_t<Dest>*>( &src )->store;
409 }
410 }
411
413 #if defined(__SIZEOF_INT128__)
414 return true;
415 #else
416 return false;
417 #endif
418 }
419
420 #if defined(__SIZEOF_INT128__)
421 // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode
422 #if defined(__GNUG__)
423 typedef int int128_t __attribute__((mode(TI)));
424 typedef unsigned int uint128_t __attribute__((mode(TI)));
425 #else
426 typedef __int128 int128_t;
427 typedef unsigned __int128 uint128_t;
428 #endif
429 #endif
430
431 /** Returns true if compiled with debug information and w/o optimization, i.e. not `defined(NDEBUG) && !defined(DEBUG)`. */
433 #if defined(NDEBUG) && !defined(DEBUG)
434 return false;
435 #else
436 return true;
437 #endif
438 }
439
440 #if defined(__clang__)
441 #define __attrdecl_no_optimize__ __attribute__ ((optnone))
442 #define __attrdef_no_optimize__ __attribute__ ((optnone))
443 #elif defined(__GNUC__) && !defined(__clang__)
444 #define __attrdecl_no_optimize__ __attribute__((optimize("O0")))
445 // #define __attrdecl_no_optimize__ [[gnu::optimize("O0")]]
446 #define __attrdef_no_optimize__
447 #else
448 #define __attrdecl_no_optimize__
449 #define __attrdef_no_optimize__
450 #endif
451
452 /**
453 * Simple unary function wrapper which ensures function call to happen in order and not optimized away.
454 */
455 template <typename UnaryFunc>
457 // asm asm-qualifiers ( AssemblerTemplate : OutputOperands [ : InputOperands [ : Clobbers ] ] )
458 asm volatile("" : "+r,m"(f) : : "memory"); // a nop asm, usually guaranteeing synchronized order and non-optimization
459 f();
460 }
461
462 /**@}*/
463
464 /** \addtogroup Exceptions
465 *
466 * @{
467 */
468
469 /**
470 * Handle given optional exception (nullable std::exception_ptr) and send std::exception::what() message to `stderr`
471 * @param eptr contains optional exception, may be `nullptr`
472 * @return true if `eptr` contained an exception pointer, false otherwise (`nullptr`)
473 */
474 inline __attribute__((always_inline))
475 bool handle_exception(std::exception_ptr eptr, const char* file, int line) noexcept { // NOLINT(performance-unnecessary-value-param) passing by value is OK
476 if (eptr) {
477 try {
478 std::rethrow_exception(eptr);
479 } catch (const std::exception &e) {
480 ::fprintf(stderr, "Exception caught @ %s:%d: %s\n", file, line, e.what());
481 return true;
482 }
483 }
484 return false;
485 }
486
487 /// No throw wrap for given unary predicate `p` action. Returns true for success (no exception), otherwise false (exception occurred).
488 template<class UnaryPredicate>
489 inline bool do_noexcept(UnaryPredicate p) noexcept {
490 std::exception_ptr eptr;
491 try {
492 p();
493 return true;
494 } catch (...) {
495 eptr = std::current_exception();
496 }
497 return !handle_exception(eptr, __FILE__, __LINE__);
498 }
499
500 /**@}*/
501
502 /** \addtogroup StringUtils
503 *
504 * @{
505 */
506
507 /// No throw wrap for given unary predicate `p` producing a `std::string`. Returns an empty string if `p` causes an exception.
508 template<class UnaryPredicate>
509 inline std::string string_noexcept(UnaryPredicate p) noexcept {
510 std::exception_ptr eptr;
511 try {
512 return p();
513 } catch (...) {
514 eptr = std::current_exception();
515 }
516 handle_exception(eptr, __FILE__, __LINE__);
517 return std::string();
518 }
519
520 /// No throw `std::string(std::string_view)` instantiation
521 inline std::string string_noexcept(std::string_view v) noexcept {
522 return string_noexcept([v]() { return std::string(v); });
523 }
524
525 /**@}*/
526
527 /** \addtogroup CppLang
528 *
529 * @{
530 */
531
532 /// Boolean type without implicit conversion, safe for function parameter
533 enum class Bool : bool {
534 False = false,
535 True = true
536 };
537 constexpr Bool True() noexcept { return Bool::True; }
538 constexpr Bool False() noexcept { return Bool::False; }
539 constexpr Bool makeBool(bool v) noexcept { return v ? Bool::True : Bool::False; }
540
541 constexpr bool value(const Bool rhs) noexcept {
542 return static_cast<bool>(rhs);
543 }
544 constexpr bool operator*(const Bool rhs) noexcept {
545 return static_cast<bool>(rhs);
546 }
547 constexpr Bool operator!(const Bool rhs) noexcept {
548 return Bool(!*rhs);
549 }
550 constexpr Bool operator&&(const Bool lhs, const Bool rhs) noexcept {
551 return Bool(*lhs && *rhs);
552 }
553 constexpr Bool operator||(const Bool lhs, const Bool rhs) noexcept {
554 return Bool(*lhs || *rhs);
555 }
556 constexpr Bool operator^(const Bool lhs, const Bool rhs) noexcept {
557 return Bool(*lhs ^ *rhs);
558 }
559 constexpr Bool operator|(const Bool lhs, const Bool rhs) noexcept {
560 return Bool(*lhs || *rhs);
561 }
562 constexpr Bool operator&(const Bool lhs, const Bool rhs) noexcept {
563 return Bool(*lhs && *rhs);
564 }
565 constexpr Bool& operator|=(Bool& lhs, const Bool rhs) noexcept {
566 lhs = lhs | rhs;
567 return lhs;
568 }
569 constexpr Bool& operator&=(Bool& lhs, const Bool rhs) noexcept {
570 lhs = lhs & rhs;
571 return lhs;
572 }
573 constexpr Bool& operator^=(Bool& lhs, const Bool rhs) noexcept {
574 lhs = lhs ^ rhs;
575 return lhs;
576 }
577 constexpr bool operator==(const Bool lhs, const Bool rhs) noexcept {
578 return *lhs == *rhs;
579 }
580 constexpr std::string_view name(const Bool v) noexcept {
581 if( *v ) {
582 return "true";
583 } else {
584 return "false";
585 }
586 }
587 inline std::string to_string(const Bool v) noexcept {
588 return string_noexcept([v]() { return std::string(name(v)); });
589 }
590 inline std::ostream & operator << (std::ostream &out, const Bool c) {
591 out << to_string(c);
592 return out;
593 }
594
595 //
596 //
597 //
598
599 /** Simple pre-defined value pair [size_t, bool] for structured bindings to multi-values. */
601 /** a size_t value, e.g. index, length, etc */
602 size_t s;
603 /** a boolean value, e.g. success, etc */
604 bool b;
605 };
606 /** Simple pre-defined value pair [uint8_t*, size_t, bool] for structured bindings to multi-values. */
608 /** a uint8_t* pointer value */
609 uint8_t* p;
610 /** a size_t value, e.g. index, length, etc */
611 size_t s;
612 /** a boolean value, e.g. success, etc */
613 bool b;
614 };
615
616 /** Simple pre-defined value tuple [uint64_t, size_t, bool] for structured bindings to multi-values. */
618 /** a uint64_t value, e.g. compute result value, etc */
619 uint64_t v;
620 /** a size_t value, e.g. index, length, etc */
621 size_t s;
622 /** a boolean value, e.g. success, etc */
623 bool b;
624 };
625
626 /** Simple pre-defined value tuple [int64_t, size_t, bool] for structured bindings to multi-values. */
628 /** a int64_t value, e.g. compute result value, etc */
629 int64_t v;
630 /** a size_t value, e.g. index, length, etc */
631 size_t s;
632 /** a boolean value, e.g. success, etc */
633 bool b;
634 };
635
636 //
637 //
638 //
639
640 namespace impl {
641 inline bool runtime_eval(bool v) { return v; }
642 }
643
645 [[maybe_unused]] bool r = v ? true : impl::runtime_eval(v);
646 }
647
648 /**@}*/
649
650} // namespace jau
651
652/** \addtogroup CppLang
653 *
654 * @{
655 */
656
657#define E_FILE_LINE __FILE__, __LINE__
658
659//
660// JAU_FOR_EACH macros inspired by David Mazières, June 2021
661// <https://www.scs.stanford.edu/~dm/blog/va-opt.html>
662//
663// All hacks below to circumvent lack of C++26 reflection.
664//
665
666// Note space before (), so object-like macro
667#define JAU_PARENS ()
668
669#define JAU_EXPAND(...) JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(JAU_EXPAND4(__VA_ARGS__))))
670#define JAU_EXPAND4(...) JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(JAU_EXPAND3(__VA_ARGS__))))
671#define JAU_EXPAND3(...) JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(JAU_EXPAND2(__VA_ARGS__))))
672#define JAU_EXPAND2(...) JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(JAU_EXPAND1(__VA_ARGS__))))
673#define JAU_EXPAND1(...) __VA_ARGS__
674
675// Macro w/ 1 arguments
676
677#define JAU_FOR_EACH1_LIST(macro, ...) \
678 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH1_LIST_HELPER(macro, __VA_ARGS__)))
679#define JAU_FOR_EACH1_LIST_HELPER(macro, a1, ...) \
680 macro(a1) \
681 __VA_OPT__(, JAU_FOR_EACH1_LIST_AGAIN JAU_PARENS (macro, __VA_ARGS__))
682#define JAU_FOR_EACH1_LIST_AGAIN() JAU_FOR_EACH1_LIST_HELPER
683
684#define JAU_DECLTYPE_VALUE(type) decltype(type)
685#define JAU_NOREF_DECLTYPE_VALUE(type) std::remove_reference_t<decltype(type)>
686
687// Macro w/ 2 arguments
688
689#define JAU_FOR_EACH2(macro, type, ...) \
690 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH2_HELPER(macro, type, __VA_ARGS__)))
691#define JAU_FOR_EACH2_HELPER(macro, type, a1, ...) \
692 macro(type, a1) \
693 __VA_OPT__(JAU_FOR_EACH2_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
694#define JAU_FOR_EACH2_AGAIN() JAU_FOR_EACH2_HELPER
695
696#define JAU_FOR_EACH2_LIST(macro, type, ...) \
697 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH2_LIST_HELPER(macro, type, __VA_ARGS__)))
698#define JAU_FOR_EACH2_LIST_HELPER(macro, type, a1, ...) \
699 macro(type, a1) \
700 __VA_OPT__(, JAU_FOR_EACH2_LIST_AGAIN JAU_PARENS (macro, type, __VA_ARGS__))
701#define JAU_FOR_EACH2_LIST_AGAIN() JAU_FOR_EACH2_LIST_HELPER
702
703#define JAU_FOR_EACH2_VALUE(macro, type, value, ...) \
704 __VA_OPT__(JAU_EXPAND(JAU_FOR_EACH2_VALUE_HELPER(macro, type, value, __VA_ARGS__)))
705#define JAU_FOR_EACH2_VALUE_HELPER(macro, type, value, a1, ...) \
706 macro(type, a1, value) \
707 __VA_OPT__(JAU_FOR_EACH2_VALUE_AGAIN JAU_PARENS (macro, type, value, __VA_ARGS__))
708#define JAU_FOR_EACH2_VALUE_AGAIN() JAU_FOR_EACH2_VALUE_HELPER
709
710/**@}*/
711
712#endif /* JAU_CPP_LANG_EXT_HPP_ */
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
std::ostream & operator<<(std::ostream &out, const bitfield_t< StorageType, BitSize > &v)
Definition bitfield.hpp:495
consteval_cxx20 bool is_builtin_int128_available() noexcept
constexpr bool value(const Bool rhs) noexcept
constexpr bool operator*(const Bool rhs) noexcept
constexpr Bool & operator&=(Bool &lhs, const Bool rhs) noexcept
constexpr Bool makeBool(bool v) noexcept
constexpr Bool & operator^=(Bool &lhs, const Bool rhs) noexcept
consteval_cxx20 bool is_cxx23() noexcept
Returns true if compiled with >= C++23.
void callNotOptimize(UnaryFunc f) __attrdef_no_optimize__
Simple unary function wrapper which ensures function call to happen in order and not optimized away.
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 .
constexpr Bool False() noexcept
constexpr Bool operator^(const Bool lhs, const Bool rhs) noexcept
consteval_cxx20 bool is_cxx17() noexcept
Returns true if compiled with >= C++17.
constexpr Bool operator|(const Bool lhs, const Bool rhs) noexcept
constexpr Bool True() noexcept
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 Bool operator&(const Bool lhs, const Bool rhs) noexcept
constexpr Bool operator&&(const Bool lhs, const Bool rhs) noexcept
constexpr Bool & operator|=(Bool &lhs, const Bool rhs) noexcept
consteval_cxx20 bool has_builtin_bit_cast() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available via __has_builtin(__builtin_bit_cast).
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).
consteval_cxx20 void consteval_assert(bool v)
constexpr Bool operator||(const Bool lhs, const Bool rhs) noexcept
std::string demangle_name(const char *mangled_name) noexcept
Returns the demangled given mangled_name if successful, otherwise the mangled_name.
Definition debug.cpp:59
#define __attrdef_no_optimize__
constexpr std::string_view name(const Bool v) noexcept
constexpr Bool operator!(const Bool rhs) noexcept
#define consteval_cxx20
consteval qualifier replacement for C++20 consteval.
consteval_cxx20 bool is_cxx26() noexcept
Returns true if compiled with >= C++26.
Bool
Boolean type without implicit conversion, safe for function parameter.
bool handle_exception(std::exception_ptr eptr, const char *file, int line) noexcept
Handle given optional exception (nullable std::exception_ptr) and send std::exception::what() message...
bool do_noexcept(UnaryPredicate p) noexcept
No throw wrap for given unary predicate p action. Returns true for success (no exception),...
std::string string_noexcept(UnaryPredicate p) noexcept
No throw wrap for given unary predicate p producing a std::string. Returns an empty string if p cause...
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
STL namespace.
Simple pre-defined value tuple [int64_t, size_t, bool] for structured bindings to multi-values.
size_t s
a size_t value, e.g.
bool b
a boolean value, e.g.
int64_t v
a int64_t value, e.g.
Simple pre-defined value pair [size_t, bool] for structured bindings to multi-values.
size_t s
a size_t value, e.g.
bool b
a boolean value, e.g.
Simple pre-defined value tuple [uint64_t, size_t, bool] for structured bindings to multi-values.
bool b
a boolean value, e.g.
uint64_t v
a uint64_t value, e.g.
size_t s
a size_t value, e.g.
Simple pre-defined value pair [uint8_t*, size_t, bool] for structured bindings to multi-values.
uint8_t * p
a uint8_t* pointer value
bool b
a boolean value, e.g.
size_t s
a size_t value, e.g.
Convenience type trait for __has_builtin(__builtin_bit_cast).
static std::string f(uint32_t v)