jaulib v1.3.6
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 <type_traits>
29#include <string>
30#include <cstring>
31#include <ostream>
33
34namespace jau {
35
36 /** @defgroup CppLang C++ Language Utilities
37 * C++ language utilities, language feature alignment, type trails, data alignment and intrinsics.
38 *
39 * Used predefined `__cplusplus` macro identifier for C++ language specs:
40 * - `199711L`: pre C++11
41 * - `201103L`: C++11
42 * - `201402L`: C++14
43 * - `201703L`: C++17
44 * - `202002L`: C++20
45 * - `202302L`: C++23
46 * - `??????L`: C++26 ??
47 *
48 * Used predefined macros denoting the compiler:
49 * - `__clang__` : LLVM's clang, clang++
50 * - `__GNUC__` : GNU Compiler Collection (GCC)'s gcc, g++
51 * - `_MSC_VER` : Microsoft Compiler
52 * - `__MINGW32__` : MinGW 32
53 * - `__MINGW64__` : MinGW 64
54 * - `__EMSCRIPTEN__`: emscripten for asm.js and WebAssembly
55 *
56 * Further infos:
57 * - [Unix standards](https://sourceforge.net/p/predef/wiki/Standards/)
58 * - [GNU glibc](https://sourceforge.net/p/predef/wiki/Libraries/)
59 * - [glibc 1.3.4 Feature Test Macros](https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html)
60 * - [Architectures](https://sourceforge.net/p/predef/wiki/Architectures/)
61 *
62 * @{
63 */
64
65 /**
66 * `consteval` qualifier replacement for C++20 `consteval`.
67 *
68 * > A `consteval` specifier implies `inline`.
69 * > At most one of the `constexpr`, `consteval`, and `constinit` specifiers is allowed to appear within the same sequence of declaration specifiers.
70 * > ...
71 * > An immediate function is a `constexpr` function,
72 * > and must satisfy the requirements applicable to `constexpr` functions or `constexpr` constructors, as the case may be.
73 *
74 * <p>
75 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
76 * as it is almost contained within `consteval` but lacks the `immediate function` constraint.
77 * </p>
78 * <p>
79 * Evaluated as `consteval` for C++20.
80 * </p>
81 */
82#if __cplusplus > 201703L
83 #define consteval_cxx20 consteval
84#else
85 #define consteval_cxx20 constexpr
86#endif
87
88 /** Returns true if compiled with >= C++17 */
89 consteval_cxx20 bool is_cxx17() noexcept {
90 #if __cplusplus > 201402L
91 return true;
92 #else
93 return false;
94 #endif
95 }
96 /** Returns true if compiled with >= C++20 */
97 consteval_cxx20 bool is_cxx20() noexcept {
98 #if __cplusplus > 201703L
99 return true;
100 #else
101 return false;
102 #endif
103 }
104 /** Returns true if compiled with >= C++23 */
105 consteval_cxx20 bool is_cxx23() noexcept {
106 #if __cplusplus > 202002L
107 return true;
108 #else
109 return false;
110 #endif
111 }
112 /** Returns true if compiled with >= C++26 */
113 consteval_cxx20 bool is_cxx26() noexcept {
114 #if __cplusplus > 202302L
115 return true;
116 #else
117 return false;
118 #endif
119 }
120
121 /**
122 * `constinit` qualifier replacement for C++20 `constinit`.
123 *
124 * > `constinit` cannot be used together with `constexpr` or `consteval`.
125 * > When the declared variable is a reference, `constinit` is equivalent to `constexpr`.
126 * > When the declared variable is an object,
127 * > `constexpr` mandates that the object must have static initialization and constant destruction
128 * > and makes the object const-qualified, however, `constinit` does not mandate constant destruction and const-qualification.
129 *
130 * <p>
131 * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
132 * as it is almost contained within `constinit` but lacks the loosening of not mandating constant destruction and const-qualification.<br>
133 * FIXME: Due to the above, this replacement might not be suitable: TBD!
134 * </p>
135 * <p>
136 * Evaluated as `constinit` for C++20.
137 * </p>
138 */
139#if __cplusplus > 201703L
140 #define constinit_cxx20 constinit
141#else
142 #define constinit_cxx20 constexpr
143#endif
144
145 /**
146 * `constexpr` qualifier replacement for C++20 `constexpr`.
147 *
148 * > A `constexpr` specifier used in a function or static member variable (since C++17) declaration implies `inline`.
149 *
150 * <p>
151 * Evaluated using the alternative qualifier `inline` for C++ < 20,
152 * as it is implied for `constexpr` functions or static member variables, see above.
153 * </p>
154 * <p>
155 * Evaluated as `constexpr` for C++20, i.e. std::string literals, virtual functions, etc.
156 * </p>
157 */
158#if __cplusplus > 201703L
159 #define constexpr_cxx20 constexpr
160#else
161 #define constexpr_cxx20 inline
162#endif
163
164#if __cplusplus > 202002L
165 #define constexpr_cxx23 constexpr
166#else
167 #define constexpr_cxx23 inline
168#endif
169
170#if __cplusplus > 202302L
171 #define constexpr_cxx26 constexpr
172#else
173 #define constexpr_cxx26 inline
174#endif
175
176
177 /**
178 * Used when designed to declare a function `constexpr`,
179 * but prohibited by its specific implementation.
180 * <p>
181 * Evaluated using the alternative qualifier `inline` for C++ < 23,
182 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx23.
183 * </p>
184 * <p>
185 * Here it but uses non-literal variables, such as std::lock_guard etc.
186 * As these can't be evaluated at compile time, the standard does
187 * not allow using `constexpr` here.
188 * </p>
189 * <p>
190 * Empty until standard defines otherwise.
191 * </p>
192 * @see constexpr_cxx23
193 */
194 #define constexpr_non_literal_var constexpr_cxx23
195
196 /**
197 * Used when designed to declare a function `constexpr`,
198 * but prohibited by its specific implementation.
199 * <p>
200 * Evaluated using the alternative qualifier `inline` for C++ < 23,
201 * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx23.
202 * </p>
203 * <p>
204 * Here it uses thread-safety related measures like atomic storage
205 * or mutex locks, which are non-literal variables and hence
206 * prohibit the use of `constexpr`.
207 * </p>
208 * @see constexpr_cxx23
209 * @see constexpr_non_literal_var
210 */
211 #define constexpr_atomic constexpr_cxx23
212
213 /**
214 * Wrap C++ extension `__restrict__` covering C99's `restrict` feature keyword.
215 */
216 #if defined(__clang__)
217 #define __restrict_cxx__ __restrict__
218 #elif defined(__GNUC__) && !defined(__clang__)
219 #define __restrict_cxx__ __restrict__
220 #elif defined(_MSC_VER)
221 #define __restrict_cxx__ __restrict
222 #else
223 #define __restrict_cxx__
224 #endif
225
226 #if defined(__clang__)
227 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
228 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
229 #elif defined(__GNUC__) && !defined(__clang__)
230 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
231 #define JAU_PRETTY_FUNCTION __PRETTY_FUNCTION__
232 #elif defined(_MSC_VER)
233 /** Consider using [jau::ctti_name<R, L, A...>()](@ref ctti_name_lambda). */
234 #define JAU_PRETTY_FUNCTION __FUNCSIG__
235 #else
236 #error "JAU_PRETTY_FUNCTION not available"
237 #endif
238
239 /**
240 * Returns the demangled given mangled_name if successful,
241 * otherwise the mangled_name.
242 *
243 * Implementation utilizes the [cross-vendor C++ ABI abi::__cxa_demangle()](https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
244 * as supported at least on on `gcc` and `clang`.
245 *
246 * May be used to demangle the result of jau::type_name() or jau::type_info::name() if jau::type_info::rtti_available == true,
247 * i.e. RTTI typeif(T) symbols are being used.
248 *
249 * See also [gcc libstdc++ FAQ, Chapter 28](https://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html).
250 *
251 * Further, implementation also checks whether the mangled_name results from [jau::ctti_name<T>()](@ref ctti_name_type)
252 * and cleans up the known `gcc` and `clang` variant of JAU_PRETTY_FUNCTION.
253 *
254 * @param mangled_name mangled name
255 */
256 std::string demangle_name(const char* mangled_name) noexcept;
257
258 #if defined(__clang__)
259 /** Optional generic usage of final keyword w/o negative performance impact. (Disabled) */
260 #define final_opt
261 #elif defined(__GNUC__) && !defined(__clang__)
262 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled) */
263 #define final_opt final
264 #elif defined(_MSC_VER)
265 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled, OK?) */
266 #define final_opt final
267 #else
268 /** Optional generic usage of final keyword w/o negative performance impact. (Enabled, OK?) */
269 #define final_opt final
270 #endif
271
272 /**
273 // *************************************************
274 // *************************************************
275 // *************************************************
276 */
277
278 /**
279 * Convenience type trait for `__has_builtin(__builtin_bit_cast)`.
280 * @tparam Dummy_type just to make template `SFINAE` happy
281 * @see jau::has_builtin_bit_cast()
282 * @see jau::bit_cast()
283 * @see jau::pointer_cast()
284 */
285 template <typename Dummy_type>
287 #if defined __has_builtin && __has_builtin(__builtin_bit_cast)
288 : std::true_type
289 #else
290 : std::false_type
291 #endif
292 {};
293 /**
294 * Value access of has_builtin_bit_cast type trait for convenience ..
295 * @tparam Dummy_type just to make template `SFINAE` happy
296 * @see has_builtin_bit_cast
297 */
298 template <typename Dummy_type> constexpr bool has_builtin_bit_cast_v = has_builtin_bit_cast_t<Dummy_type>::value;
299
300 /**
301 * Query whether `__builtin_bit_cast(Dest_type, arg)` is available
302 * via `__has_builtin(__builtin_bit_cast)`.
303 *
304 * - - - - - - - - - - - - - - -
305 *
306 * Availability of `__builtin_bit_cast(Dest_type, arg)`
307 *
308 * Reflecting my manual platform tests using `test_basictypeconv.cpp`
309 *
310 * Compiler | Version | Architecture | Available |
311 * :--------- | -------: | :------------------ | :-------- |
312 * GCC | 8.3.0 | amd64, arm64, arm32 | no |
313 * GCC | 10.2.1 | amd64 | no |
314 * GCC | 12.2.0 | amd64 | yes |
315 * clang | 9.0.1 | amd64, arm64 | yes |
316 * clang | 11.0.1 | amd64 | yes |
317 *
318 * @return `true` if query subject is available, otherwise not.
319 * @see has_builtin_bit_cast_t
320 * @see bit_cast()
321 * @see pointer_cast()
322 */
324 #if defined __has_builtin && __has_builtin(__builtin_bit_cast)
325 return true;
326 #else
327 return false;
328 #endif
329 }
330
331 /**
332 * A `constexpr` pointer cast implementation for C++17,
333 * inspired by C++20 `bit_cast<>(arg)`.
334 * <p>
335 * If is_builtin_bit_cast_available() evaluates `true`,
336 * implementation uses `__builtin_bit_cast(Dest, src)`.<br>
337 *
338 * Otherwise a simple `reinterpret_cast<Dest>(src)` is utilized,
339 * which officially is questionable to deliver a `constexpr`.
340 * </p>
341 * @tparam Dest the target pointer type
342 * @tparam Source the source pointer argument type
343 * @param src the pointer to convert to Dest pointer type
344 * @return the converted Dest pointer type value
345 * @see jau::has_builtin_bit_cast
346 * @see is_builtin_bit_cast_available()
347 * @see bit_cast()
348 */
349 template <class Dest, class Source>
350 constexpr
351 typename std::enable_if_t<
352 sizeof(Dest) == sizeof(Source) && // NOLINT(bugprone-sizeof-expression): Intended, same pointer size
353 std::is_pointer_v<Source> &&
354 std::is_pointer_v<Dest>,
355 Dest>
356 pointer_cast(const Source& src) noexcept
357 {
358 if constexpr ( has_builtin_bit_cast() ) {
359 return __builtin_bit_cast(Dest, src);
360 } else {
361 // not 'really' constexpr .. oops, working though
362 return reinterpret_cast<Dest>( const_cast< std::remove_const_t< std::remove_pointer_t<Source> >* >( src ) );
363 }
364 }
365
366 /**
367 * C++20 `bit_cast<>(arg)` implementation for C++17.
368 * <p>
369 * Utilizing native bit_cast if is_builtin_bit_cast_available(), otherwise `pointer_cast<const packed_t<Dest>*>( &src )->store`.
370 * </p>
371 * @tparam Dest the target type
372 * @tparam Source the source argument type
373 * @param src the value to convert to Dest type
374 * @return the converted Dest type value
375 * @see jau::has_builtin_bit_cast
376 * @see is_builtin_bit_cast_available()
377 * @see pointer_cast()
378 */
379 template <class Dest, class Source>
380 constexpr
381 typename std::enable_if_t<
382 sizeof(Dest) == sizeof(Source) &&
383 std::is_trivially_copyable_v<Dest> &&
384 std::is_trivially_copyable_v<Source>,
385 Dest>
386 bit_cast(const Source& src) noexcept
387 {
388 if constexpr ( has_builtin_bit_cast() ) {
389 return __builtin_bit_cast(Dest, src);
390 } else {
391 return pointer_cast<const packed_t<Dest>*>( &src )->store;
392 }
393 }
394
396 #if defined(__SIZEOF_INT128__)
397 return true;
398 #else
399 return false;
400 #endif
401 }
402
403 #if defined(__SIZEOF_INT128__)
404 // Prefer TI mode over __int128 as GCC rejects the latter in pendantic mode
405 #if defined(__GNUG__)
406 typedef int int128_t __attribute__((mode(TI)));
407 typedef unsigned int uint128_t __attribute__((mode(TI)));
408 #else
409 typedef __int128 int128_t;
410 typedef unsigned __int128 uint128_t;
411 #endif
412 #endif
413
414 /** Returns true if compiled with debug information and w/o optimization, i.e. not `defined(NDEBUG) && !defined(DEBUG)`. */
416 #if defined(NDEBUG) && !defined(DEBUG)
417 return false;
418 #else
419 return true;
420 #endif
421 }
422
423 #if defined(__clang__)
424 #define __attrdecl_no_optimize__ __attribute__ ((optnone))
425 #define __attrdef_no_optimize__ __attribute__ ((optnone))
426 #elif defined(__GNUC__) && !defined(__clang__)
427 #define __attrdecl_no_optimize__ __attribute__((optimize("O0")))
428 // #define __attrdecl_no_optimize__ [[gnu::optimize("O0")]]
429 #define __attrdef_no_optimize__
430 #else
431 #define __attrdecl_no_optimize__
432 #define __attrdef_no_optimize__
433 #endif
434
435 /**
436 * Simple unary function wrapper which ensures function call to happen in order and not optimized away.
437 */
438 template <typename UnaryFunc>
439 inline void callNotOptimize(UnaryFunc f) __attrdef_no_optimize__ {
440 // asm asm-qualifiers ( AssemblerTemplate : OutputOperands [ : InputOperands [ : Clobbers ] ] )
441 asm volatile("" : "+r,m"(f) : : "memory"); // a nop asm, usually guaranteeing synchronized order and non-optimization
442 f();
443 }
444
445 /// Boolean type without implicit conversion, safe for function parameter
446 enum class Bool : bool {
447 False = false,
448 True = true
449 };
450 constexpr Bool True() noexcept { return Bool::True; }
451 constexpr Bool False() noexcept { return Bool::False; }
452
453 constexpr bool value(const Bool rhs) noexcept {
454 return static_cast<bool>(rhs);
455 }
456 constexpr bool operator*(const Bool rhs) noexcept {
457 return static_cast<bool>(rhs);
458 }
459 constexpr Bool operator!(const Bool rhs) noexcept {
460 return Bool(!*rhs);
461 }
462 constexpr Bool operator&&(const Bool lhs, const Bool rhs) noexcept {
463 return Bool(*lhs && *rhs);
464 }
465 constexpr Bool operator||(const Bool lhs, const Bool rhs) noexcept {
466 return Bool(*lhs || *rhs);
467 }
468 constexpr Bool operator^(const Bool lhs, const Bool rhs) noexcept {
469 return Bool(*lhs ^ *rhs);
470 }
471 constexpr Bool operator|(const Bool lhs, const Bool rhs) noexcept {
472 return Bool(*lhs || *rhs);
473 }
474 constexpr Bool operator&(const Bool lhs, const Bool rhs) noexcept {
475 return Bool(*lhs && *rhs);
476 }
477 constexpr Bool& operator|=(Bool& lhs, const Bool rhs) noexcept {
478 lhs = lhs | rhs;
479 return lhs;
480 }
481 constexpr Bool& operator&=(Bool& lhs, const Bool rhs) noexcept {
482 lhs = lhs & rhs;
483 return lhs;
484 }
485 constexpr Bool& operator^=(Bool& lhs, const Bool rhs) noexcept {
486 lhs = lhs ^ rhs;
487 return lhs;
488 }
489 constexpr bool operator==(const Bool lhs, const Bool rhs) noexcept {
490 return *lhs == *rhs;
491 }
492 constexpr std::string_view name(const Bool v) noexcept {
493 if( *v ) {
494 return "true";
495 } else {
496 return "false";
497 }
498 }
499 constexpr std::string to_string(const Bool v) noexcept { return std::string(name(v)); }
500 inline std::ostream & operator << (std::ostream &out, const Bool c) {
501 out << to_string(c);
502 return out;
503 }
504
505 /**@}*/
506
507} // namespace jau
508
509#endif /* JAU_CPP_LANG_EXT_HPP_ */
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
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 & 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).
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:57
#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.
std::ostream & operator<<(std::ostream &out, const cow_darray< Value_type, Size_type, Alloc_type > &c)
__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.
Convenience type trait for __has_builtin(__builtin_bit_cast).