| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #include "absl/base/no_destructor.h" |
|
|
| #include <array> |
| #include <initializer_list> |
| #include <string> |
| #include <type_traits> |
| #include <vector> |
|
|
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/base/config.h" |
| #include "absl/base/internal/raw_logging.h" |
|
|
| namespace { |
|
|
| struct Blob { |
| Blob() : val(42) {} |
| Blob(int x, int y) : val(x + y) {} |
| Blob(std::initializer_list<int> xs) { |
| val = 0; |
| for (auto& x : xs) val += x; |
| } |
|
|
| Blob(const Blob& ) = delete; |
| Blob(Blob&& b) noexcept : val(b.val) { |
| b.moved_out = true; |
| } |
|
|
| |
| |
| ~Blob() { ABSL_INTERNAL_CHECK(moved_out, "~Blob"); } |
|
|
| int val; |
| bool moved_out = false; |
| }; |
|
|
| struct TypeWithDeletedDestructor { |
| ~TypeWithDeletedDestructor() = delete; |
| }; |
|
|
| TEST(NoDestructorTest, DestructorNeverCalled) { |
| absl::NoDestructor<TypeWithDeletedDestructor> a; |
| (void)a; |
| } |
|
|
| TEST(NoDestructorTest, Noncopyable) { |
| using T = absl::NoDestructor<int>; |
|
|
| EXPECT_FALSE((std::is_constructible<T, T>::value)); |
| EXPECT_FALSE((std::is_constructible<T, const T>::value)); |
| EXPECT_FALSE((std::is_constructible<T, T&>::value)); |
| EXPECT_FALSE((std::is_constructible<T, const T&>::value)); |
|
|
| EXPECT_FALSE((std::is_assignable<T&, T>::value)); |
| EXPECT_FALSE((std::is_assignable<T&, const T>::value)); |
| EXPECT_FALSE((std::is_assignable<T&, T&>::value)); |
| EXPECT_FALSE((std::is_assignable<T&, const T&>::value)); |
| } |
|
|
| TEST(NoDestructorTest, Interface) { |
| EXPECT_TRUE(std::is_trivially_destructible<absl::NoDestructor<Blob>>::value); |
| EXPECT_TRUE( |
| std::is_trivially_destructible<absl::NoDestructor<const Blob>>::value); |
| { |
| absl::NoDestructor<Blob> b; |
| |
| EXPECT_EQ(42, (*b).val); |
| (*b).val = 55; |
| EXPECT_EQ(55, b->val); |
| b->val = 66; |
| EXPECT_EQ(66, b.get()->val); |
| b.get()->val = 42; |
| EXPECT_EQ(42, (*b).val); |
| } |
| { |
| absl::NoDestructor<const Blob> b(70, 7); |
| EXPECT_EQ(77, (*b).val); |
| EXPECT_EQ(77, b->val); |
| EXPECT_EQ(77, b.get()->val); |
| } |
| { |
| const absl::NoDestructor<Blob> b{ |
| {20, 28, 40}}; |
| |
| |
| EXPECT_EQ(88, (*b).val); |
| EXPECT_EQ(88, b->val); |
| EXPECT_EQ(88, b.get()->val); |
| } |
| } |
|
|
| TEST(NoDestructorTest, SfinaeRegressionAbstractArg) { |
| struct Abstract { |
| virtual ~Abstract() = default; |
| virtual int foo() const = 0; |
| }; |
|
|
| struct Concrete : Abstract { |
| int foo() const override { return 17; } |
| }; |
|
|
| struct UsesAbstractInConstructor { |
| explicit UsesAbstractInConstructor(const Abstract& abstract) |
| : i(abstract.foo()) {} |
| int i; |
| }; |
|
|
| Concrete input; |
| absl::NoDestructor<UsesAbstractInConstructor> foo1(input); |
| EXPECT_EQ(foo1->i, 17); |
| absl::NoDestructor<UsesAbstractInConstructor> foo2( |
| static_cast<const Abstract&>(input)); |
| EXPECT_EQ(foo2->i, 17); |
| } |
|
|
| |
|
|
| std::string* Str0() { |
| static absl::NoDestructor<std::string> x; |
| return x.get(); |
| } |
|
|
| extern const std::string& Str2(); |
|
|
| const char* Str1() { |
| static absl::NoDestructor<std::string> x(Str2() + "_Str1"); |
| return x->c_str(); |
| } |
|
|
| const std::string& Str2() { |
| static absl::NoDestructor<std::string> x("Str2"); |
| return *x; |
| } |
|
|
| const std::string& Str2Copy() { |
| |
| static absl::NoDestructor<std::string> x(Str2()); |
| return *x; |
| } |
|
|
| typedef std::array<std::string, 3> MyArray; |
| const MyArray& Array() { |
| static absl::NoDestructor<MyArray> x{{{"foo", "bar", "baz"}}}; |
| |
| |
| return *x; |
| } |
|
|
| typedef std::vector<int> MyVector; |
| const MyVector& Vector() { |
| static absl::NoDestructor<MyVector> x{{1, 2, 3}}; |
| return *x; |
| } |
|
|
| const int& Int() { |
| static absl::NoDestructor<int> x; |
| return *x; |
| } |
|
|
| TEST(NoDestructorTest, StaticPattern) { |
| EXPECT_TRUE( |
| std::is_trivially_destructible<absl::NoDestructor<std::string>>::value); |
| EXPECT_TRUE( |
| std::is_trivially_destructible<absl::NoDestructor<MyArray>>::value); |
| EXPECT_TRUE( |
| std::is_trivially_destructible<absl::NoDestructor<MyVector>>::value); |
| EXPECT_TRUE(std::is_trivially_destructible<absl::NoDestructor<int>>::value); |
|
|
| EXPECT_EQ(*Str0(), ""); |
| Str0()->append("foo"); |
| EXPECT_EQ(*Str0(), "foo"); |
|
|
| EXPECT_EQ(std::string(Str1()), "Str2_Str1"); |
|
|
| EXPECT_EQ(Str2(), "Str2"); |
| EXPECT_EQ(Str2Copy(), "Str2"); |
|
|
| EXPECT_THAT(Array(), testing::ElementsAre("foo", "bar", "baz")); |
|
|
| EXPECT_THAT(Vector(), testing::ElementsAre(1, 2, 3)); |
|
|
| EXPECT_EQ(0, Int()); |
| } |
|
|
| #ifdef ABSL_HAVE_CLASS_TEMPLATE_ARGUMENT_DEDUCTION |
| |
| |
| TEST(NoDestructorTest, ClassTemplateArgumentDeduction) { |
| absl::NoDestructor i(1); |
| static_assert(std::is_same<decltype(i), absl::NoDestructor<int>>::value, |
| "Expected deduced type to be int."); |
| } |
| #endif |
|
|
| } |
|
|