File indexing completed on 2024-11-15 09:00:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
0018 #define ABSL_BASE_INTERNAL_EXCEPTION_SAFETY_TESTING_H_
0019
0020 #include "absl/base/config.h"
0021
0022 #ifdef ABSL_HAVE_EXCEPTIONS
0023
0024 #include <cstddef>
0025 #include <cstdint>
0026 #include <functional>
0027 #include <initializer_list>
0028 #include <iosfwd>
0029 #include <string>
0030 #include <tuple>
0031 #include <unordered_map>
0032
0033 #include "gtest/gtest.h"
0034 #include "absl/base/internal/pretty_function.h"
0035 #include "absl/memory/memory.h"
0036 #include "absl/meta/type_traits.h"
0037 #include "absl/strings/string_view.h"
0038 #include "absl/strings/substitute.h"
0039 #include "absl/utility/utility.h"
0040
0041 namespace testing {
0042
0043 enum class TypeSpec;
0044 enum class AllocSpec;
0045
0046 constexpr TypeSpec operator|(TypeSpec a, TypeSpec b) {
0047 using T = absl::underlying_type_t<TypeSpec>;
0048 return static_cast<TypeSpec>(static_cast<T>(a) | static_cast<T>(b));
0049 }
0050
0051 constexpr TypeSpec operator&(TypeSpec a, TypeSpec b) {
0052 using T = absl::underlying_type_t<TypeSpec>;
0053 return static_cast<TypeSpec>(static_cast<T>(a) & static_cast<T>(b));
0054 }
0055
0056 constexpr AllocSpec operator|(AllocSpec a, AllocSpec b) {
0057 using T = absl::underlying_type_t<AllocSpec>;
0058 return static_cast<AllocSpec>(static_cast<T>(a) | static_cast<T>(b));
0059 }
0060
0061 constexpr AllocSpec operator&(AllocSpec a, AllocSpec b) {
0062 using T = absl::underlying_type_t<AllocSpec>;
0063 return static_cast<AllocSpec>(static_cast<T>(a) & static_cast<T>(b));
0064 }
0065
0066 namespace exceptions_internal {
0067
0068 std::string GetSpecString(TypeSpec);
0069 std::string GetSpecString(AllocSpec);
0070
0071 struct NoThrowTag {};
0072 struct StrongGuaranteeTagType {};
0073
0074
0075
0076 class TestException {
0077 public:
0078 explicit TestException(absl::string_view msg) : msg_(msg) {}
0079 virtual ~TestException() {}
0080 virtual const char* what() const noexcept { return msg_.c_str(); }
0081
0082 private:
0083 std::string msg_;
0084 };
0085
0086
0087
0088
0089
0090
0091 class TestBadAllocException : public std::bad_alloc, public TestException {
0092 public:
0093 explicit TestBadAllocException(absl::string_view msg) : TestException(msg) {}
0094 using TestException::what;
0095 };
0096
0097 extern int countdown;
0098
0099
0100
0101 inline void SetCountdown(int i = 0) { countdown = i; }
0102
0103 inline void UnsetCountdown() { SetCountdown(-1); }
0104
0105 void MaybeThrow(absl::string_view msg, bool throw_bad_alloc = false);
0106
0107 testing::AssertionResult FailureMessage(const TestException& e,
0108 int countdown) noexcept;
0109
0110 struct TrackedAddress {
0111 bool is_alive;
0112 std::string description;
0113 };
0114
0115
0116
0117
0118 class ConstructorTracker {
0119 public:
0120 explicit ConstructorTracker(int count) : countdown_(count) {
0121 assert(current_tracker_instance_ == nullptr);
0122 current_tracker_instance_ = this;
0123 }
0124
0125 ~ConstructorTracker() {
0126 assert(current_tracker_instance_ == this);
0127 current_tracker_instance_ = nullptr;
0128
0129 for (auto& it : address_map_) {
0130 void* address = it.first;
0131 TrackedAddress& tracked_address = it.second;
0132 if (tracked_address.is_alive) {
0133 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
0134 countdown_, "Object was not destroyed.");
0135 }
0136 }
0137 }
0138
0139 static void ObjectConstructed(void* address, std::string description) {
0140 if (!CurrentlyTracking()) return;
0141
0142 TrackedAddress& tracked_address =
0143 current_tracker_instance_->address_map_[address];
0144 if (tracked_address.is_alive) {
0145 ADD_FAILURE() << ErrorMessage(
0146 address, tracked_address.description,
0147 current_tracker_instance_->countdown_,
0148 "Object was re-constructed. Current object was constructed by " +
0149 description);
0150 }
0151 tracked_address = {true, std::move(description)};
0152 }
0153
0154 static void ObjectDestructed(void* address) {
0155 if (!CurrentlyTracking()) return;
0156
0157 auto it = current_tracker_instance_->address_map_.find(address);
0158
0159 if (it == current_tracker_instance_->address_map_.end()) return;
0160
0161 TrackedAddress& tracked_address = it->second;
0162 if (!tracked_address.is_alive) {
0163 ADD_FAILURE() << ErrorMessage(address, tracked_address.description,
0164 current_tracker_instance_->countdown_,
0165 "Object was re-destroyed.");
0166 }
0167 tracked_address.is_alive = false;
0168 }
0169
0170 private:
0171 static bool CurrentlyTracking() {
0172 return current_tracker_instance_ != nullptr;
0173 }
0174
0175 static std::string ErrorMessage(void* address,
0176 const std::string& address_description,
0177 int countdown,
0178 const std::string& error_description) {
0179 return absl::Substitute(
0180 "With coundtown at $0:\n"
0181 " $1\n"
0182 " Object originally constructed by $2\n"
0183 " Object address: $3\n",
0184 countdown, error_description, address_description, address);
0185 }
0186
0187 std::unordered_map<void*, TrackedAddress> address_map_;
0188 int countdown_;
0189
0190 static ConstructorTracker* current_tracker_instance_;
0191 };
0192
0193 class TrackedObject {
0194 public:
0195 TrackedObject(const TrackedObject&) = delete;
0196 TrackedObject(TrackedObject&&) = delete;
0197
0198 protected:
0199 explicit TrackedObject(std::string description) {
0200 ConstructorTracker::ObjectConstructed(this, std::move(description));
0201 }
0202
0203 ~TrackedObject() noexcept { ConstructorTracker::ObjectDestructed(this); }
0204 };
0205 }
0206
0207 extern exceptions_internal::NoThrowTag nothrow_ctor;
0208
0209 extern exceptions_internal::StrongGuaranteeTagType strong_guarantee;
0210
0211
0212
0213 class ThrowingBool {
0214 public:
0215 ThrowingBool(bool b) noexcept : b_(b) {}
0216 operator bool() const {
0217 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0218 return b_;
0219 }
0220
0221 private:
0222 bool b_;
0223 };
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235 enum class TypeSpec {
0236 kEverythingThrows = 0,
0237 kNoThrowCopy = 1,
0238 kNoThrowMove = 1 << 1,
0239 kNoThrowNew = 1 << 2,
0240 };
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256 template <TypeSpec Spec = TypeSpec::kEverythingThrows>
0257 class ThrowingValue : private exceptions_internal::TrackedObject {
0258 static constexpr bool IsSpecified(TypeSpec spec) {
0259 return static_cast<bool>(Spec & spec);
0260 }
0261
0262 static constexpr int kDefaultValue = 0;
0263 static constexpr int kBadValue = 938550620;
0264
0265 public:
0266 ThrowingValue() : TrackedObject(GetInstanceString(kDefaultValue)) {
0267 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0268 dummy_ = kDefaultValue;
0269 }
0270
0271 ThrowingValue(const ThrowingValue& other) noexcept(
0272 IsSpecified(TypeSpec::kNoThrowCopy))
0273 : TrackedObject(GetInstanceString(other.dummy_)) {
0274 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
0275 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0276 }
0277 dummy_ = other.dummy_;
0278 }
0279
0280 ThrowingValue(ThrowingValue&& other) noexcept(
0281 IsSpecified(TypeSpec::kNoThrowMove))
0282 : TrackedObject(GetInstanceString(other.dummy_)) {
0283 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
0284 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0285 }
0286 dummy_ = other.dummy_;
0287 }
0288
0289 explicit ThrowingValue(int i) : TrackedObject(GetInstanceString(i)) {
0290 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0291 dummy_ = i;
0292 }
0293
0294 ThrowingValue(int i, exceptions_internal::NoThrowTag) noexcept
0295 : TrackedObject(GetInstanceString(i)), dummy_(i) {}
0296
0297
0298 ~ThrowingValue() noexcept = default;
0299
0300 ThrowingValue& operator=(const ThrowingValue& other) noexcept(
0301 IsSpecified(TypeSpec::kNoThrowCopy)) {
0302 dummy_ = kBadValue;
0303 if (!IsSpecified(TypeSpec::kNoThrowCopy)) {
0304 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0305 }
0306 dummy_ = other.dummy_;
0307 return *this;
0308 }
0309
0310 ThrowingValue& operator=(ThrowingValue&& other) noexcept(
0311 IsSpecified(TypeSpec::kNoThrowMove)) {
0312 dummy_ = kBadValue;
0313 if (!IsSpecified(TypeSpec::kNoThrowMove)) {
0314 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0315 }
0316 dummy_ = other.dummy_;
0317 return *this;
0318 }
0319
0320
0321 ThrowingValue operator+(const ThrowingValue& other) const {
0322 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0323 return ThrowingValue(dummy_ + other.dummy_, nothrow_ctor);
0324 }
0325
0326 ThrowingValue operator+() const {
0327 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0328 return ThrowingValue(dummy_, nothrow_ctor);
0329 }
0330
0331 ThrowingValue operator-(const ThrowingValue& other) const {
0332 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0333 return ThrowingValue(dummy_ - other.dummy_, nothrow_ctor);
0334 }
0335
0336 ThrowingValue operator-() const {
0337 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0338 return ThrowingValue(-dummy_, nothrow_ctor);
0339 }
0340
0341 ThrowingValue& operator++() {
0342 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0343 ++dummy_;
0344 return *this;
0345 }
0346
0347 ThrowingValue operator++(int) {
0348 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0349 auto out = ThrowingValue(dummy_, nothrow_ctor);
0350 ++dummy_;
0351 return out;
0352 }
0353
0354 ThrowingValue& operator--() {
0355 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0356 --dummy_;
0357 return *this;
0358 }
0359
0360 ThrowingValue operator--(int) {
0361 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0362 auto out = ThrowingValue(dummy_, nothrow_ctor);
0363 --dummy_;
0364 return out;
0365 }
0366
0367 ThrowingValue operator*(const ThrowingValue& other) const {
0368 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0369 return ThrowingValue(dummy_ * other.dummy_, nothrow_ctor);
0370 }
0371
0372 ThrowingValue operator/(const ThrowingValue& other) const {
0373 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0374 return ThrowingValue(dummy_ / other.dummy_, nothrow_ctor);
0375 }
0376
0377 ThrowingValue operator%(const ThrowingValue& other) const {
0378 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0379 return ThrowingValue(dummy_ % other.dummy_, nothrow_ctor);
0380 }
0381
0382 ThrowingValue operator<<(int shift) const {
0383 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0384 return ThrowingValue(dummy_ << shift, nothrow_ctor);
0385 }
0386
0387 ThrowingValue operator>>(int shift) const {
0388 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0389 return ThrowingValue(dummy_ >> shift, nothrow_ctor);
0390 }
0391
0392
0393
0394
0395 friend ThrowingBool operator==(const ThrowingValue& a,
0396 const ThrowingValue& b) {
0397 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0398 return a.dummy_ == b.dummy_;
0399 }
0400 friend ThrowingBool operator!=(const ThrowingValue& a,
0401 const ThrowingValue& b) {
0402 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0403 return a.dummy_ != b.dummy_;
0404 }
0405 friend ThrowingBool operator<(const ThrowingValue& a,
0406 const ThrowingValue& b) {
0407 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0408 return a.dummy_ < b.dummy_;
0409 }
0410 friend ThrowingBool operator<=(const ThrowingValue& a,
0411 const ThrowingValue& b) {
0412 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0413 return a.dummy_ <= b.dummy_;
0414 }
0415 friend ThrowingBool operator>(const ThrowingValue& a,
0416 const ThrowingValue& b) {
0417 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0418 return a.dummy_ > b.dummy_;
0419 }
0420 friend ThrowingBool operator>=(const ThrowingValue& a,
0421 const ThrowingValue& b) {
0422 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0423 return a.dummy_ >= b.dummy_;
0424 }
0425
0426
0427 ThrowingBool operator!() const {
0428 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0429 return !dummy_;
0430 }
0431
0432 ThrowingBool operator&&(const ThrowingValue& other) const {
0433 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0434 return dummy_ && other.dummy_;
0435 }
0436
0437 ThrowingBool operator||(const ThrowingValue& other) const {
0438 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0439 return dummy_ || other.dummy_;
0440 }
0441
0442
0443 ThrowingValue operator~() const {
0444 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0445 return ThrowingValue(~dummy_, nothrow_ctor);
0446 }
0447
0448 ThrowingValue operator&(const ThrowingValue& other) const {
0449 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0450 return ThrowingValue(dummy_ & other.dummy_, nothrow_ctor);
0451 }
0452
0453 ThrowingValue operator|(const ThrowingValue& other) const {
0454 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0455 return ThrowingValue(dummy_ | other.dummy_, nothrow_ctor);
0456 }
0457
0458 ThrowingValue operator^(const ThrowingValue& other) const {
0459 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0460 return ThrowingValue(dummy_ ^ other.dummy_, nothrow_ctor);
0461 }
0462
0463
0464 ThrowingValue& operator+=(const ThrowingValue& other) {
0465 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0466 dummy_ += other.dummy_;
0467 return *this;
0468 }
0469
0470 ThrowingValue& operator-=(const ThrowingValue& other) {
0471 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0472 dummy_ -= other.dummy_;
0473 return *this;
0474 }
0475
0476 ThrowingValue& operator*=(const ThrowingValue& other) {
0477 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0478 dummy_ *= other.dummy_;
0479 return *this;
0480 }
0481
0482 ThrowingValue& operator/=(const ThrowingValue& other) {
0483 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0484 dummy_ /= other.dummy_;
0485 return *this;
0486 }
0487
0488 ThrowingValue& operator%=(const ThrowingValue& other) {
0489 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0490 dummy_ %= other.dummy_;
0491 return *this;
0492 }
0493
0494 ThrowingValue& operator&=(const ThrowingValue& other) {
0495 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0496 dummy_ &= other.dummy_;
0497 return *this;
0498 }
0499
0500 ThrowingValue& operator|=(const ThrowingValue& other) {
0501 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0502 dummy_ |= other.dummy_;
0503 return *this;
0504 }
0505
0506 ThrowingValue& operator^=(const ThrowingValue& other) {
0507 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0508 dummy_ ^= other.dummy_;
0509 return *this;
0510 }
0511
0512 ThrowingValue& operator<<=(int shift) {
0513 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0514 dummy_ <<= shift;
0515 return *this;
0516 }
0517
0518 ThrowingValue& operator>>=(int shift) {
0519 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0520 dummy_ >>= shift;
0521 return *this;
0522 }
0523
0524
0525 void operator&() const = delete;
0526
0527
0528 friend std::ostream& operator<<(std::ostream& os, const ThrowingValue& tv) {
0529 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0530 return os << GetInstanceString(tv.dummy_);
0531 }
0532
0533 friend std::istream& operator>>(std::istream& is, const ThrowingValue&) {
0534 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0535 return is;
0536 }
0537
0538
0539 static void* operator new(size_t s) noexcept(
0540 IsSpecified(TypeSpec::kNoThrowNew)) {
0541 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
0542 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
0543 }
0544 return ::operator new(s);
0545 }
0546
0547 static void* operator new[](size_t s) noexcept(
0548 IsSpecified(TypeSpec::kNoThrowNew)) {
0549 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
0550 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
0551 }
0552 return ::operator new[](s);
0553 }
0554
0555 template <typename... Args>
0556 static void* operator new(size_t s, Args&&... args) noexcept(
0557 IsSpecified(TypeSpec::kNoThrowNew)) {
0558 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
0559 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
0560 }
0561 return ::operator new(s, std::forward<Args>(args)...);
0562 }
0563
0564 template <typename... Args>
0565 static void* operator new[](size_t s, Args&&... args) noexcept(
0566 IsSpecified(TypeSpec::kNoThrowNew)) {
0567 if (!IsSpecified(TypeSpec::kNoThrowNew)) {
0568 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION, true);
0569 }
0570 return ::operator new[](s, std::forward<Args>(args)...);
0571 }
0572
0573
0574
0575 void operator delete(void* p) noexcept { ::operator delete(p); }
0576
0577 template <typename... Args>
0578 void operator delete(void* p, Args&&... args) noexcept {
0579 ::operator delete(p, std::forward<Args>(args)...);
0580 }
0581
0582 void operator delete[](void* p) noexcept { return ::operator delete[](p); }
0583
0584 template <typename... Args>
0585 void operator delete[](void* p, Args&&... args) noexcept {
0586 return ::operator delete[](p, std::forward<Args>(args)...);
0587 }
0588
0589
0590
0591 int& Get() noexcept { return dummy_; }
0592 const int& Get() const noexcept { return dummy_; }
0593
0594 private:
0595 static std::string GetInstanceString(int dummy) {
0596 return absl::StrCat("ThrowingValue<",
0597 exceptions_internal::GetSpecString(Spec), ">(", dummy,
0598 ")");
0599 }
0600
0601 int dummy_;
0602 };
0603
0604
0605 template <TypeSpec Spec, typename T>
0606 void operator,(const ThrowingValue<Spec>&, T&&) = delete;
0607 template <TypeSpec Spec, typename T>
0608 void operator,(T&&, const ThrowingValue<Spec>&) = delete;
0609
0610
0611
0612
0613
0614
0615
0616
0617 enum class AllocSpec {
0618 kEverythingThrows = 0,
0619 kNoThrowAllocate = 1,
0620 };
0621
0622
0623
0624
0625
0626
0627
0628
0629 template <typename T, AllocSpec Spec = AllocSpec::kEverythingThrows>
0630 class ThrowingAllocator : private exceptions_internal::TrackedObject {
0631 static constexpr bool IsSpecified(AllocSpec spec) {
0632 return static_cast<bool>(Spec & spec);
0633 }
0634
0635 public:
0636 using pointer = T*;
0637 using const_pointer = const T*;
0638 using reference = T&;
0639 using const_reference = const T&;
0640 using void_pointer = void*;
0641 using const_void_pointer = const void*;
0642 using value_type = T;
0643 using size_type = size_t;
0644 using difference_type = ptrdiff_t;
0645
0646 using is_nothrow =
0647 std::integral_constant<bool, Spec == AllocSpec::kNoThrowAllocate>;
0648 using propagate_on_container_copy_assignment = std::true_type;
0649 using propagate_on_container_move_assignment = std::true_type;
0650 using propagate_on_container_swap = std::true_type;
0651 using is_always_equal = std::false_type;
0652
0653 ThrowingAllocator() : TrackedObject(GetInstanceString(next_id_)) {
0654 exceptions_internal::MaybeThrow(ABSL_PRETTY_FUNCTION);
0655 dummy_ = std::make_shared<const int>(next_id_++);
0656 }
0657
0658 template <typename U>
0659 ThrowingAllocator(const ThrowingAllocator<U, Spec>& other) noexcept
0660 : TrackedObject(GetInstanceString(*other.State())),
0661 dummy_(other.State()) {}
0662
0663
0664
0665 ThrowingAllocator(const ThrowingAllocator& other) noexcept
0666 : TrackedObject(GetInstanceString(*other.State())),
0667 dummy_(other.State()) {}
0668
0669 template <typename U>
0670 ThrowingAllocator(ThrowingAllocator<U, Spec>&& other) noexcept
0671 : TrackedObject(GetInstanceString(*other.State())),
0672 dummy_(std::move(other.State())) {}
0673
0674 ThrowingAllocator(ThrowingAllocator&& other) noexcept
0675 : TrackedObject(GetInstanceString(*other.State())),
0676 dummy_(std::move(other.State())) {}
0677
0678 ~ThrowingAllocator() noexcept = default;
0679
0680 ThrowingAllocator& operator=(const ThrowingAllocator& other) noexcept {
0681 dummy_ = other.State();
0682 return *this;
0683 }
0684
0685 template <typename U>
0686 ThrowingAllocator& operator=(
0687 const ThrowingAllocator<U, Spec>& other) noexcept {
0688 dummy_ = other.State();
0689 return *this;
0690 }
0691
0692 template <typename U>
0693 ThrowingAllocator& operator=(ThrowingAllocator<U, Spec>&& other) noexcept {
0694 dummy_ = std::move(other.State());
0695 return *this;
0696 }
0697
0698 template <typename U>
0699 struct rebind {
0700 using other = ThrowingAllocator<U, Spec>;
0701 };
0702
0703 pointer allocate(size_type n) noexcept(
0704 IsSpecified(AllocSpec::kNoThrowAllocate)) {
0705 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
0706 return static_cast<pointer>(::operator new(n * sizeof(T)));
0707 }
0708
0709 pointer allocate(size_type n, const_void_pointer) noexcept(
0710 IsSpecified(AllocSpec::kNoThrowAllocate)) {
0711 return allocate(n);
0712 }
0713
0714 void deallocate(pointer ptr, size_type) noexcept {
0715 ReadState();
0716 ::operator delete(static_cast<void*>(ptr));
0717 }
0718
0719 template <typename U, typename... Args>
0720 void construct(U* ptr, Args&&... args) noexcept(
0721 IsSpecified(AllocSpec::kNoThrowAllocate)) {
0722 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
0723 ::new (static_cast<void*>(ptr)) U(std::forward<Args>(args)...);
0724 }
0725
0726 template <typename U>
0727 void destroy(U* p) noexcept {
0728 ReadState();
0729 p->~U();
0730 }
0731
0732 size_type max_size() const noexcept {
0733 return (std::numeric_limits<difference_type>::max)() / sizeof(value_type);
0734 }
0735
0736 ThrowingAllocator select_on_container_copy_construction() noexcept(
0737 IsSpecified(AllocSpec::kNoThrowAllocate)) {
0738 ReadStateAndMaybeThrow(ABSL_PRETTY_FUNCTION);
0739 return *this;
0740 }
0741
0742 template <typename U>
0743 bool operator==(const ThrowingAllocator<U, Spec>& other) const noexcept {
0744 return dummy_ == other.dummy_;
0745 }
0746
0747 template <typename U>
0748 bool operator!=(const ThrowingAllocator<U, Spec>& other) const noexcept {
0749 return dummy_ != other.dummy_;
0750 }
0751
0752 template <typename, AllocSpec>
0753 friend class ThrowingAllocator;
0754
0755 private:
0756 static std::string GetInstanceString(int dummy) {
0757 return absl::StrCat("ThrowingAllocator<",
0758 exceptions_internal::GetSpecString(Spec), ">(", dummy,
0759 ")");
0760 }
0761
0762 const std::shared_ptr<const int>& State() const { return dummy_; }
0763 std::shared_ptr<const int>& State() { return dummy_; }
0764
0765 void ReadState() {
0766
0767
0768 if (*dummy_ < 0) std::abort();
0769 }
0770
0771 void ReadStateAndMaybeThrow(absl::string_view msg) const {
0772 if (!IsSpecified(AllocSpec::kNoThrowAllocate)) {
0773 exceptions_internal::MaybeThrow(
0774 absl::Substitute("Allocator id $0 threw from $1", *dummy_, msg));
0775 }
0776 }
0777
0778 static int next_id_;
0779 std::shared_ptr<const int> dummy_;
0780 };
0781
0782 template <typename T, AllocSpec Spec>
0783 int ThrowingAllocator<T, Spec>::next_id_ = 0;
0784
0785
0786
0787
0788 template <typename T, typename... Args>
0789 void TestThrowingCtor(Args&&... args) {
0790 struct Cleanup {
0791 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
0792 } c;
0793 for (int count = 0;; ++count) {
0794 exceptions_internal::ConstructorTracker ct(count);
0795 exceptions_internal::SetCountdown(count);
0796 try {
0797 T temp(std::forward<Args>(args)...);
0798 static_cast<void>(temp);
0799 break;
0800 } catch (const exceptions_internal::TestException&) {
0801 }
0802 }
0803 }
0804
0805
0806
0807
0808 template <typename Operation>
0809 testing::AssertionResult TestNothrowOp(const Operation& operation) {
0810 struct Cleanup {
0811 Cleanup() { exceptions_internal::SetCountdown(); }
0812 ~Cleanup() { exceptions_internal::UnsetCountdown(); }
0813 } c;
0814 try {
0815 operation();
0816 return testing::AssertionSuccess();
0817 } catch (const exceptions_internal::TestException&) {
0818 return testing::AssertionFailure()
0819 << "TestException thrown during call to operation() when nothrow "
0820 "guarantee was expected.";
0821 } catch (...) {
0822 return testing::AssertionFailure()
0823 << "Unknown exception thrown during call to operation() when "
0824 "nothrow guarantee was expected.";
0825 }
0826 }
0827
0828 namespace exceptions_internal {
0829
0830
0831 struct UninitializedT {};
0832
0833 template <typename T>
0834 class DefaultFactory {
0835 public:
0836 explicit DefaultFactory(const T& t) : t_(t) {}
0837 std::unique_ptr<T> operator()() const { return absl::make_unique<T>(t_); }
0838
0839 private:
0840 T t_;
0841 };
0842
0843 template <size_t LazyContractsCount, typename LazyFactory,
0844 typename LazyOperation>
0845 using EnableIfTestable = typename absl::enable_if_t<
0846 LazyContractsCount != 0 &&
0847 !std::is_same<LazyFactory, UninitializedT>::value &&
0848 !std::is_same<LazyOperation, UninitializedT>::value>;
0849
0850 template <typename Factory = UninitializedT,
0851 typename Operation = UninitializedT, typename... Contracts>
0852 class ExceptionSafetyTestBuilder;
0853
0854 }
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865 exceptions_internal::ExceptionSafetyTestBuilder<> MakeExceptionSafetyTester();
0866
0867 namespace exceptions_internal {
0868 template <typename T>
0869 struct IsUniquePtr : std::false_type {};
0870
0871 template <typename T, typename D>
0872 struct IsUniquePtr<std::unique_ptr<T, D>> : std::true_type {};
0873
0874 template <typename Factory>
0875 struct FactoryPtrTypeHelper {
0876 using type = decltype(std::declval<const Factory&>()());
0877
0878 static_assert(IsUniquePtr<type>::value, "Factories must return a unique_ptr");
0879 };
0880
0881 template <typename Factory>
0882 using FactoryPtrType = typename FactoryPtrTypeHelper<Factory>::type;
0883
0884 template <typename Factory>
0885 using FactoryElementType = typename FactoryPtrType<Factory>::element_type;
0886
0887 template <typename T>
0888 class ExceptionSafetyTest {
0889 using Factory = std::function<std::unique_ptr<T>()>;
0890 using Operation = std::function<void(T*)>;
0891 using Contract = std::function<AssertionResult(T*)>;
0892
0893 public:
0894 template <typename... Contracts>
0895 explicit ExceptionSafetyTest(const Factory& f, const Operation& op,
0896 const Contracts&... contracts)
0897 : factory_(f), operation_(op), contracts_{WrapContract(contracts)...} {}
0898
0899 AssertionResult Test() const {
0900 for (int count = 0;; ++count) {
0901 exceptions_internal::ConstructorTracker ct(count);
0902
0903 for (const auto& contract : contracts_) {
0904 auto t_ptr = factory_();
0905 try {
0906 SetCountdown(count);
0907 operation_(t_ptr.get());
0908
0909
0910
0911 UnsetCountdown();
0912 return AssertionSuccess();
0913 } catch (const exceptions_internal::TestException& e) {
0914 if (!contract(t_ptr.get())) {
0915 return AssertionFailure() << e.what() << " failed contract check";
0916 }
0917 }
0918 }
0919 }
0920 }
0921
0922 private:
0923 template <typename ContractFn>
0924 Contract WrapContract(const ContractFn& contract) {
0925 return [contract](T* t_ptr) { return AssertionResult(contract(t_ptr)); };
0926 }
0927
0928 Contract WrapContract(StrongGuaranteeTagType) {
0929 return [this](T* t_ptr) { return AssertionResult(*factory_() == *t_ptr); };
0930 }
0931
0932 Factory factory_;
0933 Operation operation_;
0934 std::vector<Contract> contracts_;
0935 };
0936
0937
0938
0939
0940
0941
0942
0943
0944
0945
0946
0947
0948
0949
0950
0951
0952
0953
0954
0955
0956
0957
0958
0959
0960
0961
0962
0963
0964
0965
0966
0967
0968 template <typename Factory, typename Operation, typename... Contracts>
0969 class ExceptionSafetyTestBuilder {
0970 public:
0971
0972
0973
0974
0975
0976
0977
0978
0979
0980
0981
0982
0983 template <typename T>
0984 ExceptionSafetyTestBuilder<DefaultFactory<T>, Operation, Contracts...>
0985 WithInitialValue(const T& t) const {
0986 return WithFactory(DefaultFactory<T>(t));
0987 }
0988
0989
0990
0991
0992
0993
0994
0995
0996 template <typename NewFactory>
0997 ExceptionSafetyTestBuilder<absl::decay_t<NewFactory>, Operation, Contracts...>
0998 WithFactory(const NewFactory& new_factory) const {
0999 return {new_factory, operation_, contracts_};
1000 }
1001
1002
1003
1004
1005
1006
1007 template <typename NewOperation>
1008 ExceptionSafetyTestBuilder<Factory, absl::decay_t<NewOperation>, Contracts...>
1009 WithOperation(const NewOperation& new_operation) const {
1010 return {factory_, new_operation, contracts_};
1011 }
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 template <typename... MoreContracts>
1027 ExceptionSafetyTestBuilder<Factory, Operation, Contracts...,
1028 absl::decay_t<MoreContracts>...>
1029 WithContracts(const MoreContracts&... more_contracts) const {
1030 return {
1031 factory_, operation_,
1032 std::tuple_cat(contracts_, std::tuple<absl::decay_t<MoreContracts>...>(
1033 more_contracts...))};
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052 template <
1053 typename NewOperation,
1054 typename = EnableIfTestable<sizeof...(Contracts), Factory, NewOperation>>
1055 testing::AssertionResult Test(const NewOperation& new_operation) const {
1056 return TestImpl(new_operation, absl::index_sequence_for<Contracts...>());
1057 }
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071 template <
1072 typename LazyOperation = Operation,
1073 typename = EnableIfTestable<sizeof...(Contracts), Factory, LazyOperation>>
1074 testing::AssertionResult Test() const {
1075 return Test(operation_);
1076 }
1077
1078 private:
1079 template <typename, typename, typename...>
1080 friend class ExceptionSafetyTestBuilder;
1081
1082 friend ExceptionSafetyTestBuilder<> testing::MakeExceptionSafetyTester();
1083
1084 ExceptionSafetyTestBuilder() {}
1085
1086 ExceptionSafetyTestBuilder(const Factory& f, const Operation& o,
1087 const std::tuple<Contracts...>& i)
1088 : factory_(f), operation_(o), contracts_(i) {}
1089
1090 template <typename SelectedOperation, size_t... Indices>
1091 testing::AssertionResult TestImpl(SelectedOperation selected_operation,
1092 absl::index_sequence<Indices...>) const {
1093 return ExceptionSafetyTest<FactoryElementType<Factory>>(
1094 factory_, selected_operation, std::get<Indices>(contracts_)...)
1095 .Test();
1096 }
1097
1098 Factory factory_;
1099 Operation operation_;
1100 std::tuple<Contracts...> contracts_;
1101 };
1102
1103 }
1104
1105 }
1106
1107 #endif
1108
1109 #endif