diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake index 0fa06af..f45b9a4 100644 --- a/CMake/AbseilDll.cmake +++ b/CMake/AbseilDll.cmake
@@ -20,6 +20,8 @@ "base/internal/dynamic_annotations.h" "base/internal/endian.h" "base/internal/errno_saver.h" + "base/internal/hardening.h" + "base/internal/hardening.cc" "base/internal/hide_ptr.h" "base/internal/iterator_traits.h" "base/internal/low_level_alloc.cc" @@ -453,6 +455,7 @@ "types/any.h" "types/compare.h" "types/optional.h" + "types/optional_ref.h" "types/span.h" "types/internal/span.h" "types/variant.h"
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel index f95e187..6b39370 100644 --- a/absl/base/BUILD.bazel +++ b/absl/base/BUILD.bazel
@@ -61,6 +61,25 @@ ) cc_library( + name = "hardening", + srcs = [ + "internal/hardening.cc", + ], + hdrs = [ + "internal/hardening.h", + ], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + visibility = [ + "//absl:__subpackages__", + ], + deps = [ + ":config", + ":core_headers", + ], +) + +cc_library( name = "log_severity", srcs = ["log_severity.cc"], hdrs = ["log_severity.h"], @@ -619,6 +638,22 @@ ) cc_test( + name = "hardening_test", + size = "small", + srcs = [ + "internal/hardening_test.cc", + ], + copts = ABSL_TEST_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + ":config", + ":hardening", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +) + +cc_test( name = "no_destructor_test", srcs = ["no_destructor_test.cc"], copts = ABSL_TEST_COPTS, @@ -953,7 +988,6 @@ linkopts = ABSL_DEFAULT_LINKOPTS, deps = [ ":core_headers", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt index 91a8a58..ad1932e 100644 --- a/absl/base/CMakeLists.txt +++ b/absl/base/CMakeLists.txt
@@ -43,6 +43,20 @@ absl_cc_library( NAME + hardening + HDRS + "internal/hardening.h" + SRCS + "internal/hardening.cc" + DEPS + absl::config + absl::core_headers + COPTS + ${ABSL_DEFAULT_COPTS} +) + +absl_cc_library( + NAME log_severity HDRS "log_severity.h" @@ -406,6 +420,19 @@ absl_cc_test( NAME + hardening_test + SRCS + "internal/hardening_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::config + absl::hardening + GTest::gtest_main +) + +absl_cc_test( + NAME bit_cast_test SRCS "bit_cast_test.cc" @@ -765,7 +792,6 @@ ${ABSL_TEST_COPTS} DEPS absl::core_headers - absl::optional GTest::gtest_main )
diff --git a/absl/base/attributes.h b/absl/base/attributes.h index cced170..91e552f 100644 --- a/absl/base/attributes.h +++ b/absl/base/attributes.h
@@ -933,7 +933,7 @@ // We disable this on Clang versions < 13 because of the following // false-positive: // -// absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; } +// absl::string_view f(std::optional<absl::string_view> sv) { return *sv; } // // See the following links for details: // https://reviews.llvm.org/D64448 @@ -964,7 +964,7 @@ // We disable this on Clang versions < 13 because of the following // false-positive: // -// absl::string_view f(absl::optional<absl::string_view> sv) { return *sv; } +// absl::string_view f(std::optional<absl::string_view> sv) { return *sv; } // // See the following links for details: // https://reviews.llvm.org/D64448
diff --git a/absl/base/internal/hardening.cc b/absl/base/internal/hardening.cc new file mode 100644 index 0000000..bd7da60 --- /dev/null +++ b/absl/base/internal/hardening.cc
@@ -0,0 +1,46 @@ +// +// Copyright 2026 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 +// +// https://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. + +#ifdef _WIN32 +#include <intrin.h> +// kFastFailRangeCheckFailure mirrors the FAST_FAIL_RANGE_CHECK_FAILURE macro. +// Typically FAST_FAIL_RANGE_CHECK_FAILURE would be imported from winnt.h +// but winnt.h pulls in other dependencies and introduces build failures. +constexpr unsigned int kFastFailRangeCheckFailure = 8u; +#endif + +#include "absl/base/internal/hardening.h" + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/macros.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace base_internal { + +[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void FailedBoundsCheckAbort() { +#ifdef _WIN32 + __fastfail(kFastFailRangeCheckFailure); +#else + ABSL_INTERNAL_HARDENING_ABORT(); +#endif +} + +} // namespace base_internal + +ABSL_NAMESPACE_END +} // namespace absl
diff --git a/absl/base/internal/hardening.h b/absl/base/internal/hardening.h new file mode 100644 index 0000000..02207cc --- /dev/null +++ b/absl/base/internal/hardening.h
@@ -0,0 +1,63 @@ +// +// Copyright 2026 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 +// +// https://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. +// +// ----------------------------------------------------------------------------- +// File: hardening.h +// ----------------------------------------------------------------------------- +// +// This header file defines macros and functions for checking bounds on +// accesses to Abseil container types. + +#ifndef ABSL_BASE_INTERNAL_HARDENING_H_ +#define ABSL_BASE_INTERNAL_HARDENING_H_ + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/base/options.h" + +#ifdef ABSL_INTERNAL_ATTRIBUTE_NO_MERGE +#error ABSL_INTERNAL_ATTRIBUTE_NO_MERGE cannot be directly set +#elif ABSL_HAVE_CPP_ATTRIBUTE(clang::nomerge) +#define ABSL_INTERNAL_ATTRIBUTE_NO_MERGE [[clang::nomerge]] +#else +#define ABSL_INTERNAL_ATTRIBUTE_NO_MERGE +#endif + +namespace absl { +ABSL_NAMESPACE_BEGIN + +namespace base_internal { + +[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void FailedBoundsCheckAbort(); + +inline void HardeningAssertInBounds(size_t index, size_t size) { +#if (ABSL_OPTION_HARDENED == 1 || ABSL_OPTION_HARDENED == 2) && defined(NDEBUG) + if (ABSL_PREDICT_FALSE(index >= size)) { + ABSL_INTERNAL_ATTRIBUTE_NO_MERGE FailedBoundsCheckAbort(); + } +#else + ABSL_ASSERT(index < size); +#endif +} + +} // namespace base_internal + +ABSL_NAMESPACE_END +} // namespace absl + +#undef ABSL_INTERNAL_ATTRIBUTE_NO_MERGE + +#endif // ABSL_BASE_INTERNAL_HARDENING_H_
diff --git a/absl/base/internal/hardening_test.cc b/absl/base/internal/hardening_test.cc new file mode 100644 index 0000000..8666f29 --- /dev/null +++ b/absl/base/internal/hardening_test.cc
@@ -0,0 +1,35 @@ +// Copyright 2026 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 +// +// https://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/hardening.h" + +#include "gtest/gtest.h" +#include "absl/base/options.h" + +namespace { + +TEST(BoundsCheckTest, HardeningAssertInBounds) { + absl::base_internal::HardeningAssertInBounds(0, 10); +} + +TEST(BoundsChecksDeathTest, HardeningAssertInBounds) { +#if GTEST_HAS_DEATH_TEST && (!defined(NDEBUG) || (ABSL_OPTION_HARDENED == 1 || \ + ABSL_OPTION_HARDENED == 2)) + // The underlying mechanism of termination varies, and may include SIGILL + // or SIGABRT. + EXPECT_DEATH(absl::base_internal::HardeningAssertInBounds(10, 10), ""); +#endif +} + +} // namespace
diff --git a/absl/base/optimization_test.cc b/absl/base/optimization_test.cc index b47b11a..11d22fe 100644 --- a/absl/base/optimization_test.cc +++ b/absl/base/optimization_test.cc
@@ -14,8 +14,9 @@ #include "absl/base/optimization.h" +#include <optional> + #include "gtest/gtest.h" -#include "absl/types/optional.h" namespace { @@ -80,8 +81,8 @@ TEST(PredictTest, Optional) { // Note: An optional's truth value is the value's existence, not its truth. - absl::optional<bool> has_value(false); - absl::optional<bool> no_value; + std::optional<bool> has_value(false); + std::optional<bool> no_value; EXPECT_TRUE(ABSL_PREDICT_TRUE(has_value)); EXPECT_FALSE(ABSL_PREDICT_TRUE(no_value)); EXPECT_TRUE(ABSL_PREDICT_FALSE(has_value));
diff --git a/absl/cleanup/internal/cleanup.h b/absl/cleanup/internal/cleanup.h index 4dd6f91..2022fa7 100644 --- a/absl/cleanup/internal/cleanup.h +++ b/absl/cleanup/internal/cleanup.h
@@ -49,7 +49,7 @@ explicit Storage(Callback callback) { // Placement-new into a character buffer is used for eager destruction when // the cleanup is invoked or cancelled. To ensure this optimizes well, the - // behavior is implemented locally instead of using an absl::optional. + // behavior is implemented locally instead of using a std::optional. ::new (GetCallbackBuffer()) Callback(std::move(callback)); is_callback_engaged_ = true; }
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index e90aaec..efcdc51 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel
@@ -54,8 +54,6 @@ ":compressed_tuple", ":test_instance_tracker", "//absl/memory", - "//absl/types:any", - "//absl/types:optional", "//absl/utility", "@googletest//:gtest", "@googletest//:gtest_main", @@ -283,7 +281,6 @@ "//absl/base:config", "//absl/log:check", "//absl/meta:type_traits", - "//absl/types:any", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -810,7 +807,6 @@ "//absl/numeric:int128", "//absl/random", "//absl/strings", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -855,7 +851,6 @@ "//absl/random:distributions", "//absl/strings", "//absl/strings:str_format", - "//absl/types:optional", ], ) @@ -1193,7 +1188,6 @@ "//absl/random", "//absl/strings", "//absl/types:compare", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index 365c6ea..589a3a4 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt
@@ -80,7 +80,6 @@ absl::core_headers absl::flags absl::hash_testing - absl::optional absl::random_random absl::raw_logging_internal absl::strings @@ -110,10 +109,8 @@ COPTS ${ABSL_TEST_COPTS} DEPS - absl::any absl::compressed_tuple absl::memory - absl::optional absl::test_instance_tracker absl::utility GTest::gmock_main @@ -309,7 +306,6 @@ COPTS ${ABSL_TEST_COPTS} DEPS - absl::any absl::check absl::config absl::flat_hash_map @@ -840,7 +836,6 @@ absl::log absl::memory absl::node_hash_set - absl::optional absl::prefetch absl::random_random absl::raw_hash_set @@ -1119,6 +1114,7 @@ absl::config absl::test_instance_tracker GTest::gmock + TESTONLY ) absl_cc_library(
diff --git a/absl/container/btree_test.cc b/absl/container/btree_test.cc index 0cf3ed3..dc880a8 100644 --- a/absl/container/btree_test.cc +++ b/absl/container/btree_test.cc
@@ -24,6 +24,7 @@ #include <map> #include <memory> #include <numeric> +#include <optional> #include <stdexcept> #include <string> #include <type_traits> @@ -47,7 +48,6 @@ #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" #include "absl/types/compare.h" -#include "absl/types/optional.h" ABSL_FLAG(int, test_values, 10000, "The number of values to use for tests"); @@ -3007,11 +3007,11 @@ // compare differently with each other from how they compare with instances // that don't have the optional field. struct ClockTime { - absl::optional<int> hour; + std::optional<int> hour; int minute; }; // `comp(a,b) && comp(b,c) && !comp(a,c)` violates transitivity. - ClockTime a = {absl::nullopt, 1}; + ClockTime a = {std::nullopt, 1}; ClockTime b = {2, 5}; ClockTime c = {6, 0}; {
diff --git a/absl/container/flat_hash_map_test.cc b/absl/container/flat_hash_map_test.cc index a4efb7d..0839b00 100644 --- a/absl/container/flat_hash_map_test.cc +++ b/absl/container/flat_hash_map_test.cc
@@ -33,7 +33,6 @@ #include "absl/container/internal/unordered_map_modifiers_test.h" #include "absl/log/check.h" #include "absl/meta/type_traits.h" -#include "absl/types/any.h" #if ABSL_INTERNAL_CPLUSPLUS_LANG >= 202002L #include <ranges> // NOLINT(build/c++20)
diff --git a/absl/container/internal/common.h b/absl/container/internal/common.h index 3e263a3..62517af 100644 --- a/absl/container/internal/common.h +++ b/absl/container/internal/common.h
@@ -18,6 +18,7 @@ #include <algorithm> #include <cassert> #include <cstddef> +#include <optional> #include <tuple> #include <type_traits> @@ -146,7 +147,7 @@ void reset() { assert(alloc_.has_value()); - alloc_ = absl::nullopt; + alloc_ = std::nullopt; } slot_type* slot() const { @@ -156,7 +157,7 @@ allocator_type* alloc() { return std::addressof(*alloc_); } private: - absl::optional<allocator_type> alloc_ = {}; + std::optional<allocator_type> alloc_ = {}; alignas(slot_type) mutable unsigned char slot_space_[sizeof(slot_type)] = {}; };
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc index 662f944..47648c9 100644 --- a/absl/container/internal/compressed_tuple_test.cc +++ b/absl/container/internal/compressed_tuple_test.cc
@@ -14,7 +14,9 @@ #include "absl/container/internal/compressed_tuple.h" +#include <any> #include <memory> +#include <optional> #include <set> #include <string> #include <type_traits> @@ -25,8 +27,6 @@ #include "gtest/gtest.h" #include "absl/container/internal/test_instance_tracker.h" #include "absl/memory/memory.h" -#include "absl/types/any.h" -#include "absl/types/optional.h" #include "absl/utility/utility.h" // These are declared at global scope purely so that error messages @@ -363,13 +363,13 @@ } TEST(CompressedTupleTest, AnyElements) { - any a(std::string("str")); - CompressedTuple<any, any&> x(any(5), a); - EXPECT_EQ(absl::any_cast<int>(x.get<0>()), 5); - EXPECT_EQ(absl::any_cast<std::string>(x.get<1>()), "str"); + std::any a(std::string("str")); + CompressedTuple<std::any, std::any&> x(std::any(5), a); + EXPECT_EQ(std::any_cast<int>(x.get<0>()), 5); + EXPECT_EQ(std::any_cast<std::string>(x.get<1>()), "str"); a = 0.5f; - EXPECT_EQ(absl::any_cast<float>(x.get<1>()), 0.5); + EXPECT_EQ(std::any_cast<float>(x.get<1>()), 0.5); } TEST(CompressedTupleTest, Constexpr) { @@ -418,15 +418,15 @@ EXPECT_EQ(trivial1, 0); EXPECT_EQ(trivial2, 0); - constexpr CompressedTuple<Empty<0>, NonTrivialStruct, absl::optional<int>> + constexpr CompressedTuple<Empty<0>, NonTrivialStruct, std::optional<int>> non_trivial = {}; constexpr CallType non_trivial0 = non_trivial.get<0>().value(); constexpr int non_trivial1 = non_trivial.get<1>().value(); - constexpr absl::optional<int> non_trivial2 = non_trivial.get<2>(); + constexpr std::optional<int> non_trivial2 = non_trivial.get<2>(); EXPECT_EQ(non_trivial0, CallType::kConstRef); EXPECT_EQ(non_trivial1, 5); - EXPECT_EQ(non_trivial2, absl::nullopt); + EXPECT_EQ(non_trivial2, std::nullopt); static constexpr char data[] = "DEF"; constexpr CompressedTuple<const char*> z(data);
diff --git a/absl/container/internal/raw_hash_set.cc b/absl/container/internal/raw_hash_set.cc index 9955029..15d072a 100644 --- a/absl/container/internal/raw_hash_set.cc +++ b/absl/container/internal/raw_hash_set.cc
@@ -62,14 +62,15 @@ assert((CONDITION) && "Try enabling sanitizers.") #endif -[[noreturn]] ABSL_ATTRIBUTE_NOINLINE void HashTableSizeOverflow() { - ABSL_RAW_LOG(FATAL, "Hash table size overflow"); +void ValidateMaxSize([[maybe_unused]] size_t size, + [[maybe_unused]] size_t key_size, + [[maybe_unused]] size_t slot_size) { + ABSL_SWISSTABLE_ASSERT(size <= MaxValidSize(key_size, slot_size)); } - -void ValidateMaxSize(size_t size, size_t slot_size) { - if (IsAboveValidSize(size, slot_size)) { - HashTableSizeOverflow(); - } +void ValidateMaxCapacity(size_t capacity, size_t key_size, size_t slot_size) { + if (capacity <= 1) return; + ValidateMaxSize(CapacityToGrowth(PreviousCapacity(capacity)), key_size, + slot_size); } // Returns "random" seed. @@ -1681,7 +1682,7 @@ void ReserveEmptyNonAllocatedTableToFitNewSize( CommonFields& common, const PolicyFunctions& __restrict policy, size_t new_size) { - ValidateMaxSize(new_size, policy.slot_size); + ValidateMaxSize(new_size, policy.key_size, policy.slot_size); ABSL_ASSUME(new_size > 0); ResizeEmptyNonAllocatedTableImpl(common, policy, SizeToCapacity(new_size), /*force_infoz=*/false); @@ -1700,7 +1701,7 @@ CommonFields& common, const PolicyFunctions& __restrict policy, size_t new_size) { const size_t cap = common.capacity(); - ValidateMaxSize(new_size, policy.slot_size); + ValidateMaxSize(new_size, policy.key_size, policy.slot_size); ABSL_ASSUME(new_size > 0); const size_t new_capacity = SizeToCapacity(new_size); if (cap == policy.soo_capacity()) { @@ -1747,7 +1748,7 @@ CommonFields& common, const PolicyFunctions& __restrict policy, size_t bucket_count) { size_t new_capacity = NormalizeCapacity(bucket_count); - ValidateMaxSize(CapacityToGrowth(new_capacity), policy.slot_size); + ValidateMaxCapacity(new_capacity, policy.key_size, policy.slot_size); ResizeEmptyNonAllocatedTableImpl(common, policy, new_capacity, /*force_infoz=*/false); } @@ -1864,11 +1865,11 @@ } } - ValidateMaxSize(n, policy.slot_size); // bitor is a faster way of doing `max` here. We will round up to the next // power-of-2-minus-1, so bitor is good enough. const size_t new_capacity = NormalizeCapacity(n | SizeToCapacity(common.size())); + ValidateMaxCapacity(new_capacity, policy.key_size, policy.slot_size); // n == 0 unconditionally rehashes as per the standard. if (n == 0 || new_capacity > cap) { if (cap == policy.soo_capacity()) {
diff --git a/absl/container/internal/raw_hash_set.h b/absl/container/internal/raw_hash_set.h index e6ea164..1adb396 100644 --- a/absl/container/internal/raw_hash_set.h +++ b/absl/container/internal/raw_hash_set.h
@@ -1557,51 +1557,52 @@ } }; -// Returns the maximum valid size for a table with 1-byte slots. -// This function is an utility shared by MaxValidSize and IsAboveValidSize. -// Template parameter is only used to enable testing. +// The following functions are used for calculating the max valid size of the +// table. This is important for security to avoid overflowing size_t when +// calculating the allocation size of the backing array +// (https://nvd.nist.gov/vuln/detail/CVE-2025-0838). We also limit the max valid +// size based on the size of the key_type, and this is an optimization because +// we ABSL_ASSUME that the size is less than MaxValidSize, which can enable +// other optimizations for tables with small keys. + template <size_t kSizeOfSizeT = sizeof(size_t)> -constexpr size_t MaxValidSizeFor1ByteSlot() { - if constexpr (kSizeOfSizeT == 8) { - return CapacityToGrowth( - static_cast<size_t>(uint64_t{1} << HashtableSize::kSizeBitCount) - 1); - } else { - static_assert(kSizeOfSizeT == 4); - return CapacityToGrowth((size_t{1} << (kSizeOfSizeT * 8 - 2)) - 1); - } +constexpr size_t MaxSizeAtMaxValidCapacity(size_t slot_size) { + using SizeT = std::conditional_t<kSizeOfSizeT == 4, uint32_t, uint64_t>; + // We shift right by 2 for a safe margin against overflow. + constexpr SizeT kMaxValidCapacity = ~SizeT{} >> 2; + return CapacityToGrowth(kMaxValidCapacity) / slot_size; } -// Returns the maximum valid size for a table with provided slot size. -// Template parameter is only used to enable testing. +constexpr size_t MaxStorableSize() { + return static_cast<size_t>(uint64_t{1} << HashtableSize::kSizeBitCount) - 1; +} + +// There are no more than 2^sizeof(key_type) unique key_types (and hashtable +// keys must be unique) so we can't have a hashtable with more than +// 2^sizeof(key_type) elements. template <size_t kSizeOfSizeT = sizeof(size_t)> -constexpr size_t MaxValidSize(size_t slot_size) { +constexpr size_t MaxValidSizeForKeySize(size_t key_size) { + if (key_size < kSizeOfSizeT) return uint64_t{1} << 8 * key_size; + return (std::numeric_limits<size_t>::max)(); +} + +template <size_t kSizeOfSizeT = sizeof(size_t)> +constexpr size_t MaxValidSizeForSlotSize(size_t slot_size) { if constexpr (kSizeOfSizeT == 8) { // For small slot sizes we are limited by HashtableSize::kSizeBitCount. if (slot_size < size_t{1} << (64 - HashtableSize::kSizeBitCount)) { - return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>(); + return MaxStorableSize(); } - return (size_t{1} << (kSizeOfSizeT * 8 - 2)) / slot_size; - } else { - return MaxValidSizeFor1ByteSlot<kSizeOfSizeT>() / slot_size; } + return MaxSizeAtMaxValidCapacity<kSizeOfSizeT>(slot_size); } -// Returns true if size is larger than the maximum valid size. -// It is an optimization to avoid the division operation in the common case. +// Returns the maximum valid size for a table, given the key size and slot size. // Template parameter is only used to enable testing. template <size_t kSizeOfSizeT = sizeof(size_t)> -constexpr bool IsAboveValidSize(size_t size, size_t slot_size) { - if constexpr (kSizeOfSizeT == 8) { - // For small slot sizes we are limited by HashtableSize::kSizeBitCount. - if (ABSL_PREDICT_TRUE(slot_size < - (size_t{1} << (64 - HashtableSize::kSizeBitCount)))) { - return size > MaxValidSizeFor1ByteSlot<kSizeOfSizeT>(); - } - return size > MaxValidSize<kSizeOfSizeT>(slot_size); - } else { - return uint64_t{size} * slot_size > - MaxValidSizeFor1ByteSlot<kSizeOfSizeT>(); - } +constexpr size_t MaxValidSize(size_t key_size, size_t slot_size) { + return (std::min)(MaxValidSizeForKeySize<kSizeOfSizeT>(key_size), + MaxValidSizeForSlotSize<kSizeOfSizeT>(slot_size)); } // Returns the index of the SOO slot when growing from SOO to non-SOO in a @@ -1616,8 +1617,9 @@ // Allowing till 16 would require additional store that can be avoided. constexpr size_t MaxSmallAfterSooCapacity() { return 7; } -// Type erased version of raw_hash_set::reserve. -// Requires: `new_size > policy.soo_capacity`. +// Type erased version of raw_hash_set::reserve. Requires: +// 1. `new_size > policy.soo_capacity`. +// 2. `new_size <= kMaxValidSize`. void ReserveTableToFitNewSize(CommonFields& common, const PolicyFunctions& policy, size_t new_size); @@ -1626,11 +1628,13 @@ // 1. `c.capacity() == policy.soo_capacity`. // 2. `c.empty()`. // 3. `new_size > policy.soo_capacity`. +// 4. `bucket_count <= MaxValidCapacity()`. // The table will be attempted to be sampled. void ReserveEmptyNonAllocatedTableToFitBucketCount( CommonFields& common, const PolicyFunctions& policy, size_t bucket_count); // Type erased version of raw_hash_set::rehash. +// Requires: `n <= MaxValidCapacity()`. void Rehash(CommonFields& common, const PolicyFunctions& policy, size_t n); // Type erased version of copy constructor. @@ -1856,13 +1860,20 @@ constexpr static size_t DefaultCapacity() { return SooEnabled() ? SooCapacity() : 0; } + constexpr static size_t MaxValidSize() { + return container_internal::MaxValidSize(sizeof(key_type), + sizeof(slot_type)); + } + constexpr static size_t MaxValidCapacity() { + return SizeToCapacity(MaxValidSize()); + } // Whether `size` fits in the SOO capacity of this table. bool fits_in_soo(size_t size) const { return SooEnabled() && size <= SooCapacity(); } // Whether this table is in SOO mode or non-SOO mode. - bool is_soo() const { return fits_in_soo(capacity()); } + bool is_soo() const { return fits_in_soo(maybe_invalid_capacity()); } bool is_full_soo() const { return is_soo() && !empty(); } bool is_small() const { return common().is_small(); } @@ -2110,7 +2121,8 @@ alloc) { if (bucket_count > DefaultCapacity()) { ReserveEmptyNonAllocatedTableToFitBucketCount( - common(), GetPolicyFunctions(), bucket_count); + common(), GetPolicyFunctions(), + (std::min)(bucket_count, MaxValidCapacity())); } } @@ -2342,21 +2354,27 @@ bool empty() const { return !size(); } size_t size() const { AssertNotDebugCapacity(); - return common().size(); + const size_t size = common().size(); + [[maybe_unused]] const size_t kMaxValidSize = MaxValidSize(); + ABSL_ASSUME(size <= kMaxValidSize); + return size; } size_t capacity() const { const size_t cap = common().capacity(); - // Compiler complains when using functions in ASSUME so use local variable. - [[maybe_unused]] static constexpr size_t kDefaultCapacity = - DefaultCapacity(); + // Compiler complains when using functions in ASSUME so use local variables. + [[maybe_unused]] const bool kIsValid = IsValidCapacity(cap); + [[maybe_unused]] const size_t kDefaultCapacity = DefaultCapacity(); + [[maybe_unused]] const size_t kMaxValidCapacity = MaxValidCapacity(); + ABSL_ASSUME(kIsValid || cap == 0); ABSL_ASSUME(cap >= kDefaultCapacity); + ABSL_ASSUME(cap <= kMaxValidCapacity); return cap; } - size_t max_size() const { return MaxValidSize(sizeof(slot_type)); } + size_t max_size() const { return MaxValidSize(); } ABSL_ATTRIBUTE_REINITIALIZES void clear() { if (SwisstableGenerationsEnabled() && - capacity() >= InvalidCapacity::kMovedFrom) { + maybe_invalid_capacity() >= InvalidCapacity::kMovedFrom) { common().set_capacity(DefaultCapacity()); } AssertNotDebugCapacity(); @@ -2752,11 +2770,14 @@ typename AllocTraits::propagate_on_container_swap{}); } - void rehash(size_t n) { Rehash(common(), GetPolicyFunctions(), n); } + void rehash(size_t n) { + Rehash(common(), GetPolicyFunctions(), (std::min)(n, MaxValidCapacity())); + } void reserve(size_t n) { if (ABSL_PREDICT_TRUE(n > DefaultCapacity())) { - ReserveTableToFitNewSize(common(), GetPolicyFunctions(), n); + ReserveTableToFitNewSize(common(), GetPolicyFunctions(), + (std::min)(n, MaxValidSize())); } } @@ -3034,7 +3055,7 @@ void destructor_impl() { if (SwisstableGenerationsEnabled() && - capacity() >= InvalidCapacity::kMovedFrom) { + maybe_invalid_capacity() >= InvalidCapacity::kMovedFrom) { return; } if (capacity() == 0) return; @@ -3132,8 +3153,9 @@ that.common().set_capacity(this == &that ? InvalidCapacity::kSelfMovedFrom : InvalidCapacity::kMovedFrom); } - if (!SwisstableGenerationsEnabled() || capacity() == DefaultCapacity() || - capacity() > kAboveMaxValidCapacity) { + if (!SwisstableGenerationsEnabled() || + maybe_invalid_capacity() == DefaultCapacity() || + maybe_invalid_capacity() > kAboveMaxValidCapacity) { return; } common().increment_generation(); @@ -3302,21 +3324,21 @@ return; } #endif - if (ABSL_PREDICT_TRUE(capacity() < - InvalidCapacity::kAboveMaxValidCapacity)) { + const size_t cap = maybe_invalid_capacity(); + if (ABSL_PREDICT_TRUE(cap < InvalidCapacity::kAboveMaxValidCapacity)) { return; } - assert(capacity() != InvalidCapacity::kReentrance && + assert(cap != InvalidCapacity::kReentrance && "Reentrant container access during element construction/destruction " "is not allowed."); if constexpr (SwisstableAssertAccessToDestroyedTable()) { - if (capacity() == InvalidCapacity::kDestroyed) { + if (cap == InvalidCapacity::kDestroyed) { ABSL_RAW_LOG(FATAL, "Use of destroyed hash table."); } } if (SwisstableGenerationsEnabled() && - ABSL_PREDICT_FALSE(capacity() >= InvalidCapacity::kMovedFrom)) { - if (capacity() == InvalidCapacity::kSelfMovedFrom) { + ABSL_PREDICT_FALSE(cap >= InvalidCapacity::kMovedFrom)) { + if (cap == InvalidCapacity::kSelfMovedFrom) { // If this log triggers, then a hash table was move-assigned to itself // and then used again later without being reinitialized. ABSL_RAW_LOG(FATAL, "Use of self-move-assigned hash table."); @@ -3444,6 +3466,9 @@ CommonFields& common() { return settings_.template get<0>(); } const CommonFields& common() const { return settings_.template get<0>(); } + // For use when the capacity is potentially invalid so we shouldn't assume + // that the capacity is valid (which is done in `capacity()`). + size_t maybe_invalid_capacity() const { return common().capacity(); } ctrl_t* control() const { ABSL_SWISSTABLE_ASSERT(!is_soo()); return common().control();
diff --git a/absl/container/internal/raw_hash_set_probe_benchmark.cc b/absl/container/internal/raw_hash_set_probe_benchmark.cc index 7165558..dcd1596 100644 --- a/absl/container/internal/raw_hash_set_probe_benchmark.cc +++ b/absl/container/internal/raw_hash_set_probe_benchmark.cc
@@ -20,6 +20,7 @@ #include <cstdint> #include <limits> #include <memory> +#include <optional> #include <regex> // NOLINT #include <string> #include <utility> @@ -36,7 +37,6 @@ #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" -#include "absl/types/optional.h" namespace { @@ -450,10 +450,10 @@ constexpr int kDistWidth = 16; bool CanRunBenchmark(absl::string_view name) { - static const absl::NoDestructor<absl::optional<std::regex>> filter([] { + static const absl::NoDestructor<std::optional<std::regex>> filter([] { return benchmarks.empty() || benchmarks == "all" - ? absl::nullopt - : absl::make_optional(std::regex(std::string(benchmarks))); + ? std::nullopt + : std::make_optional(std::regex(std::string(benchmarks))); }()); return !filter->has_value() || std::regex_search(std::string(name), **filter); }
diff --git a/absl/container/internal/raw_hash_set_test.cc b/absl/container/internal/raw_hash_set_test.cc index 5b3cd0e..610ba82 100644 --- a/absl/container/internal/raw_hash_set_test.cc +++ b/absl/container/internal/raw_hash_set_test.cc
@@ -31,6 +31,7 @@ #include <map> #include <memory> #include <numeric> +#include <optional> #include <ostream> #include <random> #include <set> @@ -53,7 +54,6 @@ #include "absl/container/internal/container_memory.h" #include "absl/container/internal/hash_function_defaults.h" #include "absl/container/internal/hash_policy_testing.h" -#include "absl/random/random.h" #include "absl/container/internal/hashtable_control_bytes.h" #include "absl/container/internal/hashtable_debug.h" #include "absl/container/internal/hashtablez_sampler.h" @@ -68,9 +68,9 @@ #include "absl/memory/memory.h" #include "absl/meta/type_traits.h" #include "absl/numeric/int128.h" +#include "absl/random/random.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -3840,7 +3840,7 @@ ~DestroyCaller() { if (destroy_func) (*destroy_func)(); } - void Deactivate() { destroy_func = absl::nullopt; } + void Deactivate() { destroy_func = std::nullopt; } template <typename H> friend H AbslHashValue(H h, const DestroyCaller& d) { @@ -3849,7 +3849,7 @@ bool operator==(const DestroyCaller& d) const { return val == d.val; } int val; - absl::optional<absl::FunctionRef<void()>> destroy_func; + std::optional<absl::FunctionRef<void()>> destroy_func; }; TEST(Table, ReentrantCallsFail) { @@ -3896,8 +3896,11 @@ } #if !defined(__clang__) && defined(__GNUC__) GTEST_SKIP() << "Flaky on GCC."; -#endif - absl::optional<IntTable> t; +#elif defined(ABSL_HAVE_THREAD_SANITIZER) + GTEST_SKIP() << "Fails on TSan."; + // Note: we use else rather than endif here to avoid unreachable code errors. +#else + std::optional<IntTable> t; t.emplace({1}); IntTable* t_ptr = &*t; EXPECT_TRUE(t_ptr->contains(1)); @@ -3907,8 +3910,10 @@ "use-of-uninitialized-value"; #else "destroyed hash table"; -#endif +#endif // ABSL_HAVE_MEMORY_SANITIZER EXPECT_DEATH_IF_SUPPORTED(t_ptr->contains(1), expected_death_message); + +#endif // ABSL_HAVE_THREAD_SANITIZER } TEST(Table, DestroyedCallsFailDuringDestruction) { @@ -3925,7 +3930,7 @@ bool do_lookup = false; using Table = absl::flat_hash_map<int, std::shared_ptr<int>>; - absl::optional<Table> t = Table(); + std::optional<Table> t = Table(); Table* t_ptr = &*t; auto destroy = [&](int* ptr) { if (do_lookup) { @@ -4001,64 +4006,91 @@ hs.generate_new_seed(); EXPECT_EQ(hs.size(), size); size = size * 2 + 1; - } while (size < MaxValidSizeFor1ByteSlot()); + } while (size < std::min(MaxStorableSize(), + MaxSizeAtMaxValidCapacity(/*slot_size=*/1))); } TEST(Table, MaxValidSize) { IntTable t; - EXPECT_EQ(MaxValidSize(sizeof(IntTable::value_type)), t.max_size()); + EXPECT_EQ( + MaxValidSize(sizeof(IntTable::key_type), sizeof(IntTable::value_type)), + t.max_size()); if constexpr (sizeof(size_t) == 8) { for (size_t i = 0; i < 35; ++i) { SCOPED_TRACE(i); size_t slot_size = size_t{1} << i; - size_t max_size = MaxValidSize(slot_size); - ASSERT_FALSE(IsAboveValidSize(max_size, slot_size)); - ASSERT_TRUE(IsAboveValidSize(max_size + 1, slot_size)); + size_t key_size = slot_size; + size_t max_size = MaxValidSize(key_size, slot_size); ASSERT_LT(max_size, uint64_t{1} << 60); - // For non gigantic slot sizes we expect max size to be at least 2^40. - if (i <= 22) { - ASSERT_FALSE(IsAboveValidSize(size_t{1} << 40, slot_size)); + if (key_size <= 4) { + ASSERT_EQ(max_size, uint64_t{1} << 8 * key_size); + } else if (i <= 21) { ASSERT_GE(max_size, uint64_t{1} << 40); } - ASSERT_LT(SizeToCapacity(max_size), - uint64_t{1} << HashtableSize::kSizeBitCount); + ASSERT_LE(max_size, uint64_t{1} << HashtableSize::kSizeBitCount); ASSERT_LT(absl::uint128(max_size) * slot_size, uint64_t{1} << 63); } } - EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(1), 1 << 30); - EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(2), 1 << 29); + EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(1, 1), 1 << 30); + EXPECT_LT(MaxValidSize</*kSizeOfSizeT=*/4>(2, 2), 1 << 29); for (size_t i = 0; i < 29; ++i) { + SCOPED_TRACE(i); size_t slot_size = size_t{1} << i; - size_t max_size = MaxValidSize</*kSizeOfSizeT=*/4>(slot_size); - ASSERT_FALSE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size, slot_size)); - ASSERT_TRUE(IsAboveValidSize</*kSizeOfSizeT=*/4>(max_size + 1, slot_size)); + size_t key_size = slot_size; + size_t max_size = MaxValidSize</*kSizeOfSizeT=*/4>(key_size, slot_size); ASSERT_LT(max_size, 1 << 30); size_t max_capacity = SizeToCapacity(max_size); - ASSERT_LT(max_capacity, (size_t{1} << 31) / slot_size); - ASSERT_GT(max_capacity, (1 << 29) / slot_size); + ASSERT_LT(uint64_t{max_capacity} * slot_size, size_t{1} << 31); + if (key_size < 4) { + ASSERT_EQ(max_size, uint64_t{1} << 8 * key_size); + } else { + ASSERT_GT(max_capacity, (1 << 29) / slot_size); + } ASSERT_LT(max_capacity * slot_size, size_t{1} << 31); } } TEST(Table, MaxSizeOverflow) { +#ifdef ABSL_HAVE_EXCEPTIONS + GTEST_SKIP() << "Skipping test because exceptions are enabled. EXPECT_DEATH " + "doesn't work with exceptions."; +#elif defined(ABSL_HAVE_THREAD_SANITIZER) + GTEST_SKIP() << "ThreadSanitizer test runs fail on OOM even in EXPECT_DEATH."; +#else + const std::string expected_death_message = + "new failed|failed to allocate|bad_alloc|exceeds maximum supported size"; size_t overflow = (std::numeric_limits<size_t>::max)(); - EXPECT_DEATH_IF_SUPPORTED(IntTable t(overflow), "Hash table size overflow"); + EXPECT_DEATH_IF_SUPPORTED(IntTable t(overflow), expected_death_message); IntTable t; - EXPECT_DEATH_IF_SUPPORTED(t.reserve(overflow), "Hash table size overflow"); - EXPECT_DEATH_IF_SUPPORTED(t.rehash(overflow), "Hash table size overflow"); - size_t slightly_overflow = MaxValidSize(sizeof(IntTable::value_type)) + 1; + EXPECT_DEATH_IF_SUPPORTED(t.reserve(overflow), expected_death_message); + EXPECT_DEATH_IF_SUPPORTED(t.rehash(overflow), expected_death_message); + size_t slightly_overflow = + MaxValidSize(sizeof(IntTable::key_type), sizeof(IntTable::value_type)) + + 1; size_t slightly_overflow_capacity = NextCapacity(NormalizeCapacity(slightly_overflow)); EXPECT_DEATH_IF_SUPPORTED(IntTable t2(slightly_overflow_capacity - 10), - "Hash table size overflow"); + expected_death_message); EXPECT_DEATH_IF_SUPPORTED(t.reserve(slightly_overflow), - "Hash table size overflow"); + expected_death_message); EXPECT_DEATH_IF_SUPPORTED(t.rehash(slightly_overflow), - "Hash table size overflow"); + expected_death_message); IntTable non_empty_table; non_empty_table.insert(0); EXPECT_DEATH_IF_SUPPORTED(non_empty_table.reserve(slightly_overflow), - "Hash table size overflow"); + expected_death_message); +#endif // defined(ABSL_HAVE_THREAD_SANITIZER) +} + +// Tests that reserving enough space for more than the max number of unique keys +// doesn't crash and we end up with kMaxValidCapacity. +TEST(Table, MaxSizeOverflowUniqueKeys) { + absl::flat_hash_set<uint8_t> t8; + t8.reserve(1 << 9); + EXPECT_EQ(t8.capacity(), SizeToCapacity(t8.max_size())); + absl::flat_hash_set<uint16_t> t16; + t16.reserve(1 << 17); + EXPECT_EQ(t16.capacity(), SizeToCapacity(t16.max_size())); } // TODO(b/397453582): Remove support for const hasher and remove this test. @@ -4082,9 +4114,11 @@ EXPECT_EQ(t.find(3), t.end()); } -struct ConstUint8Hash { - size_t operator()(uint8_t) const { return *value; } - size_t* value; +struct ZeroHash { + template <typename T> + size_t operator()(T) const { + return 0; + } }; // This test is imitating growth of a very big table and triggers all buffer @@ -4100,18 +4134,18 @@ // 4. Then a few times we will extend control buffer end. // 5. Finally we will catch up and go to overflow codepath. TEST(Table, GrowExtremelyLargeTable) { + // ProbedItem8Bytes causes OOMs on some platforms so we use ProbedItem4Bytes. constexpr size_t kTargetCapacity = -#if defined(__wasm__) || defined(__asmjs__) || defined(__i386__) - NextCapacity(ProbedItem4Bytes::kMaxNewCapacity); // OOMs on WASM, 32-bit. +#if defined(__wasm__) || defined(__asmjs__) || defined(__i386__) || \ + defined(_MSC_VER) || defined(ABSL_HAVE_THREAD_SANITIZER) || \ + defined(ABSL_HAVE_MEMORY_SANITIZER) || \ + (!defined(__clang__) && defined(__GNUC__)) + NextCapacity(ProbedItem4Bytes::kMaxNewCapacity); #else NextCapacity(ProbedItem8Bytes::kMaxNewCapacity); #endif - size_t hash = 0; - // In order to save memory we use 1 byte slot. - // There are not enough different values to achieve big capacity, so we - // artificially update growth info to force resize. - absl::flat_hash_set<uint8_t, ConstUint8Hash> t(63, ConstUint8Hash{&hash}); + absl::flat_hash_set<uint32_t, ZeroHash> t(63); CommonFields& common = RawHashSetTestOnlyAccess::GetCommon(t); // Set 0 seed so that H1 is always 0. common.set_no_seed_for_testing(); @@ -4127,7 +4161,8 @@ for (size_t cap = t.capacity(); cap < kTargetCapacity; cap = NextCapacity(cap)) { ASSERT_EQ(t.capacity(), cap); - // Update growth info to force resize on the next insert. + // Update growth info to force resize on the next insert. This way we avoid + // having to insert many elements. common.growth_info().OverwriteManyEmptyAsFull(CapacityToGrowth(cap) - t.size()); t.insert(inserted_till++);
diff --git a/absl/crc/BUILD.bazel b/absl/crc/BUILD.bazel index 22c3cbf..49e916c 100644 --- a/absl/crc/BUILD.bazel +++ b/absl/crc/BUILD.bazel
@@ -45,7 +45,6 @@ deps = [ "//absl/base", "//absl/base:config", - "//absl/types:optional", ], )
diff --git a/absl/crc/CMakeLists.txt b/absl/crc/CMakeLists.txt index 09d3485..034d0d0 100644 --- a/absl/crc/CMakeLists.txt +++ b/absl/crc/CMakeLists.txt
@@ -25,7 +25,6 @@ DEPS absl::base absl::config - absl::optional ) # Internal-only target, do not depend on directly.
diff --git a/absl/crc/internal/cpu_detect.cc b/absl/crc/internal/cpu_detect.cc index a697601..86f55d0 100644 --- a/absl/crc/internal/cpu_detect.cc +++ b/absl/crc/internal/cpu_detect.cc
@@ -15,10 +15,10 @@ #include "absl/crc/internal/cpu_detect.h" #include <cstdint> +#include <optional> // IWYU pragma: keep #include <string> #include "absl/base/config.h" -#include "absl/types/optional.h" // IWYU pragma: keep #if defined(__aarch64__) && defined(__linux__) #include <asm/hwcap.h> @@ -308,12 +308,12 @@ CpuType GetCpuType() { return CpuType::kUnknown; } template <typename T> -static absl::optional<T> ReadSysctlByName(const char* name) { +static std::optional<T> ReadSysctlByName(const char* name) { T val; size_t val_size = sizeof(T); int ret = sysctlbyname(name, &val, &val_size, nullptr, 0); if (ret == -1) { - return absl::nullopt; + return std::nullopt; } return val; } @@ -322,7 +322,7 @@ // Newer XNU kernels support querying all capabilities in a single // sysctlbyname. #if defined(CAP_BIT_CRC32) && defined(CAP_BIT_FEAT_PMULL) - static const absl::optional<uint64_t> caps = + static const std::optional<uint64_t> caps = ReadSysctlByName<uint64_t>("hw.optional.arm.caps"); if (caps.has_value()) { constexpr uint64_t kCrc32AndPmullCaps = @@ -332,13 +332,13 @@ #endif // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3915619 - static const absl::optional<int> armv8_crc32 = + static const std::optional<int> armv8_crc32 = ReadSysctlByName<int>("hw.optional.armv8_crc32"); if (armv8_crc32.value_or(0) == 0) { return false; } // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855 - static const absl::optional<int> feat_pmull = + static const std::optional<int> feat_pmull = ReadSysctlByName<int>("hw.optional.arm.FEAT_PMULL"); if (feat_pmull.value_or(0) == 0) { return false;
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel index a5ee2c7..9835648 100644 --- a/absl/flags/BUILD.bazel +++ b/absl/flags/BUILD.bazel
@@ -411,7 +411,6 @@ "//absl/numeric:int128", "//absl/strings", "//absl/time", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -437,7 +436,6 @@ ":reflection", "//absl/strings", "//absl/time", - "//absl/types:optional", "@google_benchmark//:benchmark_main", ], )
diff --git a/absl/flags/CMakeLists.txt b/absl/flags/CMakeLists.txt index 3ec254a..0c75c93 100644 --- a/absl/flags/CMakeLists.txt +++ b/absl/flags/CMakeLists.txt
@@ -352,7 +352,6 @@ absl::flags_parse absl::flags_reflection absl::int128 - absl::optional absl::raw_logging_internal absl::strings absl::time
diff --git a/absl/flags/commandlineflag.h b/absl/flags/commandlineflag.h index 1a9743c..9336d6d 100644 --- a/absl/flags/commandlineflag.h +++ b/absl/flags/commandlineflag.h
@@ -27,6 +27,7 @@ #define ABSL_FLAGS_COMMANDLINEFLAG_H_ #include <memory> +#include <optional> #include <string> #include "absl/base/config.h" @@ -87,11 +88,11 @@ // absl::CommandLineFlag::TryGet() // // Attempts to retrieve the flag value. Returns value on success, - // absl::nullopt otherwise. + // std::nullopt otherwise. template <typename T> - absl::optional<T> TryGet() const { + std::optional<T> TryGet() const { if (IsRetired() || !IsOfType<T>()) { - return absl::nullopt; + return std::nullopt; } // Implementation notes: @@ -119,7 +120,7 @@ Read(&u.value); // allow retired flags to be "read", so we can report invalid access. if (IsRetired()) { - return absl::nullopt; + return std::nullopt; } return std::move(u.value); }
diff --git a/absl/flags/flag_benchmark.cc b/absl/flags/flag_benchmark.cc index 88cc0c5..bbe9cba 100644 --- a/absl/flags/flag_benchmark.cc +++ b/absl/flags/flag_benchmark.cc
@@ -15,6 +15,7 @@ #include <stdint.h> +#include <optional> #include <string> #include <vector> @@ -24,7 +25,6 @@ #include "absl/flags/reflection.h" #include "absl/strings/string_view.h" #include "absl/time/time.h" -#include "absl/types/optional.h" #include "benchmark/benchmark.h" namespace { @@ -32,10 +32,10 @@ using VectorOfStrings = std::vector<std::string>; using AbslDuration = absl::Duration; -// We do not want to take over marshalling for the types absl::optional<int>, -// absl::optional<std::string> which we do not own. Instead we introduce unique +// We do not want to take over marshalling for the types std::optional<int>, +// std::optional<std::string> which we do not own. Instead we introduce unique // "aliases" to these types, which we do. -using AbslOptionalInt = absl::optional<int>; +using AbslOptionalInt = std::optional<int>; struct OptionalInt : AbslOptionalInt { using AbslOptionalInt::AbslOptionalInt; }; @@ -54,7 +54,7 @@ return !flag ? "" : absl::UnparseFlag(*flag); } -using AbslOptionalString = absl::optional<std::string>; +using AbslOptionalString = std::optional<std::string>; struct OptionalString : AbslOptionalString { using AbslOptionalString::AbslOptionalString; };
diff --git a/absl/flags/flag_test.cc b/absl/flags/flag_test.cc index e3ab24c..d303c8d 100644 --- a/absl/flags/flag_test.cc +++ b/absl/flags/flag_test.cc
@@ -19,6 +19,7 @@ #include <stdint.h> #include <atomic> +#include <optional> #include <string> #include <thread> // NOLINT #include <vector> @@ -42,7 +43,6 @@ #include "absl/strings/string_view.h" #include "absl/time/clock.h" #include "absl/time/time.h" -#include "absl/types/optional.h" ABSL_DECLARE_FLAG(int64_t, mistyped_int_flag); ABSL_DECLARE_FLAG(std::vector<std::string>, mistyped_string_flag); @@ -1038,7 +1038,7 @@ template <int id, typename F> void TestExpectedLeaks( F&& f, uint64_t num_leaks, - absl::optional<uint64_t> num_new_instances = absl::nullopt) { + std::optional<uint64_t> num_new_instances = std::nullopt) { if (!num_new_instances.has_value()) num_new_instances = num_leaks; auto num_leaked_before = flags::NumLeakedFlagValues(); @@ -1216,14 +1216,14 @@ // -------------------------------------------------------------------- -ABSL_FLAG(absl::optional<bool>, optional_bool, absl::nullopt, "help"); -ABSL_FLAG(absl::optional<int>, optional_int, {}, "help"); -ABSL_FLAG(absl::optional<double>, optional_double, 9.3, "help"); -ABSL_FLAG(absl::optional<std::string>, optional_string, absl::nullopt, "help"); -ABSL_FLAG(absl::optional<absl::Duration>, optional_duration, absl::nullopt, +ABSL_FLAG(std::optional<bool>, optional_bool, std::nullopt, "help"); +ABSL_FLAG(std::optional<int>, optional_int, {}, "help"); +ABSL_FLAG(std::optional<double>, optional_double, 9.3, "help"); +ABSL_FLAG(std::optional<std::string>, optional_string, std::nullopt, "help"); +ABSL_FLAG(std::optional<absl::Duration>, optional_duration, std::nullopt, "help"); -ABSL_FLAG(absl::optional<absl::optional<int>>, optional_optional_int, - absl::nullopt, "help"); +ABSL_FLAG(std::optional<std::optional<int>>, optional_optional_int, + std::nullopt, "help"); #if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) ABSL_FLAG(std::optional<int64_t>, std_optional_int64, std::nullopt, "help"); #endif @@ -1232,7 +1232,7 @@ TEST_F(FlagTest, TestOptionalBool) { EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), std::nullopt); absl::SetFlag(&FLAGS_optional_bool, false); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value()); @@ -1242,16 +1242,16 @@ EXPECT_TRUE(absl::GetFlag(FLAGS_optional_bool).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), true); - absl::SetFlag(&FLAGS_optional_bool, absl::nullopt); + absl::SetFlag(&FLAGS_optional_bool, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_bool).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_bool), std::nullopt); } // -------------------------------------------------------------------- TEST_F(FlagTest, TestOptionalInt) { EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), std::nullopt); absl::SetFlag(&FLAGS_optional_int, 0); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value()); @@ -1261,9 +1261,9 @@ EXPECT_TRUE(absl::GetFlag(FLAGS_optional_int).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), 10); - absl::SetFlag(&FLAGS_optional_int, absl::nullopt); + absl::SetFlag(&FLAGS_optional_int, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_int).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_int), std::nullopt); } // -------------------------------------------------------------------- @@ -1280,16 +1280,16 @@ EXPECT_TRUE(absl::GetFlag(FLAGS_optional_double).has_value()); EXPECT_DOUBLE_EQ(*absl::GetFlag(FLAGS_optional_double), 1.234); - absl::SetFlag(&FLAGS_optional_double, absl::nullopt); + absl::SetFlag(&FLAGS_optional_double, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_double).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_double), std::nullopt); } // -------------------------------------------------------------------- TEST_F(FlagTest, TestOptionalString) { EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), std::nullopt); // Setting optional string to "" leads to undefined behavior. @@ -1301,16 +1301,16 @@ EXPECT_TRUE(absl::GetFlag(FLAGS_optional_string).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), "QWERTY"); - absl::SetFlag(&FLAGS_optional_string, absl::nullopt); + absl::SetFlag(&FLAGS_optional_string, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_string).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_string), std::nullopt); } // -------------------------------------------------------------------- TEST_F(FlagTest, TestOptionalDuration) { EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), std::nullopt); absl::SetFlag(&FLAGS_optional_duration, absl::ZeroDuration()); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value()); @@ -1320,37 +1320,37 @@ EXPECT_TRUE(absl::GetFlag(FLAGS_optional_duration).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::Hours(3)); - absl::SetFlag(&FLAGS_optional_duration, absl::nullopt); + absl::SetFlag(&FLAGS_optional_duration, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_duration).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_duration), std::nullopt); } // -------------------------------------------------------------------- TEST_F(FlagTest, TestOptionalOptional) { EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::nullopt); - absl::optional<int> nullint{absl::nullopt}; + std::optional<int> nullint{std::nullopt}; absl::SetFlag(&FLAGS_optional_optional_int, nullint); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value()); EXPECT_NE(absl::GetFlag(FLAGS_optional_optional_int), nullint); EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), - absl::optional<absl::optional<int>>{nullint}); + std::optional<std::optional<int>>{nullint}); absl::SetFlag(&FLAGS_optional_optional_int, 0); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0); - absl::SetFlag(&FLAGS_optional_optional_int, absl::optional<int>{0}); + absl::SetFlag(&FLAGS_optional_optional_int, std::optional<int>{0}); EXPECT_TRUE(absl::GetFlag(FLAGS_optional_optional_int).has_value()); EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), 0); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::optional<int>{0}); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::optional<int>{0}); - absl::SetFlag(&FLAGS_optional_optional_int, absl::nullopt); + absl::SetFlag(&FLAGS_optional_optional_int, std::nullopt); EXPECT_FALSE(absl::GetFlag(FLAGS_optional_optional_int).has_value()); - EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), absl::nullopt); + EXPECT_EQ(absl::GetFlag(FLAGS_optional_optional_int), std::nullopt); } // --------------------------------------------------------------------
diff --git a/absl/flags/marshalling.h b/absl/flags/marshalling.h index 301213a..5e04d6a 100644 --- a/absl/flags/marshalling.h +++ b/absl/flags/marshalling.h
@@ -199,15 +199,12 @@ #ifndef ABSL_FLAGS_MARSHALLING_H_ #define ABSL_FLAGS_MARSHALLING_H_ -#include "absl/base/config.h" -#include "absl/numeric/int128.h" - -#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) #include <optional> -#endif #include <string> #include <vector> +#include "absl/base/config.h" +#include "absl/numeric/int128.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" @@ -242,21 +239,6 @@ bool AbslParseFlag(absl::string_view, std::vector<std::string>*, std::string*); template <typename T> -bool AbslParseFlag(absl::string_view text, absl::optional<T>* f, - std::string* err) { - if (text.empty()) { - *f = absl::nullopt; - return true; - } - T value; - if (!absl::ParseFlag(text, &value, err)) return false; - - *f = std::move(value); - return true; -} - -#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) -template <typename T> bool AbslParseFlag(absl::string_view text, std::optional<T>* f, std::string* err) { if (text.empty()) { @@ -269,7 +251,6 @@ *f = std::move(value); return true; } -#endif template <typename T> bool InvokeParseFlag(absl::string_view input, T* dst, std::string* err) { @@ -285,16 +266,9 @@ std::string AbslUnparseFlag(const std::vector<std::string>&); template <typename T> -std::string AbslUnparseFlag(const absl::optional<T>& f) { - return f.has_value() ? absl::UnparseFlag(*f) : ""; -} - -#if defined(ABSL_HAVE_STD_OPTIONAL) && !defined(ABSL_USES_STD_OPTIONAL) -template <typename T> std::string AbslUnparseFlag(const std::optional<T>& f) { return f.has_value() ? absl::UnparseFlag(*f) : ""; } -#endif template <typename T> std::string Unparse(const T& v) {
diff --git a/absl/flags/marshalling_test.cc b/absl/flags/marshalling_test.cc index b0e055f..a5faabc 100644 --- a/absl/flags/marshalling_test.cc +++ b/absl/flags/marshalling_test.cc
@@ -19,6 +19,7 @@ #include <cmath> #include <limits> +#include <optional> #include <string> #include <vector> @@ -777,7 +778,7 @@ TEST(MarshallingTest, TestOptionalBoolParsing) { std::string err; - absl::optional<bool> value; + std::optional<bool> value; EXPECT_TRUE(absl::ParseFlag("", &value, &err)); EXPECT_FALSE(value.has_value()); @@ -797,7 +798,7 @@ TEST(MarshallingTest, TestOptionalIntParsing) { std::string err; - absl::optional<int> value; + std::optional<int> value; EXPECT_TRUE(absl::ParseFlag("", &value, &err)); EXPECT_FALSE(value.has_value()); @@ -817,7 +818,7 @@ TEST(MarshallingTest, TestOptionalDoubleParsing) { std::string err; - absl::optional<double> value; + std::optional<double> value; EXPECT_TRUE(absl::ParseFlag("", &value, &err)); EXPECT_FALSE(value.has_value()); @@ -837,7 +838,7 @@ TEST(MarshallingTest, TestOptionalStringParsing) { std::string err; - absl::optional<std::string> value; + std::optional<std::string> value; EXPECT_TRUE(absl::ParseFlag("", &value, &err)); EXPECT_FALSE(value.has_value()); @@ -1041,49 +1042,49 @@ // -------------------------------------------------------------------- TEST(MarshallingTest, TestOptionalBoolUnparsing) { - absl::optional<bool> value; + std::optional<bool> value; EXPECT_EQ(absl::UnparseFlag(value), ""); value = true; EXPECT_EQ(absl::UnparseFlag(value), "true"); value = false; EXPECT_EQ(absl::UnparseFlag(value), "false"); - value = absl::nullopt; + value = std::nullopt; EXPECT_EQ(absl::UnparseFlag(value), ""); } // -------------------------------------------------------------------- TEST(MarshallingTest, TestOptionalIntUnparsing) { - absl::optional<int> value; + std::optional<int> value; EXPECT_EQ(absl::UnparseFlag(value), ""); value = 0; EXPECT_EQ(absl::UnparseFlag(value), "0"); value = -12; EXPECT_EQ(absl::UnparseFlag(value), "-12"); - value = absl::nullopt; + value = std::nullopt; EXPECT_EQ(absl::UnparseFlag(value), ""); } // -------------------------------------------------------------------- TEST(MarshallingTest, TestOptionalDoubleUnparsing) { - absl::optional<double> value; + std::optional<double> value; EXPECT_EQ(absl::UnparseFlag(value), ""); value = 1.; EXPECT_EQ(absl::UnparseFlag(value), "1"); value = -1.23; EXPECT_EQ(absl::UnparseFlag(value), "-1.23"); - value = absl::nullopt; + value = std::nullopt; EXPECT_EQ(absl::UnparseFlag(value), ""); } // -------------------------------------------------------------------- TEST(MarshallingTest, TestOptionalStringUnparsing) { - absl::optional<std::string> strvalue; + std::optional<std::string> strvalue; EXPECT_EQ(absl::UnparseFlag(strvalue), ""); strvalue = "asdfg";
diff --git a/absl/functional/BUILD.bazel b/absl/functional/BUILD.bazel index b7aa31f..dcf808b 100644 --- a/absl/functional/BUILD.bazel +++ b/absl/functional/BUILD.bazel
@@ -149,7 +149,6 @@ "//absl/base:config", "//absl/strings", "//absl/strings:string_view", - "//absl/types:variant", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/functional/CMakeLists.txt b/absl/functional/CMakeLists.txt index 07f3dc0..4ffb513 100644 --- a/absl/functional/CMakeLists.txt +++ b/absl/functional/CMakeLists.txt
@@ -135,6 +135,5 @@ absl::overload absl::string_view absl::strings - absl::variant GTest::gmock_main )
diff --git a/absl/functional/overload_test.cc b/absl/functional/overload_test.cc index 802e11f..bb51020 100644 --- a/absl/functional/overload_test.cc +++ b/absl/functional/overload_test.cc
@@ -17,12 +17,12 @@ #include <cstdint> #include <string> #include <type_traits> +#include <variant> #include "gtest/gtest.h" #include "absl/base/config.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/types/variant.h" namespace { @@ -145,32 +145,32 @@ } TEST(OverloadTest, VariantVisitDispatchesCorrectly) { - absl::variant<int, double, std::string> v(1); + std::variant<int, double, std::string> v(1); auto overloaded = absl::Overload{ [](int) -> absl::string_view { return "int"; }, [](double) -> absl::string_view { return "double"; }, [](const std::string&) -> absl::string_view { return "string"; }, }; - EXPECT_EQ("int", absl::visit(overloaded, v)); + EXPECT_EQ("int", std::visit(overloaded, v)); v = 1.1; - EXPECT_EQ("double", absl::visit(overloaded, v)); + EXPECT_EQ("double", std::visit(overloaded, v)); v = "hello"; - EXPECT_EQ("string", absl::visit(overloaded, v)); + EXPECT_EQ("string", std::visit(overloaded, v)); } TEST(OverloadTest, VariantVisitWithAutoFallbackDispatchesCorrectly) { - absl::variant<std::string, int32_t, int64_t> v(int32_t{1}); + std::variant<std::string, int32_t, int64_t> v(int32_t{1}); auto overloaded = absl::Overload{ [](const std::string& s) { return s.size(); }, [](const auto& s) { return sizeof(s); }, }; - EXPECT_EQ(4, absl::visit(overloaded, v)); + EXPECT_EQ(4, std::visit(overloaded, v)); v = int64_t{1}; - EXPECT_EQ(8, absl::visit(overloaded, v)); + EXPECT_EQ(8, std::visit(overloaded, v)); v = std::string("hello"); - EXPECT_EQ(5, absl::visit(overloaded, v)); + EXPECT_EQ(5, std::visit(overloaded, v)); } // This API used to be exported as a function, so it should also work fine to @@ -180,14 +180,14 @@ absl::Overload([](const std::string& s) { return s.size(); }, [](const auto& s) { return sizeof(s); }); - absl::variant<std::string, int32_t, int64_t> v(int32_t{1}); - EXPECT_EQ(4, absl::visit(overloaded, v)); + std::variant<std::string, int32_t, int64_t> v(int32_t{1}); + EXPECT_EQ(4, std::visit(overloaded, v)); v = int64_t{1}; - EXPECT_EQ(8, absl::visit(overloaded, v)); + EXPECT_EQ(8, std::visit(overloaded, v)); v = std::string("hello"); - EXPECT_EQ(5, absl::visit(overloaded, v)); + EXPECT_EQ(5, std::visit(overloaded, v)); } TEST(OverloadTest, HasConstexprConstructor) {
diff --git a/absl/hash/BUILD.bazel b/absl/hash/BUILD.bazel index 76dd606..a2d3a02 100644 --- a/absl/hash/BUILD.bazel +++ b/absl/hash/BUILD.bazel
@@ -98,8 +98,6 @@ "//absl/numeric:bits", "//absl/strings:cord_test_helpers", "//absl/strings:string_view", - "//absl/types:optional", - "//absl/types:variant", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/hash/CMakeLists.txt b/absl/hash/CMakeLists.txt index c8797ff..c593a5b 100644 --- a/absl/hash/CMakeLists.txt +++ b/absl/hash/CMakeLists.txt
@@ -76,10 +76,8 @@ absl::hash_testing absl::memory absl::meta - absl::optional absl::spy_hash_state absl::string_view - absl::variant GTest::gmock_main )
diff --git a/absl/hash/hash_test.cc b/absl/hash/hash_test.cc index 7395ab7..039515a 100644 --- a/absl/hash/hash_test.cc +++ b/absl/hash/hash_test.cc
@@ -26,6 +26,7 @@ #include <ios> #include <limits> #include <memory> +#include <optional> #include <ostream> #include <set> #include <string> @@ -34,6 +35,7 @@ #include <type_traits> #include <unordered_map> #include <utility> +#include <variant> #include <vector> #include "gmock/gmock.h" @@ -49,8 +51,6 @@ #include "absl/numeric/bits.h" #include "absl/strings/cord_test_helpers.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" -#include "absl/types/variant.h" #ifdef ABSL_INTERNAL_STD_FILESYSTEM_PATH_HASH_AVAILABLE #include <filesystem> // NOLINT @@ -748,22 +748,22 @@ } TEST(HashValueTest, Optional) { - EXPECT_TRUE(is_hashable<absl::optional<Private>>::value); + EXPECT_TRUE(is_hashable<std::optional<Private>>::value); - using O = absl::optional<Private>; + using O = std::optional<Private>; EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly( std::make_tuple(O{}, O{{1}}, O{{-1}}, O{{10}}))); } TEST(HashValueTest, Variant) { - using V = absl::variant<Private, std::string>; + using V = std::variant<Private, std::string>; EXPECT_TRUE(is_hashable<V>::value); EXPECT_TRUE(absl::VerifyTypeImplementsAbslHashCorrectly(std::make_tuple( V(Private{1}), V(Private{-1}), V(Private{2}), V("ABC"), V("BCD")))); struct S {}; - EXPECT_FALSE(is_hashable<absl::variant<S>>::value); + EXPECT_FALSE(is_hashable<std::variant<S>>::value); } TEST(HashValueTest, ReferenceWrapper) {
diff --git a/absl/hash/hash_testing.h b/absl/hash/hash_testing.h index 817a40d..509df07 100644 --- a/absl/hash/hash_testing.h +++ b/absl/hash/hash_testing.h
@@ -20,6 +20,7 @@ #include <string> #include <tuple> #include <type_traits> +#include <variant> #include <vector> #include "gmock/gmock.h" @@ -193,9 +194,9 @@ const V& value; size_t index; std::string ToString() const { - return absl::visit(PrintVisitor{index}, value); + return std::visit(PrintVisitor{index}, value); } - SpyHashState expand() const { return absl::visit(ExpandVisitor{}, value); } + SpyHashState expand() const { return std::visit(ExpandVisitor{}, value); } }; using EqClass = std::vector<Info>; @@ -206,7 +207,7 @@ for (const auto& value : values) { EqClass* c = nullptr; for (auto& eqclass : classes) { - if (absl::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) { + if (std::visit(EqVisitor<Eq>{equals}, value, eqclass[0].value)) { c = &eqclass; break; } @@ -300,11 +301,11 @@ template <typename... T> using VariantForTypes = typename MakeTypeSet< - const typename std::decay<T>::type*...>::template apply<absl::variant>; + const typename std::decay<T>::type*...>::template apply<std::variant>; template <typename Container> struct ContainerAsVector { - using V = absl::variant<const typename Container::value_type*>; + using V = std::variant<const typename Container::value_type*>; using Out = std::vector<V>; static Out Do(const Container& values) {
diff --git a/absl/hash/internal/hash.h b/absl/hash/internal/hash.h index 4fe474e..a6c8313 100644 --- a/absl/hash/internal/hash.h +++ b/absl/hash/internal/hash.h
@@ -63,6 +63,7 @@ #include <list> #include <map> #include <memory> +#include <optional> #include <set> #include <string> #include <string_view> @@ -71,6 +72,7 @@ #include <unordered_map> #include <unordered_set> #include <utility> +#include <variant> #include <vector> #include "absl/base/attributes.h" @@ -898,10 +900,10 @@ return H::combine(std::move(hash_state), opt.get()); } -// AbslHashValue for hashing absl::optional +// AbslHashValue for hashing std::optional template <typename H, typename T> typename std::enable_if<is_hashable<T>::value, H>::type AbslHashValue( - H hash_state, const absl::optional<T>& opt) { + H hash_state, const std::optional<T>& opt) { if (opt) hash_state = H::combine(std::move(hash_state), *opt); return H::combine(std::move(hash_state), opt.has_value()); } @@ -915,12 +917,12 @@ } }; -// AbslHashValue for hashing absl::variant +// AbslHashValue for hashing std::variant template <typename H, typename... T> typename std::enable_if<conjunction<is_hashable<T>...>::value, H>::type -AbslHashValue(H hash_state, const absl::variant<T...>& v) { +AbslHashValue(H hash_state, const std::variant<T...>& v) { if (!v.valueless_by_exception()) { - hash_state = absl::visit(VariantVisitor<H>{std::move(hash_state)}, v); + hash_state = std::visit(VariantVisitor<H>{std::move(hash_state)}, v); } return H::combine(std::move(hash_state), v.index()); } @@ -1079,19 +1081,24 @@ // The general idea here is to do two CRC32 operations in parallel using the // low and high 32 bits of state as CRC states. Note that: (1) when absl::Hash // is inlined into swisstable lookups, we know that the seed's high bits are - // zero so s.u32s.high is available immediately. (2) We chose to rotate value - // right by 45 for the low CRC because that minimizes the probe benchmark - // geomean across the 64 possible rotations. (3) The union makes it easy for - // the compiler to understand that the high and low CRC states are independent - // from each other so that when CombineRawImpl is repeated (e.g. for - // std::pair<size_t, size_t>), the CRC chains can run in parallel. We + // zero so s.u32s.high is available immediately. (2) We chose to multiply + // value by 3 for the low CRC because (a) multiplication by 3 can be done in 1 + // cycle on x86/ARM and (b) multiplication has carry bits so it's nonlinear in + // GF(2) and therefore ensures that the two CRCs are independent (unlike bit + // rotation, XOR, etc). (3) We also tried using addition instead of + // multiplication by 3, but (a) code size is larger and (b) if the input keys + // all have 0s in the bits where the addition constant has 1s, then the + // addition is equivalent to XOR and linear in GF(2). (4) The union makes it + // easy for the compiler to understand that the high and low CRC states are + // independent from each other so that when CombineRawImpl is repeated (e.g. + // for std::pair<size_t, size_t>), the CRC chains can run in parallel. We // originally tried using bswaps rather than shifting by 32 bits (to get from // high to low bits) because bswap is one byte smaller in code size, but the // compiler couldn't understand that the CRC chains were independent. s.u32s.high = static_cast<uint32_t>(ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.high, value)); s.u32s.low = static_cast<uint32_t>( - ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.low, absl::rotr(value, 45))); + ABSL_HASH_INTERNAL_CRC32_U64(s.u32s.low, 3 * value)); return s.u64; } #else // ABSL_HASH_INTERNAL_HAS_CRC32
diff --git a/absl/hash/internal/spy_hash_state.h b/absl/hash/internal/spy_hash_state.h index 823e1e9..80c9767 100644 --- a/absl/hash/internal/spy_hash_state.h +++ b/absl/hash/internal/spy_hash_state.h
@@ -18,6 +18,8 @@ #include <algorithm> #include <cstddef> #include <cstdint> +#include <memory> +#include <optional> #include <ostream> #include <string> #include <vector> @@ -44,7 +46,7 @@ template <typename T> class SpyHashStateImpl : public HashStateBase<SpyHashStateImpl<T>> { public: - SpyHashStateImpl() : error_(std::make_shared<absl::optional<std::string>>()) { + SpyHashStateImpl() : error_(std::make_shared<std::optional<std::string>>()) { static_assert(std::is_void<T>::value, ""); } @@ -198,7 +200,7 @@ return state; } - absl::optional<std::string> error() const { + std::optional<std::string> error() const { if (moved_from_) { return "Returned a moved-from instance of the hash state object."; } @@ -212,7 +214,7 @@ struct UnorderedCombinerCallback { std::vector<std::string> element_hash_representations; - std::shared_ptr<absl::optional<std::string>> error; + std::shared_ptr<std::optional<std::string>> error; // The inner spy can have a different type. template <typename U> @@ -242,7 +244,7 @@ // This is a shared_ptr because we want all instances of the particular // SpyHashState run to share the field. This way we can set the error for // use-after-move and all the copies will see it. - std::shared_ptr<absl::optional<std::string>> error_; + std::shared_ptr<std::optional<std::string>> error_; bool moved_from_ = false; };
diff --git a/absl/log/BUILD.bazel b/absl/log/BUILD.bazel index 5bc7150..ec2fde9 100644 --- a/absl/log/BUILD.bazel +++ b/absl/log/BUILD.bazel
@@ -285,7 +285,6 @@ ":vlog_is_on", "//absl/base:log_severity", "//absl/flags:flag", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -501,7 +500,6 @@ "//absl/log/internal:test_matchers", "//absl/strings", "//absl/strings:str_format", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ],
diff --git a/absl/log/CMakeLists.txt b/absl/log/CMakeLists.txt index 9d097ab..609f432 100644 --- a/absl/log/CMakeLists.txt +++ b/absl/log/CMakeLists.txt
@@ -757,7 +757,6 @@ absl::nullability absl::strings absl::synchronization - absl::optional ) absl_cc_library( @@ -806,7 +805,6 @@ absl::vlog_is_on absl::log_severity absl::flags - absl::optional GTest::gmock_main ) @@ -1016,7 +1014,6 @@ absl::config absl::log absl::log_internal_test_matchers - absl::optional absl::scoped_mock_log absl::str_format absl::strings
diff --git a/absl/log/internal/BUILD.bazel b/absl/log/internal/BUILD.bazel index 32ae277..833a5f9 100644 --- a/absl/log/internal/BUILD.bazel +++ b/absl/log/internal/BUILD.bazel
@@ -470,7 +470,6 @@ "//absl/memory", "//absl/strings", "//absl/synchronization", - "//absl/types:optional", ], )
diff --git a/absl/log/internal/structured_proto.cc b/absl/log/internal/structured_proto.cc index e3829e4..eed2e88 100644 --- a/absl/log/internal/structured_proto.cc +++ b/absl/log/internal/structured_proto.cc
@@ -16,11 +16,11 @@ #include "absl/log/internal/structured_proto.h" #include <cstdint> +#include <variant> #include "absl/base/config.h" #include "absl/log/internal/proto.h" #include "absl/types/span.h" -#include "absl/types/variant.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -81,11 +81,11 @@ // Handles protobuf-encoding a type contained inside `StructuredProtoField`. struct EncoderVisitor final { bool operator()(StructuredProtoField::Varint varint) { - return absl::visit(VarintEncoderVisitor{field_number, buf}, varint); + return std::visit(VarintEncoderVisitor{field_number, buf}, varint); } bool operator()(StructuredProtoField::I64 i64) { - return absl::visit(I64EncoderVisitor{field_number, buf}, i64); + return std::visit(I64EncoderVisitor{field_number, buf}, i64); } bool operator()(StructuredProtoField::LengthDelimited length_delimited) { @@ -95,7 +95,7 @@ } bool operator()(StructuredProtoField::I32 i32) { - return absl::visit(I32EncoderVisitor{field_number, buf}, i32); + return std::visit(I32EncoderVisitor{field_number, buf}, i32); } uint64_t field_number; @@ -106,7 +106,7 @@ bool EncodeStructuredProtoField(StructuredProtoField field, absl::Span<char>& buf) { - return absl::visit(EncoderVisitor{field.field_number, buf}, field.value); + return std::visit(EncoderVisitor{field.field_number, buf}, field.value); } } // namespace log_internal
diff --git a/absl/log/internal/structured_proto.h b/absl/log/internal/structured_proto.h index 3ebc4be..04ec499 100644 --- a/absl/log/internal/structured_proto.h +++ b/absl/log/internal/structured_proto.h
@@ -21,6 +21,7 @@ #include <cstddef> #include <cstdint> +#include <variant> #include "absl/base/config.h" #include "absl/log/internal/proto.h" @@ -35,11 +36,11 @@ struct StructuredProtoField final { // Numeric type encoded with varint encoding: // https://protobuf.dev/programming-guides/encoding/#varints - using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>; + using Varint = std::variant<uint64_t, int64_t, uint32_t, int32_t, bool>; // Fixed-length 64-bit integer encoding: // https://protobuf.dev/programming-guides/encoding/#non-varints - using I64 = absl::variant<uint64_t, int64_t, double>; + using I64 = std::variant<uint64_t, int64_t, double>; // Length-delimited record type (string, sub-message): // https://protobuf.dev/programming-guides/encoding/#length-types @@ -47,11 +48,11 @@ // Fixed-length 32-bit integer encoding: // https://protobuf.dev/programming-guides/encoding/#non-varints - using I32 = absl::variant<uint32_t, int32_t, float>; + using I32 = std::variant<uint32_t, int32_t, float>; // Valid record type: // https://protobuf.dev/programming-guides/encoding/#structure - using Value = absl::variant<Varint, I64, LengthDelimited, I32>; + using Value = std::variant<Varint, I64, LengthDelimited, I32>; // Field number for the protobuf value. uint64_t field_number; @@ -88,7 +89,7 @@ uint64_t field_number; }; - return absl::visit(BufferSizeVisitor{field.field_number}, field.value); + return std::visit(BufferSizeVisitor{field.field_number}, field.value); } // Encodes `field` into `buf` using protobuf encoding.
diff --git a/absl/log/internal/vlog_config.cc b/absl/log/internal/vlog_config.cc index e9b4827..51f003c 100644 --- a/absl/log/internal/vlog_config.cc +++ b/absl/log/internal/vlog_config.cc
@@ -20,6 +20,7 @@ #include <atomic> #include <functional> #include <memory> +#include <optional> #include <string> #include <utility> #include <vector> @@ -38,7 +39,6 @@ #include "absl/strings/string_view.h" #include "absl/strings/strip.h" #include "absl/synchronization/mutex.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -189,7 +189,7 @@ // Allocates memory. int PrependVModuleLocked(absl::string_view module_pattern, int log_level) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex) { - absl::optional<int> old_log_level; + std::optional<int> old_log_level; for (const auto& info : get_vmodule_info()) { if (FNMatch(info.module_pattern, module_pattern)) { old_log_level = info.vlog_level;
diff --git a/absl/log/log_format_test.cc b/absl/log/log_format_test.cc index 9f1cc6b..b23d90f 100644 --- a/absl/log/log_format_test.cc +++ b/absl/log/log_format_test.cc
@@ -19,6 +19,7 @@ #include <iomanip> #include <ios> #include <limits> +#include <optional> #include <ostream> #include <sstream> #include <string> @@ -28,6 +29,7 @@ #ifdef __ANDROID__ #include <android/api-level.h> #endif + #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/config.h" @@ -39,7 +41,6 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace { using ::absl::log_internal::AsString; @@ -2096,7 +2097,7 @@ } private: - absl::optional<size_t> size_; + std::optional<size_t> size_; } extractor_sink; LOG(INFO).NoPrefix().ToSinkOnly(&extractor_sink) << std::string(2 * absl::log_internal::kLogMessageBufferSize, 'x');
diff --git a/absl/log/log_streamer.h b/absl/log/log_streamer.h index 4ed2435..32c3402 100644 --- a/absl/log/log_streamer.h +++ b/absl/log/log_streamer.h
@@ -24,6 +24,7 @@ #include <ios> #include <memory> +#include <optional> #include <ostream> #include <string> #include <utility> @@ -131,7 +132,7 @@ std::string buf_; // A disengaged `stream_` indicates a moved-from `LogStreamer` that should not // `LOG` upon destruction. - absl::optional<absl::strings_internal::OStringStream> stream_; + std::optional<absl::strings_internal::OStringStream> stream_; }; // LogInfoStreamer()
diff --git a/absl/log/vlog_is_on_test.cc b/absl/log/vlog_is_on_test.cc index f612283..d523781 100644 --- a/absl/log/vlog_is_on_test.cc +++ b/absl/log/vlog_is_on_test.cc
@@ -14,6 +14,8 @@ #include "absl/log/vlog_is_on.h" +#include <optional> + #include "gmock/gmock.h" #include "gtest/gtest.h" #include "absl/base/log_severity.h" @@ -22,25 +24,24 @@ #include "absl/log/globals.h" #include "absl/log/log.h" #include "absl/log/scoped_mock_log.h" -#include "absl/types/optional.h" namespace { using ::testing::_; -absl::optional<int> MaxLogVerbosity() { +std::optional<int> MaxLogVerbosity() { #ifdef ABSL_MAX_VLOG_VERBOSITY return ABSL_MAX_VLOG_VERBOSITY; #else - return absl::nullopt; + return std::nullopt; #endif } -absl::optional<int> MinLogLevel() { +std::optional<int> MinLogLevel() { #ifdef ABSL_MIN_LOG_LEVEL return static_cast<int>(ABSL_MIN_LOG_LEVEL); #else - return absl::nullopt; + return std::nullopt; #endif }
diff --git a/absl/random/CMakeLists.txt b/absl/random/CMakeLists.txt index e0294a1..7382b0d 100644 --- a/absl/random/CMakeLists.txt +++ b/absl/random/CMakeLists.txt
@@ -852,7 +852,6 @@ absl::random_internal_platform absl::random_internal_randen_hwaes_impl absl::config - absl::optional ) # Internal-only target, do not depend on directly.
diff --git a/absl/random/internal/BUILD.bazel b/absl/random/internal/BUILD.bazel index 1a3fef8..d292d34 100644 --- a/absl/random/internal/BUILD.bazel +++ b/absl/random/internal/BUILD.bazel
@@ -399,7 +399,6 @@ ":platform", ":randen_hwaes_impl", "//absl/base:config", - "//absl/types:optional", ], )
diff --git a/absl/random/internal/mock_helpers.h b/absl/random/internal/mock_helpers.h index 85f7387..2d66a3b 100644 --- a/absl/random/internal/mock_helpers.h +++ b/absl/random/internal/mock_helpers.h
@@ -16,6 +16,7 @@ #ifndef ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ #define ABSL_RANDOM_INTERNAL_MOCK_HELPERS_H_ +#include <optional> #include <utility> #include "absl/base/config.h" @@ -71,21 +72,21 @@ // Empty implementation of InvokeMock. template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, typename... Args> - static absl::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { - return absl::nullopt; + static std::optional<ReturnT> InvokeMockImpl(char, URBG*, Args&&...) { + return std::nullopt; } // Non-empty implementation of InvokeMock. template <typename KeyT, typename ReturnT, typename ArgTupleT, typename URBG, typename = invoke_mock_t<URBG>, typename... Args> - static absl::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, - Args&&... args) { + static std::optional<ReturnT> InvokeMockImpl(int, URBG* urbg, + Args&&... args) { ArgTupleT arg_tuple(std::forward<Args>(args)...); ReturnT result; if (urbg->InvokeMock(FastTypeId<KeyT>(), &arg_tuple, &result)) { return result; } - return absl::nullopt; + return std::nullopt; } public: @@ -108,7 +109,7 @@ // the underlying mechanism requires a pointer to an argument tuple. template <typename KeyT, typename URBG, typename... Args> static auto MaybeInvokeMock(URBG* urbg, Args&&... args) - -> absl::optional<typename KeySignature<KeyT>::result_type> { + -> std::optional<typename KeySignature<KeyT>::result_type> { // Use function overloading to dispatch to the implementation since // more modern patterns (e.g. require + constexpr) are not supported in all // compiler configurations.
diff --git a/absl/random/internal/randen_detect.cc b/absl/random/internal/randen_detect.cc index 63e8379..fc8c673 100644 --- a/absl/random/internal/randen_detect.cc +++ b/absl/random/internal/randen_detect.cc
@@ -31,9 +31,9 @@ #include <cstdint> #include <cstring> +#include <optional> // IWYU pragma: keep #include "absl/random/internal/platform.h" -#include "absl/types/optional.h" // IWYU pragma: keep #if !defined(__UCLIBC__) && defined(__GLIBC__) && \ (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 16)) @@ -115,12 +115,12 @@ #if defined(__APPLE__) && defined(ABSL_ARCH_AARCH64) template <typename T> -static absl::optional<T> ReadSysctlByName(const char* name) { +static std::optional<T> ReadSysctlByName(const char* name) { T val; size_t val_size = sizeof(T); int ret = sysctlbyname(name, &val, &val_size, nullptr, 0); if (ret == -1) { - return absl::nullopt; + return std::nullopt; } return val; } @@ -210,7 +210,7 @@ // Newer XNU kernels support querying all capabilities in a single // sysctlbyname. #if defined(CAP_BIT_AdvSIMD) && defined(CAP_BIT_FEAT_AES) - static const absl::optional<uint64_t> caps = + static const std::optional<uint64_t> caps = ReadSysctlByName<uint64_t>("hw.optional.arm.caps"); if (caps.has_value()) { constexpr uint64_t kNeonAndAesCaps = @@ -220,13 +220,13 @@ #endif // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#overview - static const absl::optional<int> adv_simd = + static const std::optional<int> adv_simd = ReadSysctlByName<int>("hw.optional.AdvSIMD"); if (adv_simd.value_or(0) == 0) { return false; } // https://developer.apple.com/documentation/kernel/1387446-sysctlbyname/determining_instruction_set_characteristics#3918855 - static const absl::optional<int> feat_aes = + static const std::optional<int> feat_aes = ReadSysctlByName<int>("hw.optional.arm.FEAT_AES"); if (feat_aes.value_or(0) == 0) { return false;
diff --git a/absl/random/internal/salted_seed_seq.h b/absl/random/internal/salted_seed_seq.h index 0629186..c374d93 100644 --- a/absl/random/internal/salted_seed_seq.h +++ b/absl/random/internal/salted_seed_seq.h
@@ -20,6 +20,7 @@ #include <initializer_list> #include <iterator> #include <memory> +#include <optional> #include <type_traits> #include <utility> #include <vector>
diff --git a/absl/random/internal/seed_material.cc b/absl/random/internal/seed_material.cc index b6380c8..f509926 100644 --- a/absl/random/internal/seed_material.cc +++ b/absl/random/internal/seed_material.cc
@@ -28,6 +28,7 @@ #include <cstdint> #include <cstdlib> #include <cstring> +#include <optional> #include <string> #include <vector> @@ -38,7 +39,6 @@ #include "absl/strings/escaping.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" -#include "absl/types/optional.h" #include "absl/types/span.h" #if defined(_WIN32) @@ -228,17 +228,17 @@ } } -absl::optional<uint32_t> GetSaltMaterial() { +std::optional<uint32_t> GetSaltMaterial() { // Salt must be common for all generators within the same process so read it // only once and store in static variable. - static const auto salt_material = []() -> absl::optional<uint32_t> { + static const auto salt_material = []() -> std::optional<uint32_t> { uint32_t salt_value = 0; if (ReadSeedMaterialFromOSEntropy(absl::MakeSpan(&salt_value, 1))) { return salt_value; } - return absl::nullopt; + return std::nullopt; }(); return salt_material;
diff --git a/absl/random/internal/seed_material.h b/absl/random/internal/seed_material.h index b671a8c..23bf4fa 100644 --- a/absl/random/internal/seed_material.h +++ b/absl/random/internal/seed_material.h
@@ -18,6 +18,7 @@ #include <cassert> #include <cstdint> #include <cstdlib> +#include <optional> #include <string> #include <vector> @@ -95,7 +96,7 @@ // Salt is obtained only once and stored in static variable. // // May return empty value if obtaining the salt was not possible. -absl::optional<uint32_t> GetSaltMaterial(); +std::optional<uint32_t> GetSaltMaterial(); } // namespace random_internal ABSL_NAMESPACE_END
diff --git a/absl/status/BUILD.bazel b/absl/status/BUILD.bazel index 394222f..038f1da 100644 --- a/absl/status/BUILD.bazel +++ b/absl/status/BUILD.bazel
@@ -172,6 +172,7 @@ ":status", ":statusor", "//absl/base:config", + "//absl/base:core_headers", "//absl/strings:string_view", "@googletest//:gtest", ],
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt index d0d134c..a418bd9 100644 --- a/absl/status/CMakeLists.txt +++ b/absl/status/CMakeLists.txt
@@ -119,6 +119,7 @@ ${ABSL_DEFAULT_LINKOPTS} DEPS absl::base + absl::core_headers absl::status absl::statusor absl::strings
diff --git a/absl/status/internal/status_internal.cc b/absl/status/internal/status_internal.cc index 9884189..74bece4 100644 --- a/absl/status/internal/status_internal.cc +++ b/absl/status/internal/status_internal.cc
@@ -21,6 +21,7 @@ #include <cstdio> #include <cstring> #include <memory> +#include <optional> #include <string> #include <utility> @@ -40,7 +41,6 @@ #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN @@ -56,24 +56,24 @@ } } -static absl::optional<size_t> FindPayloadIndexByUrl( - const Payloads* payloads, absl::string_view type_url) { - if (payloads == nullptr) return absl::nullopt; +static std::optional<size_t> FindPayloadIndexByUrl(const Payloads* payloads, + absl::string_view type_url) { + if (payloads == nullptr) return std::nullopt; for (size_t i = 0; i < payloads->size(); ++i) { if ((*payloads)[i].type_url == type_url) return i; } - return absl::nullopt; + return std::nullopt; } -absl::optional<absl::Cord> StatusRep::GetPayload( +std::optional<absl::Cord> StatusRep::GetPayload( absl::string_view type_url) const { - absl::optional<size_t> index = + std::optional<size_t> index = status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url); if (index.has_value()) return (*payloads_)[index.value()].payload; - return absl::nullopt; + return std::nullopt; } void StatusRep::SetPayload(absl::string_view type_url, absl::Cord payload) { @@ -81,7 +81,7 @@ payloads_ = absl::make_unique<status_internal::Payloads>(); } - absl::optional<size_t> index = + std::optional<size_t> index = status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url); if (index.has_value()) { (*payloads_)[index.value()].payload = std::move(payload); @@ -92,7 +92,7 @@ } StatusRep::EraseResult StatusRep::ErasePayload(absl::string_view type_url) { - absl::optional<size_t> index = + std::optional<size_t> index = status_internal::FindPayloadIndexByUrl(payloads_.get(), type_url); if (!index.has_value()) return {false, Status::PointerToRep(this)}; payloads_->erase(payloads_->begin() + index.value()); @@ -142,7 +142,7 @@ status_internal::GetStatusPayloadPrinter(); this->ForEachPayload([&](absl::string_view type_url, const absl::Cord& payload) { - absl::optional<std::string> result; + std::optional<std::string> result; if (printer) result = printer(type_url, payload); absl::StrAppend( &text, " [", type_url, "='",
diff --git a/absl/status/internal/status_internal.h b/absl/status/internal/status_internal.h index 35a9f9b..f2bd83a 100644 --- a/absl/status/internal/status_internal.h +++ b/absl/status/internal/status_internal.h
@@ -20,6 +20,8 @@ #include <string> #include <utility> +#include <optional> + #include "absl/base/attributes.h" #include "absl/base/config.h" #include "absl/base/nullability.h" @@ -83,7 +85,7 @@ void Unref() const; // Payload methods correspond to the same methods in absl::Status. - absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const; + std::optional<absl::Cord> GetPayload(absl::string_view type_url) const; void SetPayload(absl::string_view type_url, absl::Cord payload); struct EraseResult { bool erased;
diff --git a/absl/status/internal/status_matchers.h b/absl/status/internal/status_matchers.h index d11742b..eb61d73 100644 --- a/absl/status/internal/status_matchers.h +++ b/absl/status/internal/status_matchers.h
@@ -16,12 +16,12 @@ #define ABSL_STATUS_INTERNAL_STATUS_MATCHERS_H_ #include <ostream> // NOLINT -#include <string> #include <type_traits> #include <utility> #include "gmock/gmock.h" // gmock_for_status_matchers.h #include "absl/base/config.h" +#include "absl/base/macros.h" #include "absl/status/status.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -30,12 +30,20 @@ ABSL_NAMESPACE_BEGIN namespace status_internal { -inline const absl::Status& GetStatus(const absl::Status& status) { +// TODO(b/323927127): Remove ABSL_REFACTOR_INLINE once callers are cleaned up +// and move it into a namespace like adl_barrier without types to avoid +// accidental ADL. +ABSL_REFACTOR_INLINE inline const absl::Status& GetStatus( + const absl::Status& status) { return status; } +// TODO(b/323927127): Remove ABSL_REFACTOR_INLINE once callers are cleaned up +// and move it into a namespace like adl_barrier without types to avoid +// accidental ADL. template <typename T> -inline const absl::Status& GetStatus(const absl::StatusOr<T>& status) { +ABSL_REFACTOR_INLINE const absl::Status& GetStatus( + const absl::StatusOr<T>& status) { return status.status(); }
diff --git a/absl/status/status.cc b/absl/status/status.cc index f219933..479c39f 100644 --- a/absl/status/status.cc +++ b/absl/status/status.cc
@@ -37,7 +37,6 @@ #include "absl/strings/str_format.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" namespace absl { ABSL_NAMESPACE_BEGIN
diff --git a/absl/status/status.h b/absl/status/status.h index b26d072..f81f912 100644 --- a/absl/status/status.h +++ b/absl/status/status.h
@@ -53,6 +53,7 @@ #include <cassert> #include <cstdint> +#include <optional> #include <ostream> #include <string> #include <utility> @@ -583,7 +584,7 @@ // Status::GetPayload() // // Gets the payload of a status given its unique `type_url` key, if present. - absl::optional<absl::Cord> GetPayload(absl::string_view type_url) const; + std::optional<absl::Cord> GetPayload(absl::string_view type_url) const; // Status::SetPayload() // @@ -862,9 +863,9 @@ swap(a.rep_, b.rep_); } -inline absl::optional<absl::Cord> Status::GetPayload( +inline std::optional<absl::Cord> Status::GetPayload( absl::string_view type_url) const { - if (IsInlined(rep_)) return absl::nullopt; + if (IsInlined(rep_)) return std::nullopt; return RepToPointer(rep_)->GetPayload(type_url); }
diff --git a/absl/status/status_matchers.h b/absl/status/status_matchers.h index 03e5f49..c418739 100644 --- a/absl/status/status_matchers.h +++ b/absl/status/status_matchers.h
@@ -129,7 +129,8 @@ // code matches code_matcher. See above for details. template <typename StatusCodeMatcherT> status_internal::StatusIsMatcher StatusIs(StatusCodeMatcherT&& code_matcher) { - return StatusIs(std::forward<StatusCodeMatcherT>(code_matcher), ::testing::_); + return absl_testing::StatusIs(std::forward<StatusCodeMatcherT>(code_matcher), + ::testing::_); } // Returns a gMock matcher that matches a Status or StatusOr<> which is OK.
diff --git a/absl/status/status_payload_printer.h b/absl/status/status_payload_printer.h index fc55515..7e2c8c8 100644 --- a/absl/status/status_payload_printer.h +++ b/absl/status/status_payload_printer.h
@@ -14,6 +14,7 @@ #ifndef ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_ #define ABSL_STATUS_STATUS_PAYLOAD_PRINTER_H_ +#include <optional> #include <string> #include "absl/base/nullability.h" @@ -30,12 +31,12 @@ // extension point, which is a global printer function that can be set by users // to specify how to print payloads. The function takes the type URL and the // payload as input, and should return a valid human-readable string on success -// or `absl::nullopt` on failure (in which case it falls back to the default +// or `std::nullopt` on failure (in which case it falls back to the default // approach of printing the raw bytes). // NOTE: This is an internal API and the design is subject to change in the // future in a non-backward-compatible way. Since it's only meant for debugging // purpose, you should not rely on it in any critical logic. -using StatusPayloadPrinter = absl::optional<std::string> (*absl_nullable)( +using StatusPayloadPrinter = std::optional<std::string> (*absl_nullable)( absl::string_view, const absl::Cord&); // Sets the global payload printer. Only one printer should be set per process.
diff --git a/absl/status/statusor.h b/absl/status/statusor.h index 52294ee..2427d24 100644 --- a/absl/status/statusor.h +++ b/absl/status/statusor.h
@@ -43,6 +43,7 @@ #include <string> #include <type_traits> #include <utility> +#include <variant> #include "absl/base/attributes.h" #include "absl/base/call_once.h"
diff --git a/absl/status/statusor_test.cc b/absl/status/statusor_test.cc index 26d4235..82cb930 100644 --- a/absl/status/statusor_test.cc +++ b/absl/status/statusor_test.cc
@@ -14,6 +14,7 @@ #include "absl/status/statusor.h" +#include <any> #include <array> #include <cstddef> #include <cstdint> @@ -25,6 +26,7 @@ #include <string> #include <type_traits> #include <utility> +#include <variant> #include <vector> #include "gmock/gmock.h" @@ -35,8 +37,6 @@ #include "absl/status/status_matchers.h" #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" -#include "absl/types/any.h" -#include "absl/types/variant.h" #include "absl/utility/utility.h" namespace { @@ -696,13 +696,13 @@ TEST(StatusOr, ImplicitConstruction) { // Check implicit casting works. auto status_or = - absl::implicit_cast<absl::StatusOr<absl::variant<int, std::string>>>(10); + absl::implicit_cast<absl::StatusOr<std::variant<int, std::string>>>(10); EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10))); } TEST(StatusOr, ImplicitConstructionFromInitliazerList) { // Note: dropping the explicit std::initializer_list<int> is not supported - // by absl::StatusOr or absl::optional. + // by absl::StatusOr or std::optional. auto status_or = absl::implicit_cast<absl::StatusOr<std::vector<int>>>({{10, 20, 30}}); EXPECT_THAT(status_or, IsOkAndHolds(ElementsAre(10, 20, 30))); @@ -796,49 +796,49 @@ } TEST(StatusOr, StatusOrAnyCopyAndMoveConstructorTests) { - absl::StatusOr<absl::any> status_or = CopyDetector(10); - absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo"); + absl::StatusOr<std::any> status_or = CopyDetector(10); + absl::StatusOr<std::any> status_error = absl::InvalidArgumentError("foo"); EXPECT_THAT( status_or, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::any> a = status_or; + absl::StatusOr<std::any> a = status_or; EXPECT_THAT( a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - absl::StatusOr<absl::any> a_err = status_error; + absl::StatusOr<std::any> a_err = status_error; EXPECT_THAT(a_err, Not(IsOk())); - const absl::StatusOr<absl::any>& cref = status_or; + const absl::StatusOr<std::any>& cref = status_or; // No lint for no-change copy. - absl::StatusOr<absl::any> b = cref; // NOLINT + absl::StatusOr<std::any> b = cref; // NOLINT EXPECT_THAT( b, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::any>& cref_err = status_error; + const absl::StatusOr<std::any>& cref_err = status_error; // No lint for no-change copy. - absl::StatusOr<absl::any> b_err = cref_err; // NOLINT + absl::StatusOr<std::any> b_err = cref_err; // NOLINT EXPECT_THAT(b_err, Not(IsOk())); - absl::StatusOr<absl::any> c = std::move(status_or); + absl::StatusOr<std::any> c = std::move(status_or); EXPECT_THAT( c, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, true, false)))); - absl::StatusOr<absl::any> c_err = std::move(status_error); + absl::StatusOr<std::any> c_err = std::move(status_error); EXPECT_THAT(c_err, Not(IsOk())); } TEST(StatusOr, StatusOrAnyCopyAndMoveAssignment) { - absl::StatusOr<absl::any> status_or = CopyDetector(10); - absl::StatusOr<absl::any> status_error = absl::InvalidArgumentError("foo"); - absl::StatusOr<absl::any> a; + absl::StatusOr<std::any> status_or = CopyDetector(10); + absl::StatusOr<std::any> status_error = absl::InvalidArgumentError("foo"); + absl::StatusOr<std::any> a; a = status_or; EXPECT_THAT( a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); a = status_error; EXPECT_THAT(a, Not(IsOk())); - const absl::StatusOr<absl::any>& cref = status_or; + const absl::StatusOr<std::any>& cref = status_or; a = cref; EXPECT_THAT( a, IsOkAndHolds(AnyWith<CopyDetector>(CopyDetectorHas(10, false, true)))); - const absl::StatusOr<absl::any>& cref_err = status_error; + const absl::StatusOr<std::any>& cref_err = status_error; a = cref_err; EXPECT_THAT(a, Not(IsOk())); a = std::move(status_or); @@ -876,15 +876,15 @@ } TEST(StatusOr, AbslAnyAssignment) { - EXPECT_FALSE((std::is_assignable<absl::StatusOr<absl::any>, + EXPECT_FALSE((std::is_assignable<absl::StatusOr<std::any>, absl::StatusOr<int>>::value)); - absl::StatusOr<absl::any> status_or; + absl::StatusOr<std::any> status_or; status_or = absl::InvalidArgumentError("foo"); EXPECT_THAT(status_or, Not(IsOk())); } TEST(StatusOr, ImplicitAssignment) { - absl::StatusOr<absl::variant<int, std::string>> status_or; + absl::StatusOr<std::variant<int, std::string>> status_or; status_or = 10; EXPECT_THAT(status_or, IsOkAndHolds(VariantWith<int>(10))); }
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel index a1e5021..64e207b 100644 --- a/absl/strings/BUILD.bazel +++ b/absl/strings/BUILD.bazel
@@ -254,7 +254,6 @@ visibility = ["//visibility:private"], deps = [ ":strings", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -278,7 +277,6 @@ visibility = ["//visibility:private"], deps = [ ":has_ostream_operator", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -978,7 +976,6 @@ "//absl/log:check", "//absl/random", "//absl/types:compare", - "//absl/types:optional", "@googletest//:gtest", "@googletest//:gtest_main", ], @@ -1371,7 +1368,6 @@ "//absl/numeric:bits", "//absl/numeric:int128", "//absl/numeric:representation", - "//absl/types:optional", "//absl/types:span", "//absl/utility", ], @@ -1465,7 +1461,6 @@ "//absl/base:raw_logging_internal", "//absl/log", "//absl/numeric:int128", - "//absl/types:optional", "//absl/types:span", "@googletest//:gtest", "@googletest//:gtest_main", @@ -1535,7 +1530,6 @@ ":str_format", ":strings", "//absl/base", - "//absl/types:optional", ], )
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt index a03943d..0e0adfa 100644 --- a/absl/strings/CMakeLists.txt +++ b/absl/strings/CMakeLists.txt
@@ -231,7 +231,6 @@ COPTS ${ABSL_TEST_COPTS} DEPS - absl::optional absl::strings GTest::gmock_main ) @@ -245,7 +244,6 @@ ${ABSL_TEST_COPTS} DEPS absl::has_ostream_operator - absl::optional GTest::gmock_main ) @@ -1138,7 +1136,6 @@ absl::hash_testing absl::no_destructor absl::log - absl::optional absl::random_random absl::str_format absl::strings
diff --git a/absl/strings/atod_manual_test.cc b/absl/strings/atod_manual_test.cc index 6cf28b0..b22657a 100644 --- a/absl/strings/atod_manual_test.cc +++ b/absl/strings/atod_manual_test.cc
@@ -39,13 +39,13 @@ #include <cstdint> #include <cstdio> +#include <optional> #include <string> #include "absl/base/casts.h" #include "absl/strings/numbers.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" static constexpr uint8_t kUnhex[256] = { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // @@ -85,10 +85,10 @@ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // }; -static absl::optional<std::string> ReadFileToString(const char* filename) { +static std::optional<std::string> ReadFileToString(const char* filename) { FILE* f = fopen(filename, "rb"); if (!f) { - return absl::nullopt; + return std::nullopt; } fseek(f, 0, SEEK_END); size_t size = ftell(f); @@ -97,13 +97,13 @@ size_t n = fread(&s[0], 1, size, f); fclose(f); if (n != size) { - return absl::nullopt; + return std::nullopt; } return s; } static bool ProcessOneTestFile(const char* filename) { - absl::optional<std::string> contents = ReadFileToString(filename); + std::optional<std::string> contents = ReadFileToString(filename); if (!contents) { absl::FPrintF(stderr, "Invalid file: %s\n", filename); return false;
diff --git a/absl/strings/cord.cc b/absl/strings/cord.cc index d3014f3..aa450d3 100644 --- a/absl/strings/cord.cc +++ b/absl/strings/cord.cc
@@ -26,6 +26,7 @@ #include <iostream> #include <limits> #include <memory> +#include <optional> #include <ostream> #include <sstream> #include <string> @@ -36,8 +37,8 @@ #include "absl/base/internal/endian.h" #include "absl/base/internal/raw_logging.h" #include "absl/base/macros.h" -#include "absl/base/optimization.h" #include "absl/base/nullability.h" +#include "absl/base/optimization.h" #include "absl/container/inlined_vector.h" #include "absl/crc/crc32c.h" #include "absl/crc/internal/crc_cord_state.h" @@ -56,7 +57,6 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" #include "absl/strings/strip.h" -#include "absl/types/optional.h" #include "absl/types/span.h" namespace absl { @@ -886,9 +886,9 @@ return &contents_.tree()->crc()->crc_cord_state; } -absl::optional<uint32_t> Cord::ExpectedChecksum() const { +std::optional<uint32_t> Cord::ExpectedChecksum() const { if (!contents_.is_tree() || !contents_.tree()->IsCrc()) { - return absl::nullopt; + return std::nullopt; } return static_cast<uint32_t>( contents_.tree()->crc()->crc_cord_state.Checksum());
diff --git a/absl/strings/cord.h b/absl/strings/cord.h index fa6eb8a..3278296 100644 --- a/absl/strings/cord.h +++ b/absl/strings/cord.h
@@ -67,6 +67,7 @@ #include <cstring> #include <iosfwd> #include <iterator> +#include <optional> #include <string> #include <type_traits> #include <utility> @@ -222,7 +223,7 @@ // remain live until the releaser is invoked. The callable releaser also must: // // * be move constructible - // * support `void operator()(absl::string_view) const` or `void operator()` + // * support `void operator()(absl::string_view)` or `void operator()()` // // Example: // @@ -763,7 +764,7 @@ // // If this cord's representation is a single flat array, returns a // string_view referencing that array. Otherwise returns nullopt. - absl::optional<absl::string_view> TryFlat() const + std::optional<absl::string_view> TryFlat() const ABSL_ATTRIBUTE_LIFETIME_BOUND; // Cord::Flatten() @@ -816,11 +817,11 @@ // Returns this cord's expected checksum, if it has one. Otherwise, returns // nullopt. - absl::optional<uint32_t> ExpectedChecksum() const; + std::optional<uint32_t> ExpectedChecksum() const; template <typename H> friend H AbslHashValue(H hash_state, const absl::Cord& c) { - absl::optional<absl::string_view> maybe_flat = c.TryFlat(); + std::optional<absl::string_view> maybe_flat = c.TryFlat(); if (maybe_flat.has_value()) { return H::combine(std::move(hash_state), *maybe_flat); } @@ -1396,7 +1397,7 @@ return result; } -inline absl::optional<absl::string_view> Cord::TryFlat() const +inline std::optional<absl::string_view> Cord::TryFlat() const ABSL_ATTRIBUTE_LIFETIME_BOUND { absl::cord_internal::CordRep* rep = contents_.tree(); if (rep == nullptr) { @@ -1406,7 +1407,7 @@ if (GetFlatAux(rep, &fragment)) { return fragment; } - return absl::nullopt; + return std::nullopt; } inline absl::string_view Cord::Flatten() ABSL_ATTRIBUTE_LIFETIME_BOUND {
diff --git a/absl/strings/cord_test.cc b/absl/strings/cord_test.cc index 55007bb..0be2aa4 100644 --- a/absl/strings/cord_test.cc +++ b/absl/strings/cord_test.cc
@@ -24,6 +24,7 @@ #include <iostream> #include <iterator> #include <limits> +#include <optional> #include <random> #include <set> #include <sstream> @@ -61,7 +62,6 @@ #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" #include "absl/types/compare.h" -#include "absl/types/optional.h" // convenience local constants static constexpr auto FLAT = absl::cord_internal::FLAT; @@ -416,7 +416,7 @@ absl::Cord x(absl::string_view("hi there")); absl::Cord y(x); MaybeHarden(y); - ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt); + ASSERT_EQ(x.ExpectedChecksum(), std::nullopt); ASSERT_EQ(std::string(x), "hi there"); ASSERT_EQ(std::string(y), "hi there"); ASSERT_TRUE(x == y); @@ -618,7 +618,7 @@ std::string(sa)) << a; if (pos != 0 || end_pos != a.size()) { - ASSERT_EQ(sa.ExpectedChecksum(), absl::nullopt); + ASSERT_EQ(sa.ExpectedChecksum(), std::nullopt); } } } @@ -662,7 +662,7 @@ MaybeHarden(x); swap(x, y); if (UseCrc()) { - ASSERT_EQ(x.ExpectedChecksum(), absl::nullopt); + ASSERT_EQ(x.ExpectedChecksum(), std::nullopt); ASSERT_EQ(y.ExpectedChecksum(), 1); } ASSERT_EQ(x, absl::Cord(b)); @@ -670,7 +670,7 @@ x.swap(y); if (UseCrc()) { ASSERT_EQ(x.ExpectedChecksum(), 1); - ASSERT_EQ(y.ExpectedChecksum(), absl::nullopt); + ASSERT_EQ(y.ExpectedChecksum(), std::nullopt); } ASSERT_EQ(x, absl::Cord(a)); ASSERT_EQ(y, absl::Cord(b)); @@ -1072,7 +1072,7 @@ TEST_P(CordTest, TryFlatConcat) { absl::Cord c = absl::MakeFragmentedCord({"hel", "lo"}); MaybeHarden(c); - EXPECT_EQ(c.TryFlat(), absl::nullopt); + EXPECT_EQ(c.TryFlat(), std::nullopt); } TEST_P(CordTest, TryFlatExternal) { @@ -1766,6 +1766,34 @@ EXPECT_TRUE(invoked); } +TEST_P(CordTest, ConstructFromExternalNonConstReleaser) { + struct Releaser { + explicit Releaser(bool* invoked) : invoked(invoked) {} + // Non const method. + void operator()(absl::string_view) { *invoked = true; } + + bool* invoked; + }; + + bool invoked = false; + (void)MaybeHardened(absl::MakeCordFromExternal("dummy", Releaser(&invoked))); + EXPECT_TRUE(invoked); +} + +TEST_P(CordTest, ConstructFromExternalNonConstNoArgReleaser) { + struct Releaser { + explicit Releaser(bool* invoked) : invoked(invoked) {} + // Non const method. + void operator()() { *invoked = true; } + + bool* invoked; + }; + + bool invoked = false; + (void)MaybeHardened(absl::MakeCordFromExternal("dummy", Releaser(&invoked))); + EXPECT_TRUE(invoked); +} + TEST_P(CordTest, ConstructFromExternalNoArgLambda) { bool invoked = false; (void)MaybeHardened( @@ -3138,13 +3166,13 @@ continue; } - EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt); + EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt); if (mutator.CanUndo()) { // Undoing an operation should not restore the checksum mutator.Undo(c2); EXPECT_EQ(c2, base_value); - EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt); + EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt); } } @@ -3254,7 +3282,7 @@ // Not a mutation continue; } - EXPECT_EQ(c2.ExpectedChecksum(), absl::nullopt); + EXPECT_EQ(c2.ExpectedChecksum(), std::nullopt); if (mutator.CanUndo()) { mutator.Undo(c2);
diff --git a/absl/strings/has_absl_stringify_test.cc b/absl/strings/has_absl_stringify_test.cc index 59e7e1d..1aee904 100644 --- a/absl/strings/has_absl_stringify_test.cc +++ b/absl/strings/has_absl_stringify_test.cc
@@ -14,10 +14,10 @@ #include "absl/strings/has_absl_stringify.h" +#include <optional> #include <string> #include "gtest/gtest.h" -#include "absl/types/optional.h" namespace { @@ -34,7 +34,7 @@ EXPECT_FALSE(absl::HasAbslStringify<TypeWithoutAbslStringify>::value); EXPECT_TRUE(absl::HasAbslStringify<TypeWithAbslStringify>::value); EXPECT_FALSE( - absl::HasAbslStringify<absl::optional<TypeWithAbslStringify>>::value); + absl::HasAbslStringify<std::optional<TypeWithAbslStringify>>::value); } } // namespace
diff --git a/absl/strings/has_ostream_operator_test.cc b/absl/strings/has_ostream_operator_test.cc index 9ef4136..720ebd5 100644 --- a/absl/strings/has_ostream_operator_test.cc +++ b/absl/strings/has_ostream_operator_test.cc
@@ -14,11 +14,11 @@ #include "absl/strings/has_ostream_operator.h" +#include <optional> #include <ostream> #include <string> #include "gtest/gtest.h" -#include "absl/types/optional.h" namespace { @@ -33,7 +33,7 @@ TEST(HasOstreamOperatorTest, Works) { EXPECT_TRUE(absl::HasOstreamOperator<int>::value); EXPECT_TRUE(absl::HasOstreamOperator<std::string>::value); - EXPECT_FALSE(absl::HasOstreamOperator<absl::optional<int>>::value); + EXPECT_FALSE(absl::HasOstreamOperator<std::optional<int>>::value); EXPECT_FALSE(absl::HasOstreamOperator<TypeWithoutOstreamOp>::value); EXPECT_TRUE(absl::HasOstreamOperator<TypeWithOstreamOp>::value); }
diff --git a/absl/strings/internal/str_format/convert_test.cc b/absl/strings/internal/str_format/convert_test.cc index f340df4..fb9b5ba 100644 --- a/absl/strings/internal/str_format/convert_test.cc +++ b/absl/strings/internal/str_format/convert_test.cc
@@ -24,6 +24,7 @@ #include <cstring> #include <cwctype> #include <limits> +#include <optional> #include <set> #include <sstream> #include <string> @@ -44,7 +45,6 @@ #include "absl/strings/match.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "absl/types/span.h" namespace absl { @@ -593,11 +593,11 @@ } template <typename T> -absl::optional<std::string> StrPrintChar(T c) { +std::optional<std::string> StrPrintChar(T c) { return StrPrint("%c", static_cast<int>(c)); } template <> -absl::optional<std::string> StrPrintChar(wchar_t c) { +std::optional<std::string> StrPrintChar(wchar_t c) { // musl libc has a bug where ("%lc", 0) writes no characters, and Android // doesn't support forcing UTF-8 via setlocale(). Hardcode the expected // answers for ASCII inputs to maximize test coverage on these platforms. @@ -611,7 +611,7 @@ // call. std::string old_locale = setlocale(LC_CTYPE, nullptr); if (!setlocale(LC_CTYPE, "en_US.UTF-8")) { - return absl::nullopt; + return std::nullopt; } const std::string output = StrPrint("%lc", static_cast<wint_t>(c)); setlocale(LC_CTYPE, old_locale.c_str()); @@ -666,7 +666,7 @@ SCOPED_TRACE(Esc(c)); const FormatArgImpl args[] = {FormatArgImpl(c)}; UntypedFormatSpecImpl format("%c"); - absl::optional<std::string> result = StrPrintChar(c); + std::optional<std::string> result = StrPrintChar(c); if (result.has_value()) { EXPECT_EQ(result.value(), FormatPack(format, absl::MakeSpan(args))); }
diff --git a/absl/strings/internal/str_format/float_conversion.cc b/absl/strings/internal/str_format/float_conversion.cc index bcef275..89275d4 100644 --- a/absl/strings/internal/str_format/float_conversion.cc +++ b/absl/strings/internal/str_format/float_conversion.cc
@@ -37,7 +37,6 @@ #include "absl/strings/internal/str_format/extension.h" #include "absl/strings/numbers.h" #include "absl/strings/string_view.h" -#include "absl/types/optional.h" #include "absl/types/span.h" namespace absl {
diff --git a/absl/time/clock_interface.h b/absl/time/clock_interface.h index 25ccf6e..a14d852 100644 --- a/absl/time/clock_interface.h +++ b/absl/time/clock_interface.h
@@ -36,6 +36,8 @@ // Clocks into interfaces rather than having implementations call absl::Now() // directly. // +// Implementations of this interface must be thread-safe. +// // The Clock::GetRealClock() function returns a reference to the global realtime // clock. //
diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index cac5e4b..a52c358 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel
@@ -164,3 +164,29 @@ "@googletest//:gtest_main", ], ) + +cc_library( + name = "optional_ref", + hdrs = ["optional_ref.h"], + copts = ABSL_DEFAULT_COPTS, + linkopts = ABSL_DEFAULT_LINKOPTS, + deps = [ + "//absl/base:config", + "//absl/base:core_headers", + ], +) + +cc_test( + name = "optional_ref_test", + size = "small", + srcs = ["optional_ref_test.cc"], + copts = ABSL_TEST_COPTS, + deps = [ + ":optional_ref", + "//absl/base:config", + "//absl/log", + "//absl/strings", + "@googletest//:gtest", + "@googletest//:gtest_main", + ], +)
diff --git a/absl/types/CMakeLists.txt b/absl/types/CMakeLists.txt index 20a7e90..75dd07d 100644 --- a/absl/types/CMakeLists.txt +++ b/absl/types/CMakeLists.txt
@@ -154,6 +154,34 @@ GTest::gmock_main ) +absl_cc_library( + NAME + internal_optional_ref + HDRS + "optional_ref.h" + COPTS + ${ABSL_DEFAULT_COPTS} + DEPS + absl::config + absl::core_headers + PUBLIC +) + +absl_cc_test( + NAME + optional_ref_test + SRCS + "optional_ref_test.cc" + COPTS + ${ABSL_TEST_COPTS} + DEPS + absl::base + absl::config + absl::internal_optional_ref + absl::strings + GTest::gmock_main +) + # Deprecated empty library. # Clients should remove this dependency. absl_cc_library(
diff --git a/absl/types/optional_ref.h b/absl/types/optional_ref.h new file mode 100644 index 0000000..fb21333 --- /dev/null +++ b/absl/types/optional_ref.h
@@ -0,0 +1,294 @@ +// Copyright 2026 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 +// +// https://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. +// +// ----------------------------------------------------------------------------- +// File: optional_ref.h +// ----------------------------------------------------------------------------- +// +// `optional_ref<T>` provides a `std::optional`-like interface around `T*`. +// It is similar to C++26's `std::optional<T&>`, but with slight enhancements, +// such as the fact that it permits construction from rvalues. That is, it +// relaxes the std::reference_constructs_from_temporary constraint. Its intent +// is to make it easier for functions to accept nullable object addresses, +// regardless of whether or not they point to temporaries. +// +// It can be constructed in the following ways: +// * optional_ref<T> ref; +// * optional_ref<T> ref = std::nullopt; +// * T foo; optional_ref<T> ref = foo; +// * std::optional<T> foo; optional_ref<T> ref = foo; +// * T* foo = ...; optional_ref<T> ref = foo; +// * optional_ref<T> foo; optional_ref<const T> ref = foo; +// +// Since it is trivially copyable and destructible, it should be passed by +// value. +// +// Other properties: +// * Assignment is not allowed. Example: +// optional_ref<int> ref; +// // Compile error. +// ref = 2; +// +// * operator bool() is intentionally not defined, as it would be error prone +// for optional_ref<bool>. +// +// Example usage, assuming some type `T` that is expensive to copy: +// void ProcessT(optional_ref<const T> input) { +// if (!input.has_value()) { +// // Handle empty case. +// return; +// } +// const T& val = *input; +// // Do something with val. +// } +// +// ProcessT(std::nullopt); +// ProcessT(BuildT()); + +#ifndef ABSL_TYPES_OPTIONAL_REF_H_ +#define ABSL_TYPES_OPTIONAL_REF_H_ + +#include <cstddef> +#include <memory> +#include <optional> +#include <type_traits> +#include <utility> + +#include "absl/base/attributes.h" +#include "absl/base/config.h" +#include "absl/base/macros.h" +#include "absl/base/optimization.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN + +template <typename T> +class optional_ref { + template <typename U> + using EnableIfConvertibleFrom = + std::enable_if_t<std::is_convertible_v<U*, T*>>; + + public: + using value_type = T; + + constexpr optional_ref() : ptr_(nullptr) {} + constexpr optional_ref( // NOLINT(google-explicit-constructor) + std::nullopt_t) + : ptr_(nullptr) {} + + // Constructor given a concrete value. + constexpr optional_ref( // NOLINT(google-explicit-constructor) + T& input ABSL_ATTRIBUTE_LIFETIME_BOUND) + : ptr_(std::addressof(input)) {} + + // Constructors given an existing std::optional value. + // Templated on the input optional's type to avoid creating a temporary. + template <typename U, typename = EnableIfConvertibleFrom<const U>> + constexpr optional_ref( // NOLINT(google-explicit-constructor) + const std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND) + : ptr_(input.has_value() ? std::addressof(*input) : nullptr) {} + template <typename U, typename = EnableIfConvertibleFrom<U>> + constexpr optional_ref( // NOLINT(google-explicit-constructor) + std::optional<U>& input ABSL_ATTRIBUTE_LIFETIME_BOUND) + : ptr_(input.has_value() ? std::addressof(*input) : nullptr) {} + + // Constructor given a T*, where nullptr indicates empty/absent. + constexpr optional_ref( // NOLINT(google-explicit-constructor) + T* input ABSL_ATTRIBUTE_LIFETIME_BOUND) + : ptr_(input) {} + + // Don't allow naked nullptr as input, as this creates confusion in the case + // of optional_ref<T*>. Use std::nullopt instead to create an empty + // optional_ref. + constexpr optional_ref( // NOLINT(google-explicit-constructor) + std::nullptr_t) = delete; + + // Copying is allowed. + optional_ref(const optional_ref<T>&) = default; + // Assignment is not allowed. + optional_ref<T>& operator=(const optional_ref<T>&) = delete; + + // Conversion from optional_ref<U> is allowed iff U* is convertible to T*. + // (Note this also allows non-const to const conversions.) + template <typename U, typename = EnableIfConvertibleFrom<U>> + constexpr optional_ref( // NOLINT(google-explicit-constructor) + optional_ref<U> input) + : ptr_(input.as_pointer()) {} + + // Determines whether the `optional_ref` contains a value. Returns `false` if + // and only if `*this` is empty. + constexpr bool has_value() const { return ptr_ != nullptr; } + + // Returns a reference to an `optional_ref`s underlying value. The constness + // and lvalue/rvalue-ness of the `optional_ref` is preserved to the view of + // the `T` sub-object. Throws the same error as `std::optional`'s `value()` + // when the `optional_ref` is empty. + constexpr T& value() const { + return ABSL_PREDICT_TRUE(ptr_ != nullptr) + ? *ptr_ + // Replicate the same error logic as in `std::optional`'s + // `value()`. It either throws an exception or aborts the + // program. We intentionally ignore the return value of + // the constructed optional's value as we only need to run + // the code for error checking. + : ((void)std::optional<T>().value(), *ptr_); + } + + // Returns the value iff *this has a value, otherwise returns `default_value`. + template <typename U> + constexpr T value_or(U&& default_value) const { + // Instantiate std::optional<T>::value_or(U) to trigger its static_asserts. + if (false) { + // We use `std::add_const_t` here since just using `const` makes MSVC + // complain about the syntax. + (void)std::add_const_t<std::optional<T>>{}.value_or( + std::forward<U>(default_value)); + } + return ptr_ != nullptr ? *ptr_ + : static_cast<T>(std::forward<U>(default_value)); + } + + // Accesses the underlying `T` value of an `optional_ref`. If the + // `optional_ref` is empty, behavior is undefined. + constexpr T& operator*() const { + ABSL_HARDENING_ASSERT(ptr_ != nullptr); + return *ptr_; + } + constexpr T* operator->() const { + ABSL_HARDENING_ASSERT(ptr_ != nullptr); + return ptr_; + } + + // Convenience function to represent the `optional_ref` as a `T*` pointer. + constexpr T* as_pointer() const { return ptr_; } + // Convenience function to represent the `optional_ref` as an `optional`, + // which incurs a copy when the `optional_ref` is non-empty. The template type + // allows for implicit type conversion; example: + // optional_ref<std::string> a = ...; + // std::optional<std::string_view> b = a.as_optional<std::string_view>(); + template <typename U = std::decay_t<T>> + constexpr std::optional<U> as_optional() const { + if (ptr_ == nullptr) return std::nullopt; + return *ptr_; + } + + private: + T* const ptr_; + + // T constraint checks. You can't have an optional of nullopt_t or + // in_place_t. + static_assert(!std::is_same_v<std::nullopt_t, std::remove_cv_t<T>>, + "optional_ref<nullopt_t> is not allowed."); + static_assert(!std::is_same_v<std::in_place_t, std::remove_cv_t<T>>, + "optional_ref<in_place_t> is not allowed."); +}; + +// Template type deduction guides: + +template <typename T> +optional_ref(const T&) -> optional_ref<const T>; +template <typename T> +optional_ref(T&) -> optional_ref<T>; + +template <typename T> +optional_ref(const std::optional<T>&) -> optional_ref<const T>; +template <typename T> +optional_ref(std::optional<T>&) -> optional_ref<T>; + +template <typename T> +optional_ref(T*) -> optional_ref<T>; + +namespace optional_ref_internal { + +// This is a C++-11 compatible version of std::equality_comparable_with that +// only requires `t == u` is a valid boolean expression. +// +// We still need this for a couple reasons: +// - As of 2026-02-13, Abseil supports C++17. +// - Even for targets that are built with the default toolchain, using +// std::equality_comparable_with gives us an error due to mutual recursion +// between its definition and our definition of operator==. +// +template <typename T, typename U> +using enable_if_equality_comparable_t = std::enable_if_t<std::is_convertible_v< + decltype(std::declval<T>() == std::declval<U>()), bool>>; + +} // namespace optional_ref_internal + +// Compare an optional referenced value to std::nullopt. + +template <typename T> +constexpr bool operator==(optional_ref<T> a, std::nullopt_t) { + return !a.has_value(); +} +template <typename T> +constexpr bool operator==(std::nullopt_t, optional_ref<T> b) { + return !b.has_value(); +} +template <typename T> +constexpr bool operator!=(optional_ref<T> a, std::nullopt_t) { + return a.has_value(); +} +template <typename T> +constexpr bool operator!=(std::nullopt_t, optional_ref<T> b) { + return b.has_value(); +} + +// Compare two optional referenced values. Note, this does not test that the +// contained `ptr_`s are equal. If the caller wants "shallow" reference equality +// semantics, they should use `as_pointer()` explicitly. + +template <typename T, typename U> +constexpr bool operator==(optional_ref<T> a, optional_ref<U> b) { + return a.has_value() ? *a == b : !b.has_value(); +} + +// Compare an optional referenced value to a non-optional value. + +template < + typename T, typename U, + typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>> +constexpr bool operator==(const T& a, optional_ref<U> b) { + return b.has_value() && a == *b; +} +template < + typename T, typename U, + typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>> +constexpr bool operator==(optional_ref<T> a, const U& b) { + return b == a; +} + +// Inequality operators, as above. + +template <typename T, typename U> +constexpr bool operator!=(optional_ref<T> a, optional_ref<U> b) { + return !(a == b); +} +template < + typename T, typename U, + typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>> +constexpr bool operator!=(optional_ref<T> a, const U& b) { + return !(a == b); +} +template < + typename T, typename U, + typename = optional_ref_internal::enable_if_equality_comparable_t<T, U>> +constexpr bool operator!=(const T& a, optional_ref<U> b) { + return !(a == b); +} + +ABSL_NAMESPACE_END +} // namespace absl + +#endif // ABSL_TYPES_OPTIONAL_REF_H_
diff --git a/absl/types/optional_ref_test.cc b/absl/types/optional_ref_test.cc new file mode 100644 index 0000000..dda1624 --- /dev/null +++ b/absl/types/optional_ref_test.cc
@@ -0,0 +1,370 @@ +// Copyright 2026 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 +// +// https://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/types/optional_ref.h" + +#include <cstddef> +#include <memory> +#include <optional> +#include <string> +#include <string_view> +#include <type_traits> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/config.h" +#include "absl/log/log.h" +#include "absl/strings/str_cat.h" + +namespace absl { +ABSL_NAMESPACE_BEGIN +namespace { + +using ::testing::Optional; +using ::testing::Pointee; + +TEST(OptionalRefTest, SimpleType) { + int val = 5; + optional_ref<int> ref = optional_ref(val); + optional_ref<int> empty_ref = std::nullopt; + EXPECT_THAT(ref, Optional(5)); + EXPECT_TRUE(ref.has_value()); + EXPECT_EQ(*ref, val); + EXPECT_EQ(ref.value(), val); + EXPECT_EQ(ref, ref); + EXPECT_EQ(ref, val); + EXPECT_EQ(val, ref); + EXPECT_NE(ref, empty_ref); + EXPECT_NE(empty_ref, ref); +} + +TEST(OptionalRefTest, SimpleConstType) { + const int val = 5; + optional_ref<const int> ref = optional_ref(val); + EXPECT_THAT(ref, Optional(5)); +} + +TEST(OptionalRefTest, DefaultConstructed) { + optional_ref<int> ref; + EXPECT_EQ(ref, std::nullopt); + EXPECT_EQ(std::nullopt, ref); +} + +TEST(OptionalRefTest, EmptyOptional) { + auto ref = optional_ref<int>(std::nullopt); + EXPECT_EQ(ref, std::nullopt); + EXPECT_EQ(std::nullopt, ref); +} + +TEST(OptionalRefTest, OptionalType) { + const std::optional<int> val = 5; + optional_ref<const int> ref = val; + EXPECT_THAT(ref, Optional(5)); + EXPECT_EQ(ref.as_pointer(), &*val); + + const std::optional<int> empty; + optional_ref<const int> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); + + // Cannot make non-const reference to const optional. + static_assert( + !std::is_convertible_v<const std::optional<int>&, optional_ref<int>>); +} + +TEST(OptionalRefTest, NonConstOptionalType) { + std::optional<int> val = 5; + optional_ref<int> ref = val; + EXPECT_THAT(ref, Optional(5)); + EXPECT_EQ(ref.as_pointer(), &*val); + + std::optional<int> empty; + optional_ref<int> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); +} + +TEST(OptionalRefTest, NonConstOptionalTypeToConstRef) { + std::optional<int> val = 5; + optional_ref<const int> ref = val; + EXPECT_THAT(ref, Optional(5)); + EXPECT_EQ(ref.as_pointer(), &*val); + + std::optional<int> empty; + optional_ref<const int> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); +} + +TEST(OptionalRefTest, NonConstOptionalWithConstValueType) { + std::optional<const int> val = 5; + optional_ref<const int> ref = val; + EXPECT_THAT(ref, Optional(5)); + EXPECT_EQ(ref.as_pointer(), &*val); + + std::optional<const int> empty; + optional_ref<const int> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); + + // Not possible to convert to non-const reference. + static_assert( + !std::is_convertible_v<std::optional<const int>&, optional_ref<int>>); +} + +class TestInterface {}; +class TestDerivedClass : public TestInterface {}; + +TEST(OptionalRefTest, BaseDerivedConvertibleOptionalType) { + const std::optional<TestDerivedClass> dc = TestDerivedClass{}; + optional_ref<const TestInterface> ref = dc; + EXPECT_NE(ref, std::nullopt); + EXPECT_EQ(ref.as_pointer(), &*dc); + + const std::optional<TestDerivedClass> empty; + optional_ref<const TestInterface> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<const std::optional<TestInterface>&, + optional_ref<const TestDerivedClass>>); + static_assert(!std::is_convertible_v<const std::optional<TestDerivedClass>&, + optional_ref<TestInterface>>); +} + +TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalType) { + std::optional<TestDerivedClass> dc = TestDerivedClass{}; + optional_ref<TestInterface> ref = dc; + EXPECT_NE(ref, std::nullopt); + EXPECT_EQ(ref.as_pointer(), &*dc); + + std::optional<TestDerivedClass> empty; + optional_ref<TestInterface> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<std::optional<TestInterface>&, + optional_ref<TestDerivedClass>>); +} + +TEST(OptionalRefTest, NonConstBaseDerivedConvertibleOptionalTypeToConstRef) { + std::optional<TestDerivedClass> dc = TestDerivedClass{}; + optional_ref<const TestInterface> ref = dc; + EXPECT_NE(ref, std::nullopt); + EXPECT_EQ(ref.as_pointer(), &*dc); + + std::optional<TestDerivedClass> empty; + optional_ref<const TestInterface> empty_ref = empty; + EXPECT_EQ(empty_ref, std::nullopt); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<std::optional<TestInterface>&, + optional_ref<const TestDerivedClass>>); + static_assert(!std::is_convertible_v<const std::optional<TestInterface>&, + optional_ref<const TestDerivedClass>>); +} + +TEST(OptionalRefTest, PointerCtor) { + int val = 5; + optional_ref<const int> ref = &val; + EXPECT_THAT(ref, Optional(5)); + + auto auto_ref = optional_ref(&val); + static_assert(std::is_same_v<decltype(auto_ref), optional_ref<int>>, + "optional_ref(T*) should deduce to optional_ref<T>."); + EXPECT_THAT(auto_ref, Optional(5)); + + int* foo = nullptr; + optional_ref<const int> empty_ref = foo; + EXPECT_EQ(empty_ref, std::nullopt); + + optional_ref<int*> ptr_ref = foo; + EXPECT_THAT(ptr_ref, Optional(nullptr)); + static_assert( + !std::is_constructible_v<optional_ref<int*>, std::nullptr_t>, + "optional_ref should not be constructible with std::nullptr_t."); + + // Pointer polymorphism works. + TestDerivedClass dc; + optional_ref<const TestInterface> dc_ref = &dc; + EXPECT_NE(dc_ref, std::nullopt); +} + +TEST(OptionalRefTest, ValueDeathWhenEmpty) { + optional_ref<int> ref; +#ifdef ABSL_HAVE_EXCEPTIONS + EXPECT_THROW(ref.value(), std::bad_optional_access); +#else + EXPECT_DEATH_IF_SUPPORTED(ref.value(), ""); +#endif +} + +TEST(OptionalRefTest, ImplicitCtor) { + const int val = 5; + optional_ref<const int> ref = val; + EXPECT_THAT(ref, Optional(5)); +} + +TEST(OptionalRefTest, DoesNotCopy) { + // Non-copyable type. + auto val = std::make_unique<int>(5); + optional_ref<std::unique_ptr<int>> ref = optional_ref(val); + EXPECT_THAT(ref, Optional(Pointee(5))); +} + +TEST(OptionalRefTest, DoesNotCopyConst) { + // Non-copyable type. + const auto val = std::make_unique<int>(5); + optional_ref<const std::unique_ptr<int>> ref = optional_ref(val); + EXPECT_THAT(ref, Optional(Pointee(5))); +} + +TEST(OptionalRefTest, RefCopyable) { + auto val = std::make_unique<int>(5); + optional_ref<std::unique_ptr<int>> ref = optional_ref(val); + optional_ref<std::unique_ptr<int>> copy = ref; + EXPECT_THAT(copy, Optional(Pointee(5))); +} + +TEST(OptionalRefTest, ConstConvertible) { + auto val = std::make_unique<int>(5); + optional_ref<std::unique_ptr<int>> ref = optional_ref(val); + optional_ref<const std::unique_ptr<int>> converted = ref; + EXPECT_THAT(converted, Optional(Pointee(5))); + EXPECT_EQ(converted.as_pointer(), &val); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<optional_ref<const std::unique_ptr<int>>, + optional_ref<std::unique_ptr<int>>>); +} + +TEST(OptionalRefTest, BaseDerivedConvertible) { + TestDerivedClass dc; + optional_ref<TestDerivedClass> dc_ref = dc; + optional_ref<TestInterface> converted = dc_ref; + EXPECT_NE(converted, std::nullopt); + EXPECT_EQ(converted.as_pointer(), &dc); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<optional_ref<TestInterface>, + optional_ref<TestDerivedClass>>); +} + +TEST(OptionalRefTest, BaseDerivedConstConvertible) { + TestDerivedClass dc; + optional_ref<TestDerivedClass> dc_ref = dc; + optional_ref<const TestInterface> converted = dc_ref; + EXPECT_NE(converted, std::nullopt); + EXPECT_EQ(converted.as_pointer(), &dc); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<optional_ref<const TestInterface>, + optional_ref<TestDerivedClass>>); + static_assert(!std::is_convertible_v<optional_ref<const TestDerivedClass>, + optional_ref<TestInterface>>); +} + +TEST(OptionalRefTest, BaseDerivedBothConstConvertible) { + TestDerivedClass dc; + optional_ref<const TestDerivedClass> dc_ref = dc; + optional_ref<const TestInterface> converted = dc_ref; + EXPECT_NE(converted, std::nullopt); + EXPECT_EQ(converted.as_pointer(), &dc); + + // Not possible in the other direction. + static_assert(!std::is_convertible_v<optional_ref<const TestInterface>, + optional_ref<const TestDerivedClass>>); +} + +TEST(OptionalRefTest, TriviallyCopyable) { + static_assert( + std::is_trivially_copyable_v<optional_ref<std::unique_ptr<int>>>); +} + +TEST(OptionalRefTest, TriviallyDestructible) { + static_assert( + std::is_trivially_destructible_v<optional_ref<std::unique_ptr<int>>>); +} + +TEST(OptionalRefTest, RefNotAssignable) { + static_assert(!std::is_copy_assignable_v<optional_ref<int>>); + static_assert(!std::is_move_assignable_v<optional_ref<int>>); +} + +struct TestStructWithCopy { + TestStructWithCopy() = default; + TestStructWithCopy(TestStructWithCopy&&) { + LOG(FATAL) << "Move constructor should not be called"; + } + TestStructWithCopy(const TestStructWithCopy&) { + LOG(FATAL) << "Copy constructor should not be called"; + } + TestStructWithCopy& operator=(const TestStructWithCopy&) { + LOG(FATAL) << "Assign operator should not be called"; + } +}; + +TEST(OptionalRefTest, DoesNotCopyUsingFatalCopyAssignOps) { + TestStructWithCopy val; + optional_ref<TestStructWithCopy> ref = optional_ref(val); + EXPECT_NE(ref, std::nullopt); + EXPECT_NE(optional_ref(TestStructWithCopy{}), std::nullopt); +} + +std::string AddExclamation(optional_ref<const std::string> input) { + if (!input.has_value()) { + return ""; + } + return absl::StrCat(*input, "!"); +} + +TEST(OptionalRefTest, RefAsFunctionParameter) { + EXPECT_EQ(AddExclamation(std::nullopt), ""); + EXPECT_EQ(AddExclamation(std::string("abc")), "abc!"); + std::string s = "def"; + EXPECT_EQ(AddExclamation(s), "def!"); + EXPECT_EQ(AddExclamation(std::make_optional<std::string>(s)), "def!"); +} + +TEST(OptionalRefTest, ValueOrWhenHasValue) { + std::optional<int> val = 5; + EXPECT_EQ(optional_ref(val).value_or(2), 5); +} + +TEST(OptionalRefTest, ValueOrWhenEmpty) { + std::optional<int> val = std::nullopt; + EXPECT_EQ(optional_ref(val).value_or(2), 2); +} + +TEST(OptionalRefTest, AsOptional) { + EXPECT_EQ(optional_ref<int>().as_optional(), std::nullopt); + std::string val = "foo"; + optional_ref<const std::string> ref = val; + static_assert( + std::is_same_v<decltype(ref.as_optional()), std::optional<std::string>>, + "The type parameter of optional_ref should decay by default for the " + "return type in as_optional()."); + std::optional<std::string> opt_string = ref.as_optional(); + EXPECT_THAT(opt_string, Optional(val)); + + std::optional<std::string_view> opt_view = + ref.as_optional<std::string_view>(); + EXPECT_THAT(opt_view, Optional(val)); +} + +TEST(OptionalRefTest, Constexpr) { + static constexpr int foo = 123; + constexpr optional_ref<const int> ref(foo); + static_assert(ref.has_value() && *ref == foo && ref.value() == foo, ""); +} + +} // namespace +ABSL_NAMESPACE_END +} // namespace absl