BDE 4.39.x Production Release
Loading...
Searching...
No Matches
bsls_consteval.h
Go to the documentation of this file.
1/// @file bsls_consteval.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bsls_consteval.h -*-C++-*-
8#ifndef INCLUDED_BSLS_CONSTEVAL
9#define INCLUDED_BSLS_CONSTEVAL
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup bsls_consteval bsls_consteval
15/// @brief Provide macros related to compile-time evaluation.
16/// @addtogroup bsl
17/// @{
18/// @addtogroup bsls
19/// @{
20/// @addtogroup bsls_consteval
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#bsls_consteval-purpose"> Purpose</a>
25/// * <a href="#bsls_consteval-macros"> Macros </a>
26/// * <a href="#bsls_consteval-description"> Description </a>
27/// * <a href="#bsls_consteval-macro-reference"> Macro Reference </a>
28/// * <a href="#bsls_consteval-usage"> Usage </a>
29/// * <a href="#bsls_consteval-example-1-bsls_consteval_constexpr-compute-with-output"> Example 1: BSLS_CONSTEVAL_CONSTEXPR compute with output </a>
30/// * <a href="#bsls_consteval-example-2-evolving-a-constexpr-function"> Example 2: Evolving a constexpr function </a>
31///
32/// # Purpose {#bsls_consteval-purpose}
33/// Provide macros related to compile-time evaluation.
34///
35/// # Macros {#bsls_consteval-macros}
36///
37/// - BSLS_CONSTEVAL_CONSTEXPR: `constexpr` if `IS_ACTIVE` defined
38/// - BSLS_CONSTEVAL_CONSTEXPR_MEMBER: `constexpr` if `IS_ACTIVE`, else `const`
39/// - BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED: `true` during constant evaluation
40/// - BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE: undefined if inactive
41///
42/// @see bsls_keyword
43///
44/// # Description {#bsls_consteval-description}
45/// This component provides preprocessor macros that, when
46/// possible, will identify whether a function is being evaluated at compile
47/// time. This enables branching to avoid the use of constructs that would not
48/// be valid to evaluate at compile time. When available, the
49/// `std::is_constant_evaluated()` function will be used. On some platforms
50/// where that is unavailable, a compiler intrinsic will be used instead.
51/// Finally, when no option for this functionality is available, the
52/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED` macro will expand to `false` and
53/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE` will not be defined. To
54/// ease writing declarations of functions where there is conditionally
55/// available compile-time behavior, `BSLS_CONSTEVAL_CONSTEXPR` is defined to be
56/// equivalent to `constexpr` if
57/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE` is defined. Note that the
58/// `BSLS_CONSTEVAL_CONSTEXPR` macro is distinct from the
59/// `BSLS_KEYWORD_CONSTEXPR*` family in @ref bsls_keyword : the former is defined
60/// according to whether the Standard Library function (or a suitable intrinsic
61/// replacement) is available, whereas the latter are defined according to
62/// which version of the C++ language is enabled.
63///
64/// ## Macro Reference {#bsls_consteval-macro-reference}
65///
66///
67/// This section documents the preprocessor macros defined in this component.
68///
69/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED`
70/// This macro expands to `std::is_constant_evaluated()` when it is
71/// available, or to a compiler intrinsic with equivalent functionality if
72/// available; otherwise it expands to `false`.
73///
74/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE`
75/// This macro is defined to `1` if `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED`
76/// can be used to identify compile-time evaluation, and is undefined
77/// otherwise.
78///
79/// `BSLS_CONSTEVAL_CONSTEXPR`
80/// This macro is defined to be `constexpr` if
81/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE` is defined; otherwise
82/// it is defined as empty.
83///
84/// `BSLS_CONSTEVAL_CONSTEXPR_MEMBER`
85/// This macro is defined to be `constexpr` if
86/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE` is defined;
87/// otherwise it is `const`. This should be applied to variables and
88/// member variables that should be initialized by a function that is
89/// `BSLS_CONSTEVAL_CONSTEXPR`.
90///
91/// ## Usage {#bsls_consteval-usage}
92///
93///
94/// This section illustrates intended use of this component.
95///
96/// ## Example 1: BSLS_CONSTEVAL_CONSTEXPR compute with output {#bsls_consteval-example-1-bsls_consteval_constexpr-compute-with-output}
97///
98///
99/// In this simple example, the macros are used to determine when it is
100/// permissible to log a message to `stdout`.
101/// @code
102/// /// Return `23` if the invocation is evaluated at compile time and that
103/// /// is detectable, otherwise print a diagnostic message to `stdout` and
104/// /// return `17`.
105/// BSLS_CONSTEVAL_CONSTEXPR int compute()
106/// {
107/// #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
108/// if (BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) {
109/// return 23; // RETURN
110/// }
111/// #endif
112/// puts("Computing value");
113/// return 17; // RETURN
114/// }
115/// @endcode
116/// Now we define a `test1` function to invoke `compute` in different contexts.
117/// This function can be evaluated both at runtime and at compile time without
118/// errors. Below, this function is evaluated in both cases, and the difference
119/// in behavior is observed.
120/// @code
121/// /// Invoke `compute` in both a const and non-const initialization,
122/// /// verifying the expected results.
123/// void test1()
124/// {
125/// int i = compute();
126/// BSLS_CONSTEVAL_CONSTEXPR_MEMBER int j = compute();
127/// #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
128/// ASSERT(17 == i);
129/// ASSERT(23 == j);
130/// #else
131/// ASSERT(17 == i);
132/// ASSERT(17 == j);
133/// #endif
134/// }
135/// @endcode
136/// When `17 == i` or `17 == j`, `compute` will write "Computing value\n" to
137/// `stdout`, so this message will be written once or twice depending on
138/// whether `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE` is defined. The
139/// variable `j` will always be `const`, and on platforms where the `compute`
140/// function supports being `constexpr`, i.e. those where it can use
141/// `BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED` to suppress its use of standard
142/// output, `j` will also be `constexpr` and its value will be computed at
143/// compile time.
144///
145/// ## Example 2: Evolving a constexpr function {#bsls_consteval-example-2-evolving-a-constexpr-function}
146///
147///
148/// Consider the situation where there are two viable implementations of the
149/// same algorithm, one of which satisfies the (stringent and pessimizing)
150/// requirements needed to be a `constexpr` function, the other of which takes
151/// advantage of runtime optimizations (such as hardware acceleration,
152/// exceptions, or non-`constexpr` third-party libraries) that are not available
153/// at compile time on any platform:
154/// @code
155/// int runtimeCompute(int input);
156///
157/// /// Return a complicated computed value based on the specified `input`.
158/// BSLS_KEYWORD_CONSTEXPR int compiletimeCompute(int input);
159/// @endcode
160/// Assuming these functions were introduced long ago, it is likely they are
161/// heavily used wherever valid throughout a codebase. The `compiletimeCompute`
162/// function is likely used to initialize many `const` and `constexpr`
163/// variables, but also potentially used in many runtime-only expressions, or as
164/// part of other `constexpr` functions that are themselves sometimes used at
165/// runtime. The `runtimeCompute` function, similarly, is likely used in many
166/// contexts that could become `constexpr` or be evaluated at compile time, but
167/// is hindered due to itself not being `constexpr`.
168///
169/// We can begin to transform `compiletimeCompute` and `runtimeCompute` to both
170/// have improved performance wherever they might be used by moving their
171/// implementations to separate functions:
172/// @code
173/// /// Return a complicated computed value based on the specified `input`.
174/// int runtimeComputeImpl(int input);
175///
176/// /// Return a complicated computed value based on the specified `input`.
177/// BSLS_KEYWORD_CONSTEXPR int compiletimeComputeImpl(int input);
178/// @endcode
179/// Then, for `compiletimeCompute` we can provide a new implementation that will
180/// use the better runtime algorithm when possible, while remaining `constexpr`
181/// on all of the platforms where it previously was `constexpr` (i.e., without
182/// changing its declaration):
183/// @code
184/// /// Return a complicated computed value based on the specified `input`.
185/// BSLS_KEYWORD_CONSTEXPR int compiletimeCompute(int input)
186/// {
187/// #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
188/// if (!BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) {
189/// return runtimeComputeImpl(input); // RETURN
190/// }
191/// #endif // BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
192/// return compiletimeComputeImpl(input);
193/// }
194/// @endcode
195/// Now clients using `compiletimeCompute` at runtime, both within and outside
196/// of other `constexpr` functions, will get the benefits of an improved
197/// algorithm without any need for change.
198///
199/// Similarly, `runtimeCompute` can become opportunistically `constexpr` by
200/// declaring the function with `BSLS_CONSTEVAL_CONSTEXPR`, which might
201/// promote some existing evaluations from runtime to compile time on
202/// platforms that can support it:
203/// @code
204/// /// Return a complicated computed value based on the specified `input`.
205/// BSLS_CONSTEVAL_CONSTEXPR int runtimeCompute(int input)
206/// {
207/// #ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
208/// if (BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED) {
209/// return compiletimeComputeImpl(input); // RETURN
210/// }
211/// #endif // BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
212/// return runtimeComputeImpl(input);
213/// }
214/// @endcode
215/// Clients of `runtimeCompute` can continue to use it at runtime with no
216/// changes, occasionally getting the benefits of the compile-time algorithm.
217/// When using `runtimeCompute` to initialize a variable, the compile-time
218/// behavior can be forced by annotating the variable with
219/// `BSLS_CONSTEVAL_CONSTEXPR_MEMBER`.
220///
221/// With these changes, clients on older platforms can continue to take
222/// advantage of having optimal algorithms available at both compile time and
223/// runtime while getting the best available implementation on newer platforms
224/// that enable the detection of compile-time evaluation.
225/// @}
226/** @} */
227/** @} */
228
229/** @addtogroup bsl
230 * @{
231 */
232/** @addtogroup bsls
233 * @{
234 */
235/** @addtogroup bsls_consteval
236 * @{
237 */
238
239#include <bsls_compilerfeatures.h>
240
241#ifdef BSLS_COMPILERFEATURES_SUPPORT_TRAITS_HEADER
242#include <type_traits>
243#endif
244
245#if defined(BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14)
246 #if defined(BSLS_COMPILERFEATURES_SUPPORT_IS_CONSTANT_EVALUATED)
247 #define BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED \
248 std::is_constant_evaluated()
249 #define BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE 1
250 #elif defined(__has_builtin)
251 #if __has_builtin(__builtin_is_constant_evaluated)
252 #define BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED \
253 __builtin_is_constant_evaluated()
254 #define BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE 1
255 #endif // __has_builtin(__builtin_is_constant_evaluated)
256 #endif // defined(BSLS_COMPILERFEATURES_SUPPORT_IS_CONSTANT_EVALUATED)
257#endif // defined BSLS_COMPILERFEATURES_SUPPORT_CONSTEXPR_CPP14
258
259#if !defined(BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED)
260 #define BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED false
261#endif // !defined(BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED)
262
263#ifdef BSLS_CONSTEVAL_IS_CONSTANT_EVALUATED_IS_ACTIVE
264 #define BSLS_CONSTEVAL_CONSTEXPR constexpr
265 #define BSLS_CONSTEVAL_CONSTEXPR_MEMBER constexpr
266#else
267 #define BSLS_CONSTEVAL_CONSTEXPR
268 #define BSLS_CONSTEVAL_CONSTEXPR_MEMBER const
269#endif
270
271#endif
272// ----------------------------------------------------------------------------
273// Copyright 2022 Bloomberg Finance L.P.
274//
275// Licensed under the Apache License, Version 2.0 (the "License");
276// you may not use this file except in compliance with the License.
277// You may obtain a copy of the License at
278//
279// http://www.apache.org/licenses/LICENSE-2.0
280//
281// Unless required by applicable law or agreed to in writing, software
282// distributed under the License is distributed on an "AS IS" BASIS,
283// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
284// See the License for the specific language governing permissions and
285// limitations under the License.
286// ----------------------------- END-OF-FILE ----------------------------------
287
288/** @} */
289/** @} */
290/** @} */
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238