From 9613678332c976568272c8f4a78631a29159271d Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Mon, 30 Apr 2018 11:44:26 -0700 Subject: - 60c1f40a5e0bc33f93392ff6827528072d749a29 Move ExceptionSafetyTester from the absl:: namespace to t... by Abseil Team - abd40a98f8ae746eb151e777ea8a8b5223d68a4b Splits the NoThrow flags into TypeSpec and AllocSpec flag... by Abseil Team - c16d0b5509b36679b384147b474135e7951afccf Change the abbreviation for the breakdowns of InfinitePas... by Abseil Team - 8ac104351764f23d666b52dce7536a34c05abf00 Use ABSL_CONST_INIT with std::atomic variables in static ... by Matt Armstrong GitOrigin-RevId: 60c1f40a5e0bc33f93392ff6827528072d749a29 Change-Id: I9d45a6ed30ed32ae57e9eff93f4205dbcd71feb2 --- absl/base/internal/exception_safety_testing.cc | 6 +- absl/base/internal/exception_safety_testing.h | 214 +++++++++++++++---------- 2 files changed, 130 insertions(+), 90 deletions(-) (limited to 'absl/base/internal') diff --git a/absl/base/internal/exception_safety_testing.cc b/absl/base/internal/exception_safety_testing.cc index c6f7c7cf..c92d07bc 100644 --- a/absl/base/internal/exception_safety_testing.cc +++ b/absl/base/internal/exception_safety_testing.cc @@ -17,7 +17,7 @@ #include "gtest/gtest.h" #include "absl/meta/type_traits.h" -namespace absl { +namespace testing { exceptions_internal::NoThrowTag no_throw_ctor; exceptions_internal::StrongGuaranteeTagType strong_guarantee; @@ -37,5 +37,7 @@ testing::AssertionResult FailureMessage(const TestException& e, int countdown) noexcept { return testing::AssertionFailure() << "Exception thrown from " << e.what(); } + } // namespace exceptions_internal -} // namespace absl + +} // namespace testing diff --git a/absl/base/internal/exception_safety_testing.h b/absl/base/internal/exception_safety_testing.h index c014fb30..32450465 100644 --- a/absl/base/internal/exception_safety_testing.h +++ b/absl/base/internal/exception_safety_testing.h @@ -35,38 +35,36 @@ #include "absl/strings/substitute.h" #include "absl/types/optional.h" -namespace absl { - -// A configuration enum for Throwing*. Operations whose flags are set will -// throw, everything else won't. This isn't meant to be exhaustive, more flags -// can always be made in the future. -enum class NoThrow : uint8_t { - kNone = 0, - kMoveCtor = 1, - kMoveAssign = 1 << 1, - kAllocation = 1 << 2, - kIntCtor = 1 << 3, - kNoThrow = static_cast(-1) -}; +namespace testing { + +enum class TypeSpec; +enum class AllocSpec; + +constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); +} + +constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) & static_cast(b)); +} -constexpr NoThrow operator|(NoThrow a, NoThrow b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) | static_cast(b)); +constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); } -constexpr NoThrow operator&(NoThrow a, NoThrow b) { - using T = absl::underlying_type_t; - return static_cast(static_cast(a) & static_cast(b)); +constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) { + using T = absl::underlying_type_t; + return static_cast(static_cast(a) & static_cast(b)); } namespace exceptions_internal { + struct NoThrowTag {}; struct StrongGuaranteeTagType {}; -constexpr bool ThrowingAllowed(NoThrow flags, NoThrow flag) { - return !static_cast(flags & flag); -} - // A simple exception class. We throw this so that test code can catch // exceptions specifically thrown by ThrowingValue. class TestException { @@ -246,47 +244,69 @@ class ThrowingBool { bool b_; }; -// A testing class instrumented to throw an exception at a controlled time. -// -// ThrowingValue implements a slightly relaxed version of the Regular concept -- -// that is it's a value type with the expected semantics. It also implements -// arithmetic operations. It doesn't implement member and pointer operators -// like operator-> or operator[]. -// -// ThrowingValue can be instrumented to have certain operations be noexcept by -// using compile-time bitfield flag template arguments. That is, to make an -// ThrowingValue which has a noexcept move constructor and noexcept move -// assignment, use -// ThrowingValue. -template +/* + * Configuration enum for the ThrowingValue type that defines behavior for the + * lifetime of the instance. Use testing::no_throw_ctor to prevent the integer + * constructor from throwing. + * + * kEverythingThrows: Every operation can throw an exception + * kNoThrowCopy: Copy construction and copy assignment will not throw + * kNoThrowMove: Move construction and move assignment will not throw + * kNoThrowNew: Overloaded operators new and new[] will not throw + */ +enum class TypeSpec { + kEverythingThrows = 0, + kNoThrowCopy = 1, + kNoThrowMove = 1 << 1, + kNoThrowNew = 1 << 2, +}; + +/* + * A testing class instrumented to throw an exception at a controlled time. + * + * ThrowingValue implements a slightly relaxed version of the Regular concept -- + * that is it's a value type with the expected semantics. It also implements + * arithmetic operations. It doesn't implement member and pointer operators + * like operator-> or operator[]. + * + * ThrowingValue can be instrumented to have certain operations be noexcept by + * using compile-time bitfield template arguments. That is, to make an + * ThrowingValue which has noexcept move construction/assignment and noexcept + * copy construction/assignment, use the following: + * ThrowingValue my_thrwr{val}; + */ +template class ThrowingValue : private exceptions_internal::TrackedObject { + constexpr static bool IsSpecified(TypeSpec spec) { + return static_cast(Spec & spec); + } + public: ThrowingValue() : TrackedObject(ABSL_PRETTY_FUNCTION) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); dummy_ = 0; } - ThrowingValue(const ThrowingValue& other) + ThrowingValue(const ThrowingValue& other) noexcept( + IsSpecified(TypeSpec::kNoThrowCopy)) : TrackedObject(ABSL_PRETTY_FUNCTION) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + if (!IsSpecified(TypeSpec::kNoThrowCopy)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + } dummy_ = other.dummy_; } ThrowingValue(ThrowingValue&& other) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) + IsSpecified(TypeSpec::kNoThrowMove)) : TrackedObject(ABSL_PRETTY_FUNCTION) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveCtor)) { + if (!IsSpecified(TypeSpec::kNoThrowMove)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); } dummy_ = other.dummy_; } - explicit ThrowingValue(int i) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) - : TrackedObject(ABSL_PRETTY_FUNCTION) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kIntCtor)) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); - } + explicit ThrowingValue(int i) : TrackedObject(ABSL_PRETTY_FUNCTION) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); dummy_ = i; } @@ -296,15 +316,18 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // absl expects nothrow destructors ~ThrowingValue() noexcept = default; - ThrowingValue& operator=(const ThrowingValue& other) { - exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + ThrowingValue& operator=(const ThrowingValue& other) noexcept( + IsSpecified(TypeSpec::kNoThrowCopy)) { + if (!IsSpecified(TypeSpec::kNoThrowCopy)) { + exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); + } dummy_ = other.dummy_; return *this; } ThrowingValue& operator=(ThrowingValue&& other) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kMoveAssign)) { + IsSpecified(TypeSpec::kNoThrowMove)) { + if (!IsSpecified(TypeSpec::kNoThrowMove)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION); } dummy_ = other.dummy_; @@ -533,8 +556,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { // Args.. allows us to overload regular and placement new in one shot template static void* operator new(size_t s, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); } return ::operator new(s, std::forward(args)...); @@ -542,8 +565,8 @@ class ThrowingValue : private exceptions_internal::TrackedObject { template static void* operator new[](size_t s, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kAllocation)) { + IsSpecified(TypeSpec::kNoThrowNew)) { + if (!IsSpecified(TypeSpec::kNoThrowNew)) { exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true); } return ::operator new[](s, std::forward(args)...); @@ -581,20 +604,35 @@ class ThrowingValue : private exceptions_internal::TrackedObject { }; // While not having to do with exceptions, explicitly delete comma operator, to // make sure we don't use it on user-supplied types. -template -void operator,(const ThrowingValue& ef, T&& t) = delete; -template -void operator,(T&& t, const ThrowingValue& ef) = delete; - -// An allocator type which is instrumented to throw at a controlled time, or not -// to throw, using NoThrow. The supported settings are the default of every -// function which is allowed to throw in a conforming allocator possibly -// throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS -// configuration macro. -template +template +void operator,(const ThrowingValue&, T&&) = delete; +template +void operator,(T&&, const ThrowingValue&) = delete; + +/* + * Configuration enum for the ThrowingAllocator type that defines behavior for + * the lifetime of the instance. + * + * kEverythingThrows: Calls to the member functions may throw + * kNoThrowAllocate: Calls to the member functions will not throw + */ +enum class AllocSpec { + kEverythingThrows = 0, + kNoThrowAllocate = 1, +}; + +/* + * An allocator type which is instrumented to throw at a controlled time, or not + * to throw, using AllocSpec. The supported settings are the default of every + * function which is allowed to throw in a conforming allocator possibly + * throwing, or nothing throws, in line with the ABSL_ALLOCATOR_THROWS + * configuration macro. + */ +template class ThrowingAllocator : private exceptions_internal::TrackedObject { - static_assert(Flags == NoThrow::kNone || Flags == NoThrow::kNoThrow, - "Invalid flag"); + constexpr static bool IsSpecified(AllocSpec spec) { + return static_cast(Spec & spec); + } public: using pointer = T*; @@ -607,7 +645,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { using size_type = size_t; using difference_type = ptrdiff_t; - using is_nothrow = std::integral_constant; + using is_nothrow = + std::integral_constant; using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_swap = std::true_type; @@ -619,8 +658,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } template - ThrowingAllocator( // NOLINT - const ThrowingAllocator& other) noexcept + ThrowingAllocator(const ThrowingAllocator& other) noexcept // NOLINT : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {} // According to C++11 standard [17.6.3.5], Table 28, the move/copy ctors of @@ -629,8 +667,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(other.State()) {} template - ThrowingAllocator( // NOLINT - ThrowingAllocator&& other) noexcept + ThrowingAllocator(ThrowingAllocator&& other) noexcept // NOLINT : TrackedObject(ABSL_PRETTY_FUNCTION), dummy_(std::move(other.State())) {} ThrowingAllocator(ThrowingAllocator&& other) noexcept @@ -645,29 +682,30 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { template ThrowingAllocator& operator=( - const ThrowingAllocator& other) noexcept { + const ThrowingAllocator& other) noexcept { dummy_ = other.State(); return *this; } template - ThrowingAllocator& operator=(ThrowingAllocator&& other) noexcept { + ThrowingAllocator& operator=(ThrowingAllocator&& other) noexcept { dummy_ = std::move(other.State()); return *this; } template struct rebind { - using other = ThrowingAllocator; + using other = ThrowingAllocator; }; pointer allocate(size_type n) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); return static_cast(::operator new(n * sizeof(T))); } + pointer allocate(size_type n, const_void_pointer) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { return allocate(n); } @@ -678,7 +716,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { template void construct(U* ptr, Args&&... args) noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); ::new (static_cast(ptr)) U(std::forward(args)...); } @@ -694,23 +732,23 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } ThrowingAllocator select_on_container_copy_construction() noexcept( - !exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + IsSpecified(AllocSpec::kNoThrowAllocate)) { auto& out = *this; ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION); return out; } template - bool operator==(const ThrowingAllocator& other) const noexcept { + bool operator==(const ThrowingAllocator& other) const noexcept { return dummy_ == other.dummy_; } template - bool operator!=(const ThrowingAllocator& other) const noexcept { + bool operator!=(const ThrowingAllocator& other) const noexcept { return dummy_ != other.dummy_; } - template + template friend class ThrowingAllocator; private: @@ -724,7 +762,7 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { } void ReadStateAndMaybeThrow(absl::string_view msg) const { - if (exceptions_internal::ThrowingAllowed(Flags, NoThrow::kNoThrow)) { + if (!IsSpecified(AllocSpec::kNoThrowAllocate)) { exceptions_internal::MaybeThrow( absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg)); } @@ -734,8 +772,8 @@ class ThrowingAllocator : private exceptions_internal::TrackedObject { std::shared_ptr dummy_; }; -template -int ThrowingAllocator::next_id_ = 0; +template +int ThrowingAllocator::next_id_ = 0; // Tests for resource leaks by attempting to construct a T using args repeatedly // until successful, using the countdown method. Side effects can then be @@ -873,7 +911,7 @@ class ExceptionSafetyTester { * created in order to get an empty Invariants... list. * * In addition to passing in custom invariant assertion callbacks, this method - * accepts `absl::strong_guarantee` as an argument which checks T instances + * accepts `testing::strong_guarantee` as an argument which checks T instances * post-throw against freshly created T instances via operator== to verify * that any state changes made during the execution of the operation were * properly rolled back. @@ -934,7 +972,7 @@ class ExceptionSafetyTester { template friend class ExceptionSafetyTester; - friend ExceptionSafetyTester<> absl::MakeExceptionSafetyTester(); + friend ExceptionSafetyTester<> testing::MakeExceptionSafetyTester(); ExceptionSafetyTester() {} @@ -992,6 +1030,6 @@ MakeExceptionSafetyTester() { return {}; } -} // namespace absl +} // namespace testing #endif // ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_ -- cgit v1.2.3