diff options
author | Martijn Vels <mvels@google.com> | 2023-01-20 07:20:05 -0800 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2023-01-20 07:21:07 -0800 |
commit | a0b102c35bae9dea68be21a718c8c7b459e239c8 (patch) | |
tree | 9123391c09f15b2f49ea725636d2b449796dad20 /absl/meta | |
parent | c611e5ce1de222eb995f5aeabf3fa8cd57ae124b (diff) |
Add absl::is_constant_evaluated for pre-c++20 support
PiperOrigin-RevId: 503437019
Change-Id: I3630fec690f1472130fef21b16dfcd3c5208aa69
Diffstat (limited to 'absl/meta')
-rw-r--r-- | absl/meta/BUILD.bazel | 2 | ||||
-rw-r--r-- | absl/meta/CMakeLists.txt | 2 | ||||
-rw-r--r-- | absl/meta/type_traits.h | 39 | ||||
-rw-r--r-- | absl/meta/type_traits_test.cc | 32 |
4 files changed, 75 insertions, 0 deletions
diff --git a/absl/meta/BUILD.bazel b/absl/meta/BUILD.bazel index 4478ccf7..125446f9 100644 --- a/absl/meta/BUILD.bazel +++ b/absl/meta/BUILD.bazel @@ -42,7 +42,9 @@ cc_test( linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":type_traits", + "//absl/base:config", "//absl/base:core_headers", + "//absl/time", "@com_google_googletest//:gtest_main", ], ) diff --git a/absl/meta/CMakeLists.txt b/absl/meta/CMakeLists.txt index f16f17bd..bb767d12 100644 --- a/absl/meta/CMakeLists.txt +++ b/absl/meta/CMakeLists.txt @@ -34,6 +34,8 @@ absl_cc_test( COPTS ${ABSL_TEST_COPTS} DEPS + absl::config + absl::time absl::core_headers absl::type_traits GTest::gmock_main diff --git a/absl/meta/type_traits.h b/absl/meta/type_traits.h index dd9de42f..b1656c39 100644 --- a/absl/meta/type_traits.h +++ b/absl/meta/type_traits.h @@ -844,6 +844,45 @@ template <class T> struct is_trivially_relocatable : std::integral_constant<bool, false> {}; #endif +// absl::is_constant_evaluated() +// +// Detects whether the function call occurs within a constant-evaluated context. +// Returns true if the evaluation of the call occurs within the evaluation of an +// expression or conversion that is manifestly constant-evaluated; otherwise +// returns false. +// +// This function is implemented in terms of `std::is_constant_evaluated` for +// c++20 and up. For older c++ versions, the function is implemented in terms +// of `__builtin_is_constant_evaluated` if available, otherwise the function +// will fail to compile. +// +// Applications can inspect `ABSL_HAVE_CONSTANT_EVALUATED` at compile time +// to check if this function is supported. +// +// Example: +// +// constexpr MyClass::MyClass(int param) { +// #ifdef ABSL_HAVE_CONSTANT_EVALUATED +// if (!absl::is_constant_evaluated()) { +// ABSL_LOG(INFO) << "MyClass(" << param << ")"; +// } +// #endif // ABSL_HAVE_CONSTANT_EVALUATED +// } +// +// Upstream documentation: +// +// http://en.cppreference.com/w/cpp/types/is_constant_evaluated +// http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#:~:text=__builtin_is_constant_evaluated +// +#if defined(ABSL_HAVE_CONSTANT_EVALUATED) +constexpr bool is_constant_evaluated() noexcept { +#ifdef __cpp_lib_is_constant_evaluated + return std::is_constant_evaluated(); +#elif ABSL_HAVE_BUILTIN(__builtin_is_constant_evaluated) + return __builtin_is_constant_evaluated(); +#endif +} +#endif // ABSL_HAVE_CONSTANT_EVALUATED ABSL_NAMESPACE_END } // namespace absl diff --git a/absl/meta/type_traits_test.cc b/absl/meta/type_traits_test.cc index d08d9ad9..b2a7a67b 100644 --- a/absl/meta/type_traits_test.cc +++ b/absl/meta/type_traits_test.cc @@ -22,6 +22,9 @@ #include "gtest/gtest.h" #include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/time/clock.h" +#include "absl/time/time.h" namespace { @@ -1413,4 +1416,33 @@ TEST(TrivallyRelocatable, Sanity) { EXPECT_TRUE(absl::is_trivially_relocatable<TrivialAbi>::value); } +#ifdef ABSL_HAVE_CONSTANT_EVALUATED + +constexpr int64_t NegateIfConstantEvaluated(int64_t i) { + if (absl::is_constant_evaluated()) { + return -i; + } else { + return i; + } +} + +#endif // ABSL_HAVE_CONSTANT_EVALUATED + +TEST(TrivallyRelocatable, is_constant_evaluated) { +#ifdef ABSL_HAVE_CONSTANT_EVALUATED + constexpr int64_t constant = NegateIfConstantEvaluated(42); + EXPECT_EQ(constant, -42); + + int64_t now = absl::ToUnixSeconds(absl::Now()); + int64_t not_constant = NegateIfConstantEvaluated(now); + EXPECT_EQ(not_constant, now); + + static int64_t const_init = NegateIfConstantEvaluated(42); + EXPECT_EQ(const_init, -42); +#else + GTEST_SKIP() << "absl::is_constant_evaluated is not defined"; +#endif // ABSL_HAVE_CONSTANT_EVALUATED +} + + } // namespace |