diff options
-rw-r--r-- | absl/base/BUILD.bazel | 17 | ||||
-rw-r--r-- | absl/base/CMakeLists.txt | 21 | ||||
-rw-r--r-- | absl/base/inline_variable_test.cc | 62 | ||||
-rw-r--r-- | absl/base/inline_variable_test_a.cc (renamed from absl/utility/utility.cc) | 14 | ||||
-rw-r--r-- | absl/base/inline_variable_test_b.cc | 25 | ||||
-rw-r--r-- | absl/base/internal/inline_variable.h | 107 | ||||
-rw-r--r-- | absl/base/internal/inline_variable_testing.h | 44 | ||||
-rw-r--r-- | absl/utility/BUILD.bazel | 1 | ||||
-rw-r--r-- | absl/utility/CMakeLists.txt | 1 | ||||
-rw-r--r-- | absl/utility/utility.h | 4 |
10 files changed, 285 insertions, 11 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index 1778f4f8453f..9bb7bfa14efb 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel @@ -128,6 +128,7 @@ cc_library( name = "base_internal", hdrs = [ "internal/identity.h", + "internal/inline_variable.h", "internal/invoke.h", ], copts = ABSL_DEFAULT_COPTS, @@ -258,6 +259,22 @@ cc_test( ) cc_test( + name = "inline_variable_test", + size = "small", + srcs = [ + "inline_variable_test.cc", + "inline_variable_test_a.cc", + "inline_variable_test_b.cc", + "internal/inline_variable_testing.h", + ], + copts = ABSL_TEST_COPTS, + deps = [ + ":base_internal", + "@com_google_googletest//:gtest_main", + ], +) + +cc_test( name = "invoke_test", size = "small", srcs = ["invoke_test.cc"], diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index d306616305dd..9d2de55fea90 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt @@ -37,6 +37,7 @@ list(APPEND BASE_INTERNAL_HEADERS "internal/exception_safety_testing.h" "internal/identity.h" "internal/invoke.h" + "internal/inline_variable.h" "internal/low_level_alloc.h" "internal/low_level_scheduling.h" "internal/malloc_extension.h" @@ -214,6 +215,26 @@ absl_test( ) +# test inline_variable_test +list(APPEND INLINE_VARIABLE_TEST_SRC + "internal/inline_variable_testing.h" + "inline_variable_test.cc" + "inline_variable_test_a.cc" + "inline_variable_test_b.cc" +) + +set(INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES absl::base) + +absl_test( + TARGET + inline_variable_test + SOURCES + ${INLINE_VARIABLE_TEST_SRC} + PUBLIC_LIBRARIES + ${INLINE_VARIABLE_TEST_PUBLIC_LIBRARIES} +) + + # test spinlock_test_common set(SPINLOCK_TEST_COMMON_SRC "spinlock_test_common.cc") set(SPINLOCK_TEST_COMMON_PUBLIC_LIBRARIES absl::base absl::synchronization) diff --git a/absl/base/inline_variable_test.cc b/absl/base/inline_variable_test.cc new file mode 100644 index 000000000000..5499189a3da9 --- /dev/null +++ b/absl/base/inline_variable_test.cc @@ -0,0 +1,62 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include <type_traits> + +#include "absl/base/internal/inline_variable.h" +#include "absl/base/internal/inline_variable_testing.h" + +#include "gtest/gtest.h" + +namespace absl { +namespace inline_variable_testing_internal { +namespace { + +TEST(InlineVariableTest, Constexpr) { + static_assert(inline_variable_foo.value == 5, ""); + static_assert(other_inline_variable_foo.value == 5, ""); + static_assert(inline_variable_int == 5, ""); + static_assert(other_inline_variable_int == 5, ""); +} + +TEST(InlineVariableTest, DefaultConstructedIdentityEquality) { + EXPECT_EQ(get_foo_a().value, 5); + EXPECT_EQ(get_foo_b().value, 5); + EXPECT_EQ(&get_foo_a(), &get_foo_b()); +} + +TEST(InlineVariableTest, DefaultConstructedIdentityInequality) { + EXPECT_NE(&inline_variable_foo, &other_inline_variable_foo); +} + +TEST(InlineVariableTest, InitializedIdentityEquality) { + EXPECT_EQ(get_int_a(), 5); + EXPECT_EQ(get_int_b(), 5); + EXPECT_EQ(&get_int_a(), &get_int_b()); +} + +TEST(InlineVariableTest, InitializedIdentityInequality) { + EXPECT_NE(&inline_variable_int, &other_inline_variable_int); +} + +TEST(InlineVariableTest, FunPtrType) { + static_assert( + std::is_same<void(*)(), + std::decay<decltype(inline_variable_fun_ptr)>::type>::value, + ""); +} + +} // namespace +} // namespace inline_variable_testing_internal +} // namespace absl diff --git a/absl/utility/utility.cc b/absl/base/inline_variable_test_a.cc index fce79f5bb5b8..a3bf3b68b3cf 100644 --- a/absl/utility/utility.cc +++ b/absl/base/inline_variable_test_a.cc @@ -12,16 +12,14 @@ // See the License for the specific language governing permissions and // limitations under the License. -// ----------------------------------------------------------------------------- -// File: ascii.h -// ----------------------------------------------------------------------------- -// -#include "absl/utility/utility.h" +#include "absl/base/internal/inline_variable_testing.h" namespace absl { +namespace inline_variable_testing_internal { + +const Foo& get_foo_a() { return inline_variable_foo; } -#ifndef ABSL_HAVE_STD_OPTIONAL -const in_place_t in_place{}; -#endif +const int& get_int_a() { return inline_variable_int; } +} // namespace inline_variable_testing_internal } // namespace absl diff --git a/absl/base/inline_variable_test_b.cc b/absl/base/inline_variable_test_b.cc new file mode 100644 index 000000000000..b4b9393a5585 --- /dev/null +++ b/absl/base/inline_variable_test_b.cc @@ -0,0 +1,25 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/base/internal/inline_variable_testing.h" + +namespace absl { +namespace inline_variable_testing_internal { + +const Foo& get_foo_b() { return inline_variable_foo; } + +const int& get_int_b() { return inline_variable_int; } + +} // namespace inline_variable_testing_internal +} // namespace absl diff --git a/absl/base/internal/inline_variable.h b/absl/base/internal/inline_variable.h new file mode 100644 index 000000000000..f7bb8c56525d --- /dev/null +++ b/absl/base/internal/inline_variable.h @@ -0,0 +1,107 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ +#define ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ + +#include <type_traits> + +#include "absl/base/internal/identity.h" + +// File: +// This file define a macro that allows the creation of or emulation of C++17 +// inline variables based on whether or not the feature is supported. + +//////////////////////////////////////////////////////////////////////////////// +// Macro: ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) +// +// Description: +// Expands to the equivalent of an inline constexpr instance of the specified +// `type` and `name`, initialized to the value `init`. If the compiler being +// used is detected as supporting actual inline variables as a language +// feature, then the macro expands to an actual inline variable definition. +// +// Requires: +// `type` is a type that is usable in an extern variable declaration. +// +// Requires: `name` is a valid identifier +// +// Requires: +// `init` is an expression that can be used in the following definition: +// constexpr type name = init; +// +// Usage: +// +// // Equivalent to: `inline constexpr size_t variant_npos = -1;` +// ABSL_INTERNAL_INLINE_CONSTEXPR(size_t, variant_npos, -1); +// +// Differences in implementation: +// For a direct, language-level inline variable, decltype(name) will be the +// type that was specified along with const qualification, whereas for +// emulated inline variables, decltype(name) may be different (in practice +// it will likely be a reference type). +//////////////////////////////////////////////////////////////////////////////// + +#ifdef __cpp_inline_variables + +// Clang's -Wmissing-variable-declarations option erroneously warned that +// inline constexpr objects need to be pre-declared. This has now been fixed, +// but we will need to support this workaround for people building with older +// versions of clang. +// +// Bug: https://bugs.llvm.org/show_bug.cgi?id=35862 +// +// Note: +// identity_t is used here so that the const and name are in the +// appropriate place for pointer types, reference types, function pointer +// types, etc.. +#if defined(__clang__) +#define ABSL_INTERNAL_EXTERN_DECL(type, name) \ + extern const ::absl::internal::identity_t<type> name; +#else // Otherwise, just define the macro to do nothing. +#define ABSL_INTERNAL_EXTERN_DECL(type, name) +#endif // defined(__clang__) + +// See above comment at top of file for details. +#define ABSL_INTERNAL_INLINE_CONSTEXPR(type, name, init) \ + ABSL_INTERNAL_EXTERN_DECL(type, name) \ + inline constexpr ::absl::internal::identity_t<type> name = init + +#else + +// See above comment at top of file for details. +// +// Note: +// identity_t is used here so that the const and name are in the +// appropriate place for pointer types, reference types, function pointer +// types, etc.. +#define ABSL_INTERNAL_INLINE_CONSTEXPR(var_type, name, init) \ + template <class /*AbslInternalDummy*/ = void> \ + struct AbslInternalInlineVariableHolder##name { \ + static constexpr ::absl::internal::identity_t<var_type> kInstance = init; \ + }; \ + \ + template <class AbslInternalDummy> \ + constexpr ::absl::internal::identity_t<var_type> \ + AbslInternalInlineVariableHolder##name<AbslInternalDummy>::kInstance; \ + \ + static constexpr const ::absl::internal::identity_t<var_type>& \ + name = /* NOLINT */ \ + AbslInternalInlineVariableHolder##name<>::kInstance; \ + static_assert(sizeof(void (*)(decltype(name))) != 0, \ + "Silence unused variable warnings.") + +#endif // __cpp_inline_variables + +#endif // ABSL_BASE_INTERNAL_INLINE_VARIABLE_EMULATION_H_ diff --git a/absl/base/internal/inline_variable_testing.h b/absl/base/internal/inline_variable_testing.h new file mode 100644 index 000000000000..a0dd2bb28a40 --- /dev/null +++ b/absl/base/internal/inline_variable_testing.h @@ -0,0 +1,44 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ABSL_BASE_INLINE_VARIABLE_TESTING_H_ +#define ABSL_BASE_INLINE_VARIABLE_TESTING_H_ + +#include "absl/base/internal/inline_variable.h" + +namespace absl { +namespace inline_variable_testing_internal { + +struct Foo { + int value = 5; +}; + +ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, inline_variable_foo, {}); +ABSL_INTERNAL_INLINE_CONSTEXPR(Foo, other_inline_variable_foo, {}); + +ABSL_INTERNAL_INLINE_CONSTEXPR(int, inline_variable_int, 5); +ABSL_INTERNAL_INLINE_CONSTEXPR(int, other_inline_variable_int, 5); + +ABSL_INTERNAL_INLINE_CONSTEXPR(void(*)(), inline_variable_fun_ptr, nullptr); + +const Foo& get_foo_a(); +const Foo& get_foo_b(); + +const int& get_int_a(); +const int& get_int_b(); + +} // namespace inline_variable_testing_internal +} // namespace absl + +#endif // ABSL_BASE_INLINE_VARIABLE_TESTING_H_ diff --git a/absl/utility/BUILD.bazel b/absl/utility/BUILD.bazel index 6298462643f4..c01b49bc97dd 100644 --- a/absl/utility/BUILD.bazel +++ b/absl/utility/BUILD.bazel @@ -10,7 +10,6 @@ licenses(["notice"]) # Apache 2.0 cc_library( name = "utility", - srcs = ["utility.cc"], hdrs = ["utility.h"], copts = ABSL_DEFAULT_COPTS, deps = [ diff --git a/absl/utility/CMakeLists.txt b/absl/utility/CMakeLists.txt index daf3417859ba..50a5d5c57aa4 100644 --- a/absl/utility/CMakeLists.txt +++ b/absl/utility/CMakeLists.txt @@ -22,7 +22,6 @@ list(APPEND UTILITY_PUBLIC_HEADERS list(APPEND UTILITY_SRC - "utility.cc" ${UTILITY_PUBLIC_HEADERS} ) diff --git a/absl/utility/utility.h b/absl/utility/utility.h index d37f4c301a44..1943c4acb577 100644 --- a/absl/utility/utility.h +++ b/absl/utility/utility.h @@ -45,6 +45,7 @@ #include <utility> #include "absl/base/config.h" +#include "absl/base/internal/inline_variable.h" #include "absl/base/internal/invoke.h" #include "absl/meta/type_traits.h" @@ -155,7 +156,8 @@ using std::in_place; // `absl::optional`, designed to be a drop-in replacement for C++17's // `std::in_place_t`. struct in_place_t {}; -extern const in_place_t in_place; + +ABSL_INTERNAL_INLINE_CONSTEXPR(in_place_t, in_place, {}); #endif // ABSL_HAVE_STD_OPTIONAL |