From 87a4c07856e7dc69958019d47b2f02ae47746ec0 Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 25 Jun 2018 09:18:19 -0700 Subject: Export of internal Abseil changes. -- 8becce38c862a044db194a9aea1b505796a46d6f by Abseil Team : Updates the FixedArray's constructors to be exception safe by preventing double deletions. Also adds exception safety tests for FixedArray to document/enforce the expected behavior. PiperOrigin-RevId: 201964431 -- 794188b401a602b4be97190fb8738066fe1f9ca5 by Derek Mauro : Fixes for str_format.h documentation. PiperOrigin-RevId: 201951760 -- beae3bdd6eee2cf61101102fddc35ada188f330b by Alex Strelnikov : Add numeric_limits specialization for uint128. Turns out numeric_limits is a case where the consensus is that it is okay to specialize for a user defined type. PiperOrigin-RevId: 201944736 -- b2b3444a52b36878ade1ae8801e69932b05fc4f9 by Shaindel Schwartz : Internal change. PiperOrigin-RevId: 201718662 -- aa924c459922f39caabfc193998c58d0f4981ac0 by Abseil Team : Typo fix. PiperOrigin-RevId: 201692176 -- bbfcaa7b1af331d9b97c92470608240c5c864fbc by Xiaoyi Zhang : Use ABSL_HAVE_ANY/OPTIONAL/VARIANT to conditionally compile out the definition of absl::bad_any_cast, absl::bad_optional_access, absl::bad_variant_access. This would fix the issues where users #include those header directly in C++17 modes. PiperOrigin-RevId: 201683792 GitOrigin-RevId: 8becce38c862a044db194a9aea1b505796a46d6f Change-Id: I60a7ad043136a439d82c374d225a1804016b0509 --- absl/algorithm/container.h | 2 +- absl/base/thread_annotations.h | 1 - absl/container/BUILD.bazel | 11 ++ absl/container/CMakeLists.txt | 19 ++++ absl/container/fixed_array.h | 52 ++++----- .../container/fixed_array_exception_safety_test.cc | 117 +++++++++++++++++++++ absl/memory/memory.h | 33 ++++++ absl/memory/memory_exception_safety_test.cc | 18 +++- absl/memory/memory_test.cc | 43 ++++++++ absl/numeric/int128.cc | 26 +++++ absl/numeric/int128.h | 58 +++++++++- absl/numeric/int128_test.cc | 11 ++ absl/strings/str_format.h | 20 ++-- absl/types/BUILD.bazel | 5 +- absl/types/bad_any_cast.cc | 4 + absl/types/bad_any_cast.h | 14 +++ absl/types/bad_optional_access.cc | 4 + absl/types/bad_optional_access.h | 14 +++ absl/types/bad_variant_access.cc | 4 + absl/types/bad_variant_access.h | 14 +++ 20 files changed, 422 insertions(+), 48 deletions(-) create mode 100644 absl/container/fixed_array_exception_safety_test.cc diff --git a/absl/algorithm/container.h b/absl/algorithm/container.h index ebe32445..acddec48 100644 --- a/absl/algorithm/container.h +++ b/absl/algorithm/container.h @@ -634,7 +634,7 @@ container_algorithm_internal::ContainerIter c_generate_n(C& c, Size n, // Note: `c_xx()` container versions for `remove()`, `remove_if()`, // and `unique()` are omitted, because it's not clear whether or not such -// functions should call erase their supplied sequences afterwards. Either +// functions should call erase on their supplied sequences afterwards. Either // behavior would be surprising for a different set of users. // diff --git a/absl/base/thread_annotations.h b/absl/base/thread_annotations.h index 8d30b932..fbb2797b 100644 --- a/absl/base/thread_annotations.h +++ b/absl/base/thread_annotations.h @@ -31,7 +31,6 @@ // that evaluate to a concrete mutex object whenever possible. If the mutex // you want to refer to is not in scope, you may use a member pointer // (e.g. &MyClass::mutex_) to refer to a mutex in some (unknown) object. -// #ifndef ABSL_BASE_THREAD_ANNOTATIONS_H_ #define ABSL_BASE_THREAD_ANNOTATIONS_H_ diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel index 119d5c88..07df3675 100644 --- a/absl/container/BUILD.bazel +++ b/absl/container/BUILD.bazel @@ -62,6 +62,17 @@ cc_test( ], ) +cc_test( + name = "fixed_array_exception_safety_test", + srcs = ["fixed_array_exception_safety_test.cc"], + copts = ABSL_TEST_COPTS + ABSL_EXCEPTIONS_FLAG, + deps = [ + ":fixed_array", + "//absl/base:exception_safety_testing", + "@com_google_googletest//:gtest_main", + ], +) + cc_test( name = "fixed_array_benchmark", srcs = ["fixed_array_benchmark.cc"], diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt index f56ce92d..d580b489 100644 --- a/absl/container/CMakeLists.txt +++ b/absl/container/CMakeLists.txt @@ -84,6 +84,25 @@ absl_test( ) +# test fixed_array_exception_safety_test +set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC "fixed_array_exception_safety_test.cc") +set(FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES + absl::container + absl_base_internal_exception_safety_testing +) + +absl_test( + TARGET + fixed_array_exception_safety_test + SOURCES + ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_SRC} + PUBLIC_LIBRARIES + ${FIXED_ARRAY_EXCEPTION_SAFETY_TEST_PUBLIC_LIBRARIES} + PRIVATE_COMPILE_FLAGS + ${ABSL_EXCEPTIONS_FLAG} +) + + # test inlined_vector_test set(INLINED_VECTOR_TEST_SRC "inlined_vector_test.cc") set(INLINED_VECTOR_TEST_PUBLIC_LIBRARIES absl::base absl_throw_delegate test_instance_tracker_lib) diff --git a/absl/container/fixed_array.h b/absl/container/fixed_array.h index 06bc8009..295f0108 100644 --- a/absl/container/fixed_array.h +++ b/absl/container/fixed_array.h @@ -108,33 +108,46 @@ class FixedArray { ? kInlineBytesDefault / sizeof(value_type) : inlined; - FixedArray(const FixedArray& other) : rep_(other.begin(), other.end()) {} + FixedArray(const FixedArray& other) + : FixedArray(other.begin(), other.end()) {} + FixedArray(FixedArray&& other) noexcept( // clang-format off absl::allocator_is_nothrow>::value && // clang-format on std::is_nothrow_move_constructible::value) - : rep_(std::make_move_iterator(other.begin()), - std::make_move_iterator(other.end())) {} + : FixedArray(std::make_move_iterator(other.begin()), + std::make_move_iterator(other.end())) {} // Creates an array object that can store `n` elements. // Note that trivially constructible elements will be uninitialized. - explicit FixedArray(size_type n) : rep_(n) {} + explicit FixedArray(size_type n) : rep_(n) { + absl::memory_internal::uninitialized_default_construct_n(rep_.begin(), + size()); + } // Creates an array initialized with `n` copies of `val`. - FixedArray(size_type n, const value_type& val) : rep_(n, val) {} + FixedArray(size_type n, const value_type& val) : rep_(n) { + std::uninitialized_fill_n(data(), size(), val); + } // Creates an array initialized with the elements from the input // range. The array's size will always be `std::distance(first, last)`. // REQUIRES: Iter must be a forward_iterator or better. template = 0> - FixedArray(Iter first, Iter last) : rep_(first, last) {} + FixedArray(Iter first, Iter last) : rep_(std::distance(first, last)) { + std::uninitialized_copy(first, last, data()); + } // Creates the array from an initializer_list. FixedArray(std::initializer_list init_list) : FixedArray(init_list.begin(), init_list.end()) {} - ~FixedArray() {} + ~FixedArray() noexcept { + for (Holder* cur = rep_.begin(); cur != rep_.end(); ++cur) { + cur->~Holder(); + } + } // Assignments are deleted because they break the invariant that the size of a // `FixedArray` never changes. @@ -431,32 +444,13 @@ class FixedArray { // Rep // - // A const Rep object holds FixedArray's size and data pointer. + // An instance of Rep manages the inline and out-of-line memory for FixedArray // class Rep : public InlineSpace { public: - Rep(size_type n, const value_type& val) : n_(n), p_(MakeHolder(n)) { - std::uninitialized_fill_n(p_, n, val); - } - - explicit Rep(size_type n) : n_(n), p_(MakeHolder(n)) { - // Loop optimizes to nothing for trivially constructible T. - for (Holder* p = p_; p != p_ + n; ++p) - // Note: no parens: default init only. - // Also note '::' to avoid Holder class placement new operator. - ::new (static_cast(p)) Holder; - } - - template - Rep(Iter first, Iter last) - : n_(std::distance(first, last)), p_(MakeHolder(n_)) { - std::uninitialized_copy(first, last, AsValue(p_)); - } + explicit Rep(size_type n) : n_(n), p_(MakeHolder(n)) {} - ~Rep() { - // Destruction must be in reverse order. - // Loop optimizes to nothing for trivially destructible T. - for (Holder* p = end(); p != begin();) (--p)->~Holder(); + ~Rep() noexcept { if (IsAllocated(size())) { std::allocator().deallocate(p_, n_); } else { diff --git a/absl/container/fixed_array_exception_safety_test.cc b/absl/container/fixed_array_exception_safety_test.cc new file mode 100644 index 00000000..c123c2a1 --- /dev/null +++ b/absl/container/fixed_array_exception_safety_test.cc @@ -0,0 +1,117 @@ +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "absl/container/fixed_array.h" + +#include "gtest/gtest.h" +#include "absl/base/internal/exception_safety_testing.h" + +namespace absl { + +namespace { + +constexpr size_t kInlined = 25; +constexpr size_t kSmallSize = kInlined / 2; +constexpr size_t kLargeSize = kInlined * 2; + +constexpr int kInitialValue = 5; +constexpr int kUpdatedValue = 10; + +using ::testing::TestThrowingCtor; + +using Thrower = testing::ThrowingValue; +using FixedArr = absl::FixedArray; + +using MoveThrower = testing::ThrowingValue; +using MoveFixedArr = absl::FixedArray; + +TEST(FixedArrayExceptionSafety, CopyConstructor) { + auto small = FixedArr(kSmallSize); + TestThrowingCtor(small); + + auto large = FixedArr(kLargeSize); + TestThrowingCtor(large); +} + +TEST(FixedArrayExceptionSafety, MoveConstructor) { + TestThrowingCtor(FixedArr(kSmallSize)); + TestThrowingCtor(FixedArr(kLargeSize)); + + // TypeSpec::kNoThrowMove + TestThrowingCtor(MoveFixedArr(kSmallSize)); + TestThrowingCtor(MoveFixedArr(kLargeSize)); +} + +TEST(FixedArrayExceptionSafety, SizeConstructor) { + TestThrowingCtor(kSmallSize); + TestThrowingCtor(kLargeSize); +} + +TEST(FixedArrayExceptionSafety, SizeValueConstructor) { + TestThrowingCtor(kSmallSize, Thrower()); + TestThrowingCtor(kLargeSize, Thrower()); +} + +TEST(FixedArrayExceptionSafety, IteratorConstructor) { + auto small = FixedArr(kSmallSize); + TestThrowingCtor(small.begin(), small.end()); + + auto large = FixedArr(kLargeSize); + TestThrowingCtor(large.begin(), large.end()); +} + +TEST(FixedArrayExceptionSafety, InitListConstructor) { + constexpr int small_inlined = 3; + using SmallFixedArr = absl::FixedArray; + + TestThrowingCtor(std::initializer_list{}); + // Test inlined allocation + TestThrowingCtor( + std::initializer_list{Thrower{}, Thrower{}}); + // Test out of line allocation + TestThrowingCtor(std::initializer_list{ + Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}}); +} + +testing::AssertionResult ReadMemory(FixedArr* fixed_arr) { + // Marked volatile to prevent optimization. Used for running asan tests. + volatile int sum = 0; + for (const auto& thrower : *fixed_arr) { + sum += thrower.Get(); + } + return testing::AssertionSuccess() << "Values sum to [" << sum << "]"; +} + +TEST(FixedArrayExceptionSafety, Fill) { + auto test_fill = testing::MakeExceptionSafetyTester() + .WithInvariants(ReadMemory) + .WithOperation([&](FixedArr* fixed_arr_ptr) { + auto thrower = + Thrower(kUpdatedValue, testing::nothrow_ctor); + fixed_arr_ptr->fill(thrower); + }); + + EXPECT_TRUE( + test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue))) + .Test()); + EXPECT_TRUE( + test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue))) + .Test()); +} + +} // namespace + +} // namespace absl diff --git a/absl/memory/memory.h b/absl/memory/memory.h index cd818cff..c43e1566 100644 --- a/absl/memory/memory.h +++ b/absl/memory/memory.h @@ -636,6 +636,39 @@ struct default_allocator_is_nothrow : std::true_type {}; struct default_allocator_is_nothrow : std::false_type {}; #endif +namespace memory_internal { +// TODO(b110200014): Implement proper backports +template +void DefaultConstruct(ForwardIt it) { + using value_type = typename std::iterator_traits::value_type; + ::new (static_cast(std::addressof(*it))) value_type; +} // namespace memory_internal + +#ifdef ABSL_HAVE_EXCEPTIONS +template +void uninitialized_default_construct_n(ForwardIt first, Size size) { + for (ForwardIt cur = first; size > 0; static_cast(++cur), --size) { + try { + absl::memory_internal::DefaultConstruct(cur); + } catch (...) { + using value_type = typename std::iterator_traits::value_type; + for (; first != cur; ++first) { + first->~value_type(); + } + throw; + } + } +} +#else // ABSL_HAVE_EXCEPTIONS +template +void uninitialized_default_construct_n(ForwardIt first, Size size) { + for (; size > 0; static_cast(++first), --size) { + absl::memory_internal::DefaultConstruct(first); + } +} +#endif // ABSL_HAVE_EXCEPTIONS +} // namespace memory_internal + } // namespace absl #endif // ABSL_MEMORY_MEMORY_H_ diff --git a/absl/memory/memory_exception_safety_test.cc b/absl/memory/memory_exception_safety_test.cc index 55e8f36f..fb8b561d 100644 --- a/absl/memory/memory_exception_safety_test.cc +++ b/absl/memory/memory_exception_safety_test.cc @@ -20,11 +20,14 @@ namespace absl { namespace { -using Thrower = ::testing::ThrowingValue<>; +constexpr int kLength = 50; +using Thrower = testing::ThrowingValue; +using ThrowerStorage = + absl::aligned_storage_t; +using ThrowerList = std::array; TEST(MakeUnique, CheckForLeaks) { constexpr int kValue = 321; - constexpr size_t kLength = 10; auto tester = testing::MakeExceptionSafetyTester() .WithInitialValue(Thrower(kValue)) // Ensures make_unique does not modify the input. The real @@ -45,5 +48,16 @@ TEST(MakeUnique, CheckForLeaks) { })); } +TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) { + EXPECT_TRUE(testing::MakeExceptionSafetyTester() + .WithInitialValue(ThrowerList{}) + .WithOperation([&](ThrowerList* list_ptr) { + absl::memory_internal::uninitialized_default_construct_n( + list_ptr->data(), kLength); + }) + .WithInvariants([&](...) { return true; }) + .Test()); +} + } // namespace } // namespace absl diff --git a/absl/memory/memory_test.cc b/absl/memory/memory_test.cc index dee9b486..8ff1945d 100644 --- a/absl/memory/memory_test.cc +++ b/absl/memory/memory_test.cc @@ -611,4 +611,47 @@ TEST(AllocatorNoThrowTest, CustomAllocator) { EXPECT_FALSE(absl::allocator_is_nothrow::value); } +TEST(MemoryInternal, UninitDefaultConstructNTrivial) { + constexpr int kInitialValue = 123; + constexpr int kExpectedValue = kInitialValue; // Expect no-op behavior + constexpr int len = 5; + + struct TestObj { + int val; + }; + static_assert(absl::is_trivially_default_constructible::value, ""); + static_assert(absl::is_trivially_destructible::value, ""); + + TestObj objs[len]; + for (auto& obj : objs) { + obj.val = kInitialValue; + } + + absl::memory_internal::uninitialized_default_construct_n(objs, len); + for (auto& obj : objs) { + EXPECT_EQ(obj.val, kExpectedValue); + } +} + +TEST(MemoryInternal, UninitDefaultConstructNNonTrivial) { + constexpr int kInitialValue = 123; + constexpr int kExpectedValue = 0; // Expect value-construction behavior + constexpr int len = 5; + + struct TestObj { + int val{kExpectedValue}; + }; + static_assert(absl::is_trivially_destructible::value, ""); + + TestObj objs[len]; + for (auto& obj : objs) { + obj.val = kInitialValue; + } + + absl::memory_internal::uninitialized_default_construct_n(objs, len); + for (auto& obj : objs) { + EXPECT_EQ(obj.val, kExpectedValue); + } +} + } // namespace diff --git a/absl/numeric/int128.cc b/absl/numeric/int128.cc index 3688e5ef..cd79534f 100644 --- a/absl/numeric/int128.cc +++ b/absl/numeric/int128.cc @@ -223,3 +223,29 @@ std::ostream& operator<<(std::ostream& os, uint128 v) { } } // namespace absl + +namespace std { +constexpr bool numeric_limits::is_specialized; +constexpr bool numeric_limits::is_signed; +constexpr bool numeric_limits::is_integer; +constexpr bool numeric_limits::is_exact; +constexpr bool numeric_limits::has_infinity; +constexpr bool numeric_limits::has_quiet_NaN; +constexpr bool numeric_limits::has_signaling_NaN; +constexpr float_denorm_style numeric_limits::has_denorm; +constexpr bool numeric_limits::has_denorm_loss; +constexpr float_round_style numeric_limits::round_style; +constexpr bool numeric_limits::is_iec559; +constexpr bool numeric_limits::is_bounded; +constexpr bool numeric_limits::is_modulo; +constexpr int numeric_limits::digits; +constexpr int numeric_limits::digits10; +constexpr int numeric_limits::max_digits10; +constexpr int numeric_limits::radix; +constexpr int numeric_limits::min_exponent; +constexpr int numeric_limits::min_exponent10; +constexpr int numeric_limits::max_exponent; +constexpr int numeric_limits::max_exponent10; +constexpr bool numeric_limits::traps; +constexpr bool numeric_limits::tinyness_before; +} // namespace std diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h index bc7dbb47..e4f39c30 100644 --- a/absl/numeric/int128.h +++ b/absl/numeric/int128.h @@ -219,21 +219,69 @@ std::ostream& operator<<(std::ostream& os, uint128 v); // TODO(strel) add operator>>(std::istream&, uint128) +constexpr uint128 Uint128Max() { + return uint128(std::numeric_limits::max(), + std::numeric_limits::max()); +} + +} // namespace absl + +// Specialized numeric_limits for uint128. +namespace std { +template <> +class numeric_limits { + public: + static constexpr bool is_specialized = true; + static constexpr bool is_signed = false; + static constexpr bool is_integer = true; + static constexpr bool is_exact = true; + static constexpr bool has_infinity = false; + static constexpr bool has_quiet_NaN = false; + static constexpr bool has_signaling_NaN = false; + static constexpr float_denorm_style has_denorm = denorm_absent; + static constexpr bool has_denorm_loss = false; + static constexpr float_round_style round_style = round_toward_zero; + static constexpr bool is_iec559 = false; + static constexpr bool is_bounded = true; + static constexpr bool is_modulo = true; + static constexpr int digits = 128; + static constexpr int digits10 = 38; + static constexpr int max_digits10 = 0; + static constexpr int radix = 2; + static constexpr int min_exponent = 0; + static constexpr int min_exponent10 = 0; + static constexpr int max_exponent = 0; + static constexpr int max_exponent10 = 0; +#ifdef ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits::traps; +#else // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool traps = numeric_limits::traps; +#endif // ABSL_HAVE_INTRINSIC_INT128 + static constexpr bool tinyness_before = false; + + static constexpr absl::uint128 min() { return 0; } + static constexpr absl::uint128 lowest() { return 0; } + static constexpr absl::uint128 max() { return absl::Uint128Max(); } + static constexpr absl::uint128 epsilon() { return 0; } + static constexpr absl::uint128 round_error() { return 0; } + static constexpr absl::uint128 infinity() { return 0; } + static constexpr absl::uint128 quiet_NaN() { return 0; } + static constexpr absl::uint128 signaling_NaN() { return 0; } + static constexpr absl::uint128 denorm_min() { return 0; } +}; +} // namespace std + // TODO(absl-team): Implement signed 128-bit type // -------------------------------------------------------------------------- // Implementation details follow // -------------------------------------------------------------------------- +namespace absl { constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { return uint128(high, low); } -constexpr uint128 Uint128Max() { - return uint128(std::numeric_limits::max(), - std::numeric_limits::max()); -} - // Assignment from integer types. inline uint128& uint128::operator=(int v) { return *this = uint128(v); } diff --git a/absl/numeric/int128_test.cc b/absl/numeric/int128_test.cc index 79bcca90..1eb3e0ec 100644 --- a/absl/numeric/int128_test.cc +++ b/absl/numeric/int128_test.cc @@ -428,4 +428,15 @@ TEST(Uint128, ConstexprTest) { EXPECT_EQ(minus_two, absl::MakeUint128(-1, -2)); } +TEST(Uint128, NumericLimitsTest) { + static_assert(std::numeric_limits::is_specialized, ""); + static_assert(!std::numeric_limits::is_signed, ""); + static_assert(std::numeric_limits::is_integer, ""); + EXPECT_EQ(static_cast(128 * std::log10(2)), + std::numeric_limits::digits10); + EXPECT_EQ(0, std::numeric_limits::min()); + EXPECT_EQ(0, std::numeric_limits::lowest()); + EXPECT_EQ(absl::Uint128Max(), std::numeric_limits::max()); +} + } // namespace diff --git a/absl/strings/str_format.h b/absl/strings/str_format.h index 98e0fef4..a3fb89c7 100644 --- a/absl/strings/str_format.h +++ b/absl/strings/str_format.h @@ -344,13 +344,13 @@ ABSL_MUST_USE_RESULT str_format_internal::Streamable StreamFormat( // PrintF() // // Writes to stdout given a format std::string and zero or more arguments. This -// function is functionally equivalent to `std::print()` (and type-safe); prefer -// `absl::PrintF()` over `std::printf()`. +// function is functionally equivalent to `std::printf()` (and type-safe); +// prefer `absl::PrintF()` over `std::printf()`. // // Example: // // std::string_view s = "Ulaanbaatar"; -// absl::PrintF("The capital of Mongolia is: %s \n", s); +// absl::PrintF("The capital of Mongolia is %s", s); // // Outputs: "The capital of Mongolia is Ulaanbaatar" // @@ -364,13 +364,13 @@ int PrintF(const FormatSpec& format, const Args&... args) { // FPrintF() // // Writes to a file given a format std::string and zero or more arguments. This -// function is functionally equivalent to `std::fprint()` (and type-safe); +// function is functionally equivalent to `std::fprintf()` (and type-safe); // prefer `absl::FPrintF()` over `std::fprintf()`. // // Example: // // std::string_view s = "Ulaanbaatar"; -// absl::FPrintF("The capital of Mongolia is: %s \n", s); +// absl::FPrintF("The capital of Mongolia is %s", s); // // Outputs: "The capital of Mongolia is Ulaanbaatar" // @@ -385,15 +385,17 @@ int FPrintF(std::FILE* output, const FormatSpec& format, // SNPrintF() // // Writes to a sized buffer given a format std::string and zero or more arguments. -// This function is functionally equivalent to `std::snprint()` (and type-safe); -// prefer `absl::SNPrintF()` over `std::snprintf()`. +// This function is functionally equivalent to `std::snprintf()` (and +// type-safe); prefer `absl::SNPrintF()` over `std::snprintf()`. // // Example: // // std::string_view s = "Ulaanbaatar"; -// absl::FPrintF("The capital of Mongolia is: %s \n", s); +// char output[128]; +// absl::SNPrintF(output, sizeof(output), +// "The capital of Mongolia is %s", s); // -// Outputs: "The capital of Mongolia is Ulaanbaatar" +// Post-condition: output == "The capital of Mongolia is Ulaanbaatar" // template int SNPrintF(char* output, std::size_t size, const FormatSpec& format, diff --git a/absl/types/BUILD.bazel b/absl/types/BUILD.bazel index c50ec425..10f6c4d2 100644 --- a/absl/types/BUILD.bazel +++ b/absl/types/BUILD.bazel @@ -42,7 +42,10 @@ cc_library( name = "bad_any_cast", hdrs = ["bad_any_cast.h"], copts = ABSL_DEFAULT_COPTS, - deps = [":bad_any_cast_impl"], + deps = [ + ":bad_any_cast_impl", + "//absl/base:config", + ], ) cc_library( diff --git a/absl/types/bad_any_cast.cc b/absl/types/bad_any_cast.cc index c9b73300..2e2fd29a 100644 --- a/absl/types/bad_any_cast.cc +++ b/absl/types/bad_any_cast.cc @@ -14,6 +14,8 @@ #include "absl/types/bad_any_cast.h" +#ifndef ABSL_HAVE_STD_ANY + #include #include "absl/base/config.h" @@ -38,3 +40,5 @@ void ThrowBadAnyCast() { } // namespace any_internal } // namespace absl + +#endif // ABSL_HAVE_STD_ANY diff --git a/absl/types/bad_any_cast.h b/absl/types/bad_any_cast.h index 3b963077..60390132 100644 --- a/absl/types/bad_any_cast.h +++ b/absl/types/bad_any_cast.h @@ -23,6 +23,18 @@ #include +#include "absl/base/config.h" + +#ifdef ABSL_HAVE_STD_ANY + +#include + +namespace absl { +using std::bad_any_cast; +} // namespace absl + +#else // ABSL_HAVE_STD_ANY + namespace absl { // ----------------------------------------------------------------------------- @@ -54,4 +66,6 @@ namespace any_internal { } // namespace any_internal } // namespace absl +#endif // ABSL_HAVE_STD_ANY + #endif // ABSL_TYPES_BAD_ANY_CAST_H_ diff --git a/absl/types/bad_optional_access.cc b/absl/types/bad_optional_access.cc index 6bc67df7..55870776 100644 --- a/absl/types/bad_optional_access.cc +++ b/absl/types/bad_optional_access.cc @@ -14,6 +14,8 @@ #include "absl/types/bad_optional_access.h" +#ifndef ABSL_HAVE_STD_OPTIONAL + #include #include "absl/base/config.h" @@ -40,3 +42,5 @@ void throw_bad_optional_access() { } // namespace optional_internal } // namespace absl + +#endif // ABSL_HAVE_STD_OPTIONAL diff --git a/absl/types/bad_optional_access.h b/absl/types/bad_optional_access.h index e9aa8b83..c6c27460 100644 --- a/absl/types/bad_optional_access.h +++ b/absl/types/bad_optional_access.h @@ -23,6 +23,18 @@ #include +#include "absl/base/config.h" + +#ifdef ABSL_HAVE_STD_OPTIONAL + +#include + +namespace absl { +using std::bad_optional_access; +} // namespace absl + +#else // ABSL_HAVE_STD_OPTIONAL + namespace absl { // ----------------------------------------------------------------------------- @@ -57,4 +69,6 @@ namespace optional_internal { } // namespace optional_internal } // namespace absl +#endif // ABSL_HAVE_STD_OPTIONAL + #endif // ABSL_TYPES_BAD_OPTIONAL_ACCESS_H_ diff --git a/absl/types/bad_variant_access.cc b/absl/types/bad_variant_access.cc index 817fd789..d27d7756 100644 --- a/absl/types/bad_variant_access.cc +++ b/absl/types/bad_variant_access.cc @@ -14,6 +14,8 @@ #include "absl/types/bad_variant_access.h" +#ifndef ABSL_HAVE_STD_VARIANT + #include #include @@ -56,3 +58,5 @@ void Rethrow() { } // namespace variant_internal } // namespace absl + +#endif // ABSL_HAVE_STD_VARIANT diff --git a/absl/types/bad_variant_access.h b/absl/types/bad_variant_access.h index 67abe713..e7355a5a 100644 --- a/absl/types/bad_variant_access.h +++ b/absl/types/bad_variant_access.h @@ -23,6 +23,18 @@ #include +#include "absl/base/config.h" + +#ifdef ABSL_HAVE_STD_VARIANT + +#include + +namespace absl { +using std::bad_variant_access; +} // namespace absl + +#else // ABSL_HAVE_STD_VARIANT + namespace absl { // ----------------------------------------------------------------------------- @@ -61,4 +73,6 @@ namespace variant_internal { } // namespace variant_internal } // namespace absl +#endif // ABSL_HAVE_STD_VARIANT + #endif // ABSL_TYPES_BAD_VARIANT_ACCESS_H_ -- cgit v1.2.3