Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
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 CPP_LANG_EXT_HPP_
26 #define CPP_LANG_EXT_HPP_
27 
28 #include <type_traits>
29 
30 namespace jau {
31 
32  /**
33  * `consteval` qualifier replacement for C++20 `consteval`.
34  *
35  * > A `consteval` specifier implies `inline`.
36  * > At most one of the `constexpr`, `consteval`, and `constinit` specifiers is allowed to appear within the same sequence of declaration specifiers.
37  * > ...
38  * > An immediate function is a `constexpr` function,
39  * > and must satisfy the requirements applicable to `constexpr` functions or `constexpr` constructors, as the case may be.
40  *
41  * <p>
42  * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
43  * as it is almost contained within `consteval` but lacks the `immediate function` constraint.
44  * </p>
45  * <p>
46  * Evaluated as `consteval` for C++20.
47  * </p>
48  */
49 #if __cplusplus > 201703L
50  #define consteval_cxx20 consteval
51 #else
52  #define consteval_cxx20 constexpr
53 #endif
54 
55  /**
56  * `constinit` qualifier replacement for C++20 `constinit`.
57  *
58  * > `constinit` cannot be used together with `constexpr` or `consteval`.
59  * > When the declared variable is a reference, `constinit` is equivalent to `constexpr`.
60  * > When the declared variable is an object,
61  * > `constexpr` mandates that the object must have static initialization and constant destruction
62  * > and makes the object const-qualified, however, `constinit` does not mandate constant destruction and const-qualification.
63  *
64  * <p>
65  * Evaluated using the alternative qualifier `constexpr` for C++ < 20,
66  * as it is almost contained within `constinit` but lacks the loosening of not mandating constant destruction and const-qualification.<br>
67  * FIXME: Due to the above, this replacement might not be suitable: TBD!
68  * </p>
69  * <p>
70  * Evaluated as `constinit` for C++20.
71  * </p>
72  */
73 #if __cplusplus > 201703L
74  #define constinit_cxx20 constinit
75 #else
76  #define constinit_cxx20 constexpr
77 #endif
78 
79  /**
80  * `constexpr` qualifier replacement for C++20 `constexpr`.
81  *
82  * > A `constexpr` specifier used in a function or static member variable (since C++17) declaration implies `inline`.
83  *
84  * <p>
85  * Evaluated using the alternative qualifier `inline` for C++ < 20,
86  * as it is implied for `constexpr` functions or static member variables, see above.
87  * </p>
88  * <p>
89  * Evaluated as `constexpr` for C++20, i.e. std::string literals, virtual functions, etc.
90  * </p>
91  */
92 #if __cplusplus > 201703L
93  #define constexpr_cxx20 constexpr
94 #else
95  #define constexpr_cxx20 inline
96 #endif
97 
98  /**
99  * Used when designed to declare a function `constexpr`,
100  * but prohibited by its specific implementation.
101  * <p>
102  * Evaluated using the alternative qualifier `inline` for C++ < 20,
103  * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx20.
104  * </p>
105  * <p>
106  * Here it but uses non-literal variables, such as std::lock_guard etc.
107  * As these can't be evaluated at compile time, the standard does
108  * not allow using `constexpr` here.
109  * </p>
110  * <p>
111  * Empty until standard defines otherwise.
112  * </p>
113  * @see constexpr_cxx20
114  */
115  #define constexpr_non_literal_var inline
116 
117  /**
118  * Used when designed to declare a function `constexpr`,
119  * but prohibited by its specific implementation.
120  * <p>
121  * Evaluated using the alternative qualifier `inline` for C++ < 20,
122  * as it is implied for `constexpr` functions or static member variables, see constexpr_cxx20.
123  * </p>
124  * <p>
125  * Here it uses thread-safety related measures like atomic storage
126  * or mutex locks, which are non-literal variables and hence
127  * prohibit the use of `constexpr`.
128  * </p>
129  * @see constexpr_cxx20
130  * @see constexpr_non_literal_var
131  */
132  #define constexpr_atomic inline
133 
134  #if defined(__clang__)
135  #if __has_feature(cxx_rtti)
136  /**
137  * Set define if RTTI is enabled during compilation,
138  * implying its runtime availability.
139  * <pre>
140  * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
141  * - g++ ('__GNUC__') may have '__GXX_RTTI'
142  * - msvc (_MSC_VER) may have: '_CPPRTTI'
143  * </pre>
144  */
145  #define __cxx_rtti_available__ 1
146  #endif
147  #else
148  #if defined(__GXX_RTTI) || defined(_CPPRTTI)
149  /**
150  * Set define if RTTI is enabled during compilation,
151  * implying its runtime availability.
152  * <pre>
153  * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
154  * - g++ ('__GNUC__') may have '__GXX_RTTI'
155  * - msvc (_MSC_VER) may have: '_CPPRTTI'
156  * </pre>
157  */
158  #define __cxx_rtti_available__ 1
159  #endif
160  #endif
161 
162  /**
163  // *************************************************
164  // *************************************************
165  // *************************************************
166  */
167 
168  #if defined __has_builtin
169  #if __has_builtin(__builtin_bit_cast)
170  #define __has_builtin_bit_cast 1
171  #endif
172  #endif
173 
174  /**
175  * Convenience type trait for `__has_builtin(__builtin_bit_cast)`.
176  * @tparam Dummy_type just to make template `SFINAE` happy
177  * @see jau::is_builtin_bit_cast_available()
178  * @see jau::bit_cast()
179  * @see jau::pointer_cast()
180  */
181  template <typename Dummy_type>
183  #if defined __has_builtin_bit_cast
184  : std::true_type
185  #else
186  : std::false_type
187  #endif
188  {};
189  /**
190  * Value access of has_builtin_bit_cast type trait for convenience ..
191  * @tparam Dummy_type just to make template `SFINAE` happy
192  * @see has_builtin_bit_cast
193  */
194  template <typename Dummy_type> constexpr bool has_builtin_bit_cast_v = has_builtin_bit_cast<Dummy_type>::value;
195 
196  #if !defined __has_builtin_bit_cast
197  /**
198  * Dummy definition in the absence of this builtin function
199  * as required to have this compilation unit compile clean.
200  * @param Dest_type the target type
201  * @param Value_arg the source value argument
202  */
203  #define __builtin_bit_cast(Dest_type,Value_arg) 0
204  #endif
205 
206  namespace impl {
207  template<class Dummy_type>
209  std::enable_if_t< has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
210  {
211  return true;
212  }
213 
214  template<class Dummy_type>
216  std::enable_if_t< !has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
217  {
218  return false;
219  }
220  }
221 
222  /**
223  * Query whether `__builtin_bit_cast(Dest_type, arg)` is available, using jau::has_builtin_bit_cast.
224  *
225  * - - - - - - - - - - - - - - -
226  *
227  * Availability of `__builtin_bit_cast(Dest_type, arg)`
228  *
229  * Reflecting my manual platform tests using `test_basictypeconv.cpp`
230  *
231  * Compiler | Version | Architecture | Available |
232  * :--------- | -------: | :------------------ | :-------- |
233  * GCC | 8.3.0 | amd64, arm64, arm32 | no |
234  * GCC | 10.2.1 | amd64 | no |
235  * clang | 9.0.1 | amd64, arm64 | yes |
236  * clang | 11.0.1 | amd64 | yes |
237  *
238  * @return `true` if query subject is available, otherwise not.
239  * @see has_builtin_bit_cast
240  * @see bit_cast()
241  * @see pointer_cast()
242  */
243  constexpr bool is_builtin_bit_cast_available() noexcept {
244  return impl::has_builtin_bit_cast_impl<bool>();
245  }
246 
247  /**
248  * C++20 `bit_cast<>(arg)` implementation for C++17.
249  * <p>
250  * Functional if is_builtin_bit_cast_available() evaluates `true`.
251  * </p>
252  * @tparam Dest the target type
253  * @tparam Source the source argument type
254  * @param src the value to convert to Dest type
255  * @return the converted Dest type value
256  * @see jau::has_builtin_bit_cast
257  * @see is_builtin_bit_cast_available()
258  * @see pointer_cast()
259  */
260  template <class Dest, class Source>
261  constexpr
262  typename std::enable_if_t<
263  sizeof(Dest) == sizeof(Source) &&
264  std::is_trivially_copyable_v<Dest> &&
265  std::is_trivially_copyable_v<Source>,
266  Dest>
267  bit_cast(const Source& src) noexcept
268  {
270  return __builtin_bit_cast(Dest, src);
271  } else {
272  (void)src;
273  return 0;
274  }
275  }
276 
277  /**
278  * A `constexpr` pointer cast implementation for C++17,
279  * inspired by C++20 `bit_cast<>(arg)`.
280  * <p>
281  * If is_builtin_bit_cast_available() evaluates `true`,
282  * implementation uses `__builtin_bit_cast(Dest, src)`.<br>
283  *
284  * Otherwise a simple `reinterpret_cast<Dest>(src)` is utilized,
285  * which officially is questionable to deliver a `constexpr`.
286  * </p>
287  * @tparam Dest the target pointer type
288  * @tparam Source the source pointer argument type
289  * @param src the pointer to convert to Dest pointer type
290  * @return the converted Dest pointer type value
291  * @see jau::has_builtin_bit_cast
292  * @see is_builtin_bit_cast_available()
293  * @see bit_cast()
294  */
295  template <class Dest, class Source>
296  constexpr
297  typename std::enable_if_t<
298  sizeof(Dest) == sizeof(Source) &&
299  std::is_pointer_v<Source> &&
300  std::is_pointer_v<Dest>,
301  Dest>
302  pointer_cast(const Source& src) noexcept
303  {
305  return __builtin_bit_cast(Dest, src);
306  } else {
307  // not 'really' constexpr .. oops, working though
308  return reinterpret_cast<Dest>(src);
309  }
310  }
311 
312 
313 } // namespace jau
314 
315 #endif /* CPP_LANG_EXT_HPP_ */
jau::is_builtin_bit_cast_available
constexpr bool is_builtin_bit_cast_available() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available, using jau::has_builtin_bit_cast.
Definition: cpp_lang_util.hpp:243
jau
Definition: basic_algos.hpp:34
jau::has_builtin_bit_cast_v
constexpr bool has_builtin_bit_cast_v
Value access of has_builtin_bit_cast type trait for convenience .
Definition: cpp_lang_util.hpp:194
jau::impl::has_builtin_bit_cast_impl
constexpr bool has_builtin_bit_cast_impl(std::enable_if_t< has_builtin_bit_cast_v< Dummy_type >, bool >=true) noexcept
Definition: cpp_lang_util.hpp:208
__builtin_bit_cast
#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...
Definition: cpp_lang_util.hpp:203
jau::pointer_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).
Definition: cpp_lang_util.hpp:302
jau::bit_cast
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.
Definition: cpp_lang_util.hpp:267
jau::has_builtin_bit_cast
Convenience type trait for __has_builtin(__builtin_bit_cast).
Definition: cpp_lang_util.hpp:188