From b57c703963be1ca9749b902c49083beac56648aa Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 24 Oct 2018 22:04:43 -0400 Subject: Googletest export Remove linked_ptr and use std::shared_ptr instead PiperOrigin-RevId: 218618184 --- googlemock/include/gmock/gmock-actions.h | 21 +- googlemock/include/gmock/gmock-cardinalities.h | 8 +- googlemock/include/gmock/gmock-generated-actions.h | 3 +- .../include/gmock/gmock-generated-actions.h.pump | 3 +- googlemock/include/gmock/gmock-matchers.h | 25 ++- googlemock/include/gmock/gmock-spec-builders.h | 31 ++- .../include/gmock/internal/gmock-internal-utils.h | 9 + googlemock/include/gmock/internal/gmock-port.h | 1 + googlemock/src/gmock-spec-builders.cc | 3 +- googlemock/test/gmock-generated-actions_test.cc | 16 +- googlemock/test/gmock-internal-utils_test.cc | 8 +- googlemock/test/gmock-matchers_test.cc | 32 ++- googlemock/test/gmock-more-actions_test.cc | 11 +- googlemock/test/gmock-spec-builders_test.cc | 8 +- googlemock/test/gmock_stress_test.cc | 81 +++++++ googletest/CMakeLists.txt | 1 + .../include/gtest/internal/gtest-linked_ptr.h | 243 +++++++++++++++++++++ .../gtest/internal/gtest-param-util-generated.h | 20 +- .../internal/gtest-param-util-generated.h.pump | 4 +- .../include/gtest/internal/gtest-param-util.h | 13 +- googletest/src/gtest-port.cc | 12 +- googletest/src/gtest.cc | 3 + googletest/test/googletest-linked-ptr-test.cc | 151 +++++++++++++ googletest/test/gtest_all_test.cc | 1 + 24 files changed, 624 insertions(+), 84 deletions(-) create mode 100644 googletest/include/gtest/internal/gtest-linked_ptr.h create mode 100644 googletest/test/googletest-linked-ptr-test.cc diff --git a/googlemock/include/gmock/gmock-actions.h b/googlemock/include/gmock/gmock-actions.h index e4af9d2..d4af949 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -42,7 +42,6 @@ #endif #include -#include #include #include @@ -347,7 +346,9 @@ class ActionInterface { // An Action is a copyable and IMMUTABLE (except by assignment) // object that represents an action to be taken when a mock function // of type F is called. The implementation of Action is just a -// std::shared_ptr to const ActionInterface. Don't inherit from Action! +// linked_ptr to const ActionInterface, so copying is fairly cheap. +// Don't inherit from Action! +// // You can view an object implementing ActionInterface as a // concrete action (including its current state), and an Action // object as a handle to it. @@ -424,7 +425,7 @@ class Action { #if GTEST_LANG_CXX11 ::std::function fun_; #endif - std::shared_ptr> impl_; + internal::linked_ptr > impl_; }; // The PolymorphicAction class template makes it easy to implement a @@ -518,7 +519,7 @@ class ActionAdaptor : public ActionInterface { } private: - const std::shared_ptr> impl_; + const internal::linked_ptr > impl_; GTEST_DISALLOW_ASSIGN_(ActionAdaptor); }; @@ -600,7 +601,7 @@ class ReturnAction { // Result to call. ImplicitCast_ forces the compiler to convert R to // Result without considering explicit constructors, thus resolving the // ambiguity. value_ is then initialized using its copy constructor. - explicit Impl(const std::shared_ptr& value) + explicit Impl(const linked_ptr& value) : value_before_cast_(*value), value_(ImplicitCast_(value_before_cast_)) {} @@ -625,7 +626,7 @@ class ReturnAction { typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; - explicit Impl(const std::shared_ptr& wrapper) + explicit Impl(const linked_ptr& wrapper) : performed_(false), wrapper_(wrapper) {} virtual Result Perform(const ArgumentTuple&) { @@ -637,12 +638,12 @@ class ReturnAction { private: bool performed_; - const std::shared_ptr wrapper_; + const linked_ptr wrapper_; GTEST_DISALLOW_ASSIGN_(Impl); }; - const std::shared_ptr value_; + const linked_ptr value_; GTEST_DISALLOW_ASSIGN_(ReturnAction); }; @@ -865,7 +866,7 @@ class SetArgumentPointeeAction { } private: - const std::shared_ptr proto_; + const internal::linked_ptr proto_; GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; @@ -930,7 +931,7 @@ class InvokeCallbackWithoutArgsAction { Result Perform(const ArgumentTuple&) const { return callback_->Run(); } private: - const std::shared_ptr callback_; + const internal::linked_ptr callback_; GTEST_DISALLOW_ASSIGN_(InvokeCallbackWithoutArgsAction); }; diff --git a/googlemock/include/gmock/gmock-cardinalities.h b/googlemock/include/gmock/gmock-cardinalities.h index 8fa25eb..f916931 100644 --- a/googlemock/include/gmock/gmock-cardinalities.h +++ b/googlemock/include/gmock/gmock-cardinalities.h @@ -40,7 +40,6 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #include -#include #include // NOLINT #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" @@ -82,8 +81,9 @@ class CardinalityInterface { // A Cardinality is a copyable and IMMUTABLE (except by assignment) // object that specifies how many times a mock function is expected to -// be called. The implementation of Cardinality is just a std::shared_ptr -// to const CardinalityInterface. Don't inherit from Cardinality! +// be called. The implementation of Cardinality is just a linked_ptr +// to const CardinalityInterface, so copying is fairly cheap. +// Don't inherit from Cardinality! class GTEST_API_ Cardinality { public: // Constructs a null cardinality. Needed for storing Cardinality @@ -123,7 +123,7 @@ class GTEST_API_ Cardinality { ::std::ostream* os); private: - std::shared_ptr impl_; + internal::linked_ptr impl_; }; // Creates a cardinality that allows at least n calls. diff --git a/googlemock/include/gmock/gmock-generated-actions.h b/googlemock/include/gmock/gmock-generated-actions.h index 8966f05..0845b22 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h +++ b/googlemock/include/gmock/gmock-generated-actions.h @@ -41,7 +41,6 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#include #include #include "gmock/gmock-actions.h" @@ -349,7 +348,7 @@ class InvokeCallbackAction { callback_.get(), args); } private: - const std::shared_ptr callback_; + const linked_ptr callback_; }; // An INTERNAL macro for extracting the type of a tuple field. It's diff --git a/googlemock/include/gmock/gmock-generated-actions.h.pump b/googlemock/include/gmock/gmock-generated-actions.h.pump index 09a39ca..bc22be8 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h.pump +++ b/googlemock/include/gmock/gmock-generated-actions.h.pump @@ -43,7 +43,6 @@ $$}} This meta comment fixes auto-indentation in editors. #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ -#include #include #include "gmock/gmock-actions.h" @@ -119,7 +118,7 @@ class InvokeCallbackAction { callback_.get(), args); } private: - const std::shared_ptr callback_; + const linked_ptr callback_; }; // An INTERNAL macro for extracting the type of a tuple field. It's diff --git a/googlemock/include/gmock/gmock-matchers.h b/googlemock/include/gmock/gmock-matchers.h index 95bc22c..6e8bc03 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -43,15 +43,14 @@ #include #include #include -#include #include // NOLINT #include #include #include #include +#include "gtest/gtest.h" #include "gmock/internal/gmock-internal-utils.h" #include "gmock/internal/gmock-port.h" -#include "gtest/gtest.h" #if GTEST_HAS_STD_INITIALIZER_LIST_ # include // NOLINT -- must be after gtest.h @@ -339,15 +338,29 @@ class MatcherBase { virtual ~MatcherBase() {} private: - std::shared_ptr> impl_; + // shared_ptr (util/gtl/shared_ptr.h) and linked_ptr have similar + // interfaces. The former dynamically allocates a chunk of memory + // to hold the reference count, while the latter tracks all + // references using a circular linked list without allocating + // memory. It has been observed that linked_ptr performs better in + // typical scenarios. However, shared_ptr can out-perform + // linked_ptr when there are many more uses of the copy constructor + // than the default constructor. + // + // If performance becomes a problem, we should see if using + // shared_ptr helps. + ::testing::internal::linked_ptr< + const MatcherInterface > + impl_; }; } // namespace internal // A Matcher is a copyable and IMMUTABLE (except by assignment) // object that can check whether a value of type T matches. The -// implementation of Matcher is just a std::shared_ptr to const -// MatcherInterface. Don't inherit from Matcher! +// implementation of Matcher is just a linked_ptr to const +// MatcherInterface, so copying is fairly cheap. Don't inherit +// from Matcher! template class Matcher : public internal::MatcherBase { public: @@ -1573,7 +1586,7 @@ class MatchesRegexMatcher { } private: - const std::shared_ptr regex_; + const internal::linked_ptr regex_; const bool full_match_; GTEST_DISALLOW_ASSIGN_(MatchesRegexMatcher); diff --git a/googlemock/include/gmock/gmock-spec-builders.h b/googlemock/include/gmock/gmock-spec-builders.h index 7759cb3..5d4b73b 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -62,7 +62,6 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ #include -#include #include #include #include @@ -220,7 +219,8 @@ class GTEST_API_ UntypedFunctionMockerBase { protected: typedef std::vector UntypedOnCallSpecs; - using UntypedExpectations = std::vector>; + typedef std::vector > + UntypedExpectations; // Returns an Expectation object that references and co-owns exp, // which must be an expectation on this mock function. @@ -498,7 +498,12 @@ class GTEST_API_ Mock { // - Constness is shallow: a const Expectation object itself cannot // be modified, but the mutable methods of the ExpectationBase // object it references can be called via expectation_base(). - +// - The constructors and destructor are defined out-of-line because +// the Symbian WINSCW compiler wants to otherwise instantiate them +// when it sees this class definition, at which point it doesn't have +// ExpectationBase available yet, leading to incorrect destruction +// in the linked_ptr (or compilation errors if using a checking +// linked_ptr). class GTEST_API_ Expectation { public: // Constructs a null object that doesn't reference any expectation. @@ -550,15 +555,16 @@ class GTEST_API_ Expectation { typedef ::std::set Set; Expectation( - const std::shared_ptr& expectation_base); + const internal::linked_ptr& expectation_base); // Returns the expectation this object references. - const std::shared_ptr& expectation_base() const { + const internal::linked_ptr& + expectation_base() const { return expectation_base_; } - // A shared_ptr that co-owns the expectation this handle references. - std::shared_ptr expectation_base_; + // A linked_ptr that co-owns the expectation this handle references. + internal::linked_ptr expectation_base_; }; // A set of expectation handles. Useful in the .After() clause of @@ -640,8 +646,11 @@ class GTEST_API_ Sequence { void AddExpectation(const Expectation& expectation) const; private: - // The last expectation in this sequence. - std::shared_ptr last_expectation_; + // The last expectation in this sequence. We use a linked_ptr here + // because Sequence objects are copyable and we want the copies to + // be aliases. The linked_ptr allows the copies to co-own and share + // the same Expectation object. + internal::linked_ptr last_expectation_; }; // class Sequence // An object of this type causes all EXPECT_CALL() statements @@ -864,7 +873,7 @@ class GTEST_API_ ExpectationBase { Cardinality cardinality_; // The cardinality of the expectation. // The immediate pre-requisites (i.e. expectations that must be // satisfied before this expectation can be matched) of this - // expectation. We use std::shared_ptr in the set because we want an + // expectation. We use linked_ptr in the set because we want an // Expectation object to be co-owned by its FunctionMocker and its // successors. This allows multiple mock objects to be deleted at // different times. @@ -1622,7 +1631,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); TypedExpectation* const expectation = new TypedExpectation(this, file, line, source_text, m); - const std::shared_ptr untyped_expectation(expectation); + const linked_ptr untyped_expectation(expectation); // See the definition of untyped_expectations_ for why access to // it is unprotected here. untyped_expectations_.push_back(untyped_expectation); diff --git a/googlemock/include/gmock/internal/gmock-internal-utils.h b/googlemock/include/gmock/internal/gmock-internal-utils.h index 7514635..fd33c00 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -92,6 +92,15 @@ inline const typename Pointer::element_type* GetRawPointer(const Pointer& p) { template inline Element* GetRawPointer(Element* p) { return p; } +// This comparator allows linked_ptr to be stored in sets. +template +struct LinkedPtrLessThan { + bool operator()(const ::testing::internal::linked_ptr& lhs, + const ::testing::internal::linked_ptr& rhs) const { + return lhs.get() < rhs.get(); + } +}; + // Symbian compilation can be done with wchar_t being either a native // type or a typedef. Using Google Mock with OpenC without wchar_t // should require the definition of _STLP_NO_WCHAR_T. diff --git a/googlemock/include/gmock/internal/gmock-port.h b/googlemock/include/gmock/internal/gmock-port.h index c593249..fda27db 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -52,6 +52,7 @@ // here, as Google Mock depends on Google Test. Only add a utility // here if it's truly specific to Google Mock. +#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gmock/internal/custom/gmock-port.h" diff --git a/googlemock/src/gmock-spec-builders.cc b/googlemock/src/gmock-spec-builders.cc index c93b2b5..5c20ed1 100644 --- a/googlemock/src/gmock-spec-builders.cc +++ b/googlemock/src/gmock-spec-builders.cc @@ -38,7 +38,6 @@ #include #include // NOLINT #include -#include #include #include #include @@ -849,7 +848,7 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) Expectation::Expectation() {} Expectation::Expectation( - const std::shared_ptr& an_expectation_base) + const internal::linked_ptr& an_expectation_base) : expectation_base_(an_expectation_base) {} Expectation::~Expectation() {} diff --git a/googlemock/test/gmock-generated-actions_test.cc b/googlemock/test/gmock-generated-actions_test.cc index 3111d85..2d663a5 100644 --- a/googlemock/test/gmock-generated-actions_test.cc +++ b/googlemock/test/gmock-generated-actions_test.cc @@ -35,7 +35,6 @@ #include "gmock/gmock-generated-actions.h" #include -#include #include #include #include "gmock/gmock.h" @@ -1130,9 +1129,9 @@ ACTION_TEMPLATE(ReturnSmartPointer, } TEST(ActionTemplateTest, WorksForTemplateTemplateParameters) { - const Action()> a = - ReturnSmartPointer(42); - std::shared_ptr p = a.Perform(std::make_tuple()); + using ::testing::internal::linked_ptr; + const Action()> a = ReturnSmartPointer(42); + linked_ptr p = a.Perform(std::make_tuple()); EXPECT_EQ(42, *p); } @@ -1162,10 +1161,11 @@ ACTION_TEMPLATE(ReturnGiant, } TEST(ActionTemplateTest, WorksFor10TemplateParameters) { - using Giant = GiantTemplate, bool, double, 5, true, 6, - char, unsigned, int>; - const Action a = ReturnGiant(42); + using ::testing::internal::linked_ptr; + typedef GiantTemplate, bool, double, 5, + true, 6, char, unsigned, int> Giant; + const Action a = ReturnGiant< + int, bool, double, 5, true, 6, char, unsigned, int, linked_ptr>(42); Giant giant = a.Perform(std::make_tuple()); EXPECT_EQ(42, giant.value); } diff --git a/googlemock/test/gmock-internal-utils_test.cc b/googlemock/test/gmock-internal-utils_test.cc index aa0162b..41498f0 100644 --- a/googlemock/test/gmock-internal-utils_test.cc +++ b/googlemock/test/gmock-internal-utils_test.cc @@ -123,6 +123,8 @@ TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) { } TEST(PointeeOfTest, WorksForSmartPointers) { + CompileAssertTypesEqual >::type>(); #if GTEST_HAS_STD_UNIQUE_PTR_ CompileAssertTypesEqual >::type>(); #endif // GTEST_HAS_STD_UNIQUE_PTR_ @@ -149,6 +151,10 @@ TEST(GetRawPointerTest, WorksForSmartPointers) { const std::shared_ptr p2(raw_p2); EXPECT_EQ(raw_p2, GetRawPointer(p2)); #endif // GTEST_HAS_STD_SHARED_PTR_ + + const char* const raw_p4 = new const char('a'); // NOLINT + const internal::linked_ptr p4(raw_p4); + EXPECT_EQ(raw_p4, GetRawPointer(p4)); } TEST(GetRawPointerTest, WorksForRawPointers) { @@ -681,7 +687,7 @@ TEST(StlContainerViewTest, WorksForDynamicNativeArray) { StlContainerView >::type>(); StaticAssertTypeEq< NativeArray, - StlContainerView, int> >::type>(); + StlContainerView, int> >::type>(); StaticAssertTypeEq< const NativeArray, diff --git a/googlemock/test/gmock-matchers_test.cc b/googlemock/test/gmock-matchers_test.cc index 45006bf..f4e9e9f 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -143,11 +143,13 @@ using testing::internal::ExplainMatchFailureTupleTo; using testing::internal::FloatingEqMatcher; using testing::internal::FormatMatcherDescription; using testing::internal::IsReadableTypeName; +using testing::internal::linked_ptr; using testing::internal::MatchMatrix; using testing::internal::RE; using testing::internal::scoped_ptr; using testing::internal::StreamMatchResultListener; using testing::internal::Strings; +using testing::internal::linked_ptr; using testing::internal::scoped_ptr; using testing::internal::string; @@ -1175,6 +1177,24 @@ TEST(IsNullTest, MatchesNullPointer) { #endif } +TEST(IsNullTest, LinkedPtr) { + const Matcher > m = IsNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new int); + + EXPECT_TRUE(m.Matches(null_p)); + EXPECT_FALSE(m.Matches(non_null_p)); +} + +TEST(IsNullTest, ReferenceToConstLinkedPtr) { + const Matcher&> m = IsNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new double); + + EXPECT_TRUE(m.Matches(null_p)); + EXPECT_FALSE(m.Matches(non_null_p)); +} + #if GTEST_LANG_CXX11 TEST(IsNullTest, StdFunction) { const Matcher> m = IsNull(); @@ -1206,18 +1226,18 @@ TEST(NotNullTest, MatchesNonNullPointer) { } TEST(NotNullTest, LinkedPtr) { - const Matcher> m = NotNull(); - const std::shared_ptr null_p; - const std::shared_ptr non_null_p(new int); + const Matcher > m = NotNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new int); EXPECT_FALSE(m.Matches(null_p)); EXPECT_TRUE(m.Matches(non_null_p)); } TEST(NotNullTest, ReferenceToConstLinkedPtr) { - const Matcher&> m = NotNull(); - const std::shared_ptr null_p; - const std::shared_ptr non_null_p(new double); + const Matcher&> m = NotNull(); + const linked_ptr null_p; + const linked_ptr non_null_p(new double); EXPECT_FALSE(m.Matches(null_p)); EXPECT_TRUE(m.Matches(non_null_p)); diff --git a/googlemock/test/gmock-more-actions_test.cc b/googlemock/test/gmock-more-actions_test.cc index b4e0fc3..521f305 100644 --- a/googlemock/test/gmock-more-actions_test.cc +++ b/googlemock/test/gmock-more-actions_test.cc @@ -35,11 +35,11 @@ #include "gmock/gmock-more-actions.h" #include -#include #include #include #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "gtest/internal/gtest-linked_ptr.h" namespace testing { namespace gmock_more_actions_test { @@ -61,6 +61,7 @@ using testing::StaticAssertTypeEq; using testing::Unused; using testing::WithArg; using testing::WithoutArgs; +using testing::internal::linked_ptr; // For suppressing compiler warnings on conversion possibly losing precision. inline short Short(short n) { return n; } // NOLINT @@ -528,6 +529,14 @@ TEST(SaveArgPointeeActionTest, WorksForCompatibleType) { EXPECT_EQ('a', result); } +TEST(SaveArgPointeeActionTest, WorksForLinkedPtr) { + int result = 0; + linked_ptr value(new int(5)); + const Action)> a1 = SaveArgPointee<0>(&result); + a1.Perform(std::make_tuple(value)); + EXPECT_EQ(5, result); +} + TEST(SetArgRefereeActionTest, WorksForSameType) { int value = 0; const Action a1 = SetArgReferee<0>(1); diff --git a/googlemock/test/gmock-spec-builders_test.cc b/googlemock/test/gmock-spec-builders_test.cc index 6502be7..65c9fcc 100644 --- a/googlemock/test/gmock-spec-builders_test.cc +++ b/googlemock/test/gmock-spec-builders_test.cc @@ -34,7 +34,6 @@ #include "gmock/gmock-spec-builders.h" -#include #include // NOLINT #include #include @@ -100,6 +99,7 @@ using testing::internal::kFail; using testing::internal::kInfoVerbosity; using testing::internal::kWarn; using testing::internal::kWarningVerbosity; +using testing::internal::linked_ptr; #if GTEST_HAS_STREAM_REDIRECTION using testing::HasSubstr; @@ -172,7 +172,7 @@ class ReferenceHoldingMock { public: ReferenceHoldingMock() {} - MOCK_METHOD1(AcceptReference, void(std::shared_ptr*)); + MOCK_METHOD1(AcceptReference, void(linked_ptr*)); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ReferenceHoldingMock); @@ -2619,7 +2619,7 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) { TEST(VerifyAndClearTest, DestroyingChainedMocksDoesNotDeadlockThroughExpectations) { - std::shared_ptr a(new MockA); + linked_ptr a(new MockA); ReferenceHoldingMock test_mock; // EXPECT_CALL stores a reference to a inside test_mock. @@ -2639,7 +2639,7 @@ TEST(VerifyAndClearTest, TEST(VerifyAndClearTest, DestroyingChainedMocksDoesNotDeadlockThroughDefaultAction) { - std::shared_ptr a(new MockA); + linked_ptr a(new MockA); ReferenceHoldingMock test_mock; // ON_CALL stores a reference to a inside test_mock. diff --git a/googlemock/test/gmock_stress_test.cc b/googlemock/test/gmock_stress_test.cc index 20725d6..9ae0b1e 100644 --- a/googlemock/test/gmock_stress_test.cc +++ b/googlemock/test/gmock_stress_test.cc @@ -60,8 +60,87 @@ void JoinAndDelete(ThreadWithParam* t) { delete t; } +using internal::linked_ptr; + +// Helper classes for testing using linked_ptr concurrently. + +class Base { + public: + explicit Base(int a_x) : x_(a_x) {} + virtual ~Base() {} + int x() const { return x_; } + private: + int x_; +}; + +class Derived1 : public Base { + public: + Derived1(int a_x, int a_y) : Base(a_x), y_(a_y) {} + int y() const { return y_; } + private: + int y_; +}; + +class Derived2 : public Base { + public: + Derived2(int a_x, int a_z) : Base(a_x), z_(a_z) {} + int z() const { return z_; } + private: + int z_; +}; + +linked_ptr pointer1(new Derived1(1, 2)); +linked_ptr pointer2(new Derived2(3, 4)); + struct Dummy {}; +// Tests that we can copy from a linked_ptr and read it concurrently. +void TestConcurrentCopyAndReadLinkedPtr(Dummy /* dummy */) { + // Reads pointer1 and pointer2 while they are being copied from in + // another thread. + EXPECT_EQ(1, pointer1->x()); + EXPECT_EQ(2, pointer1->y()); + EXPECT_EQ(3, pointer2->x()); + EXPECT_EQ(4, pointer2->z()); + + // Copies from pointer1. + linked_ptr p1(pointer1); + EXPECT_EQ(1, p1->x()); + EXPECT_EQ(2, p1->y()); + + // Assigns from pointer2 where the LHS was empty. + linked_ptr p2; + p2 = pointer1; + EXPECT_EQ(1, p2->x()); + + // Assigns from pointer2 where the LHS was not empty. + p2 = pointer2; + EXPECT_EQ(3, p2->x()); +} + +const linked_ptr p0(new Derived1(1, 2)); + +// Tests that we can concurrently modify two linked_ptrs that point to +// the same object. +void TestConcurrentWriteToEqualLinkedPtr(Dummy /* dummy */) { + // p1 and p2 point to the same, shared thing. One thread resets p1. + // Another thread assigns to p2. This will cause the same + // underlying "ring" to be updated concurrently. + linked_ptr p1(p0); + linked_ptr p2(p0); + + EXPECT_EQ(1, p1->x()); + EXPECT_EQ(2, p1->y()); + + EXPECT_EQ(1, p2->x()); + EXPECT_EQ(2, p2->y()); + + p1.reset(); + p2 = p0; + + EXPECT_EQ(1, p2->x()); + EXPECT_EQ(2, p2->y()); +} // Tests that different mock objects can be used in their respective // threads. This should generate no Google Test failure. @@ -196,6 +275,8 @@ void TestPartiallyOrderedExpectationsWithThreads(Dummy /* dummy */) { // Tests using Google Mock constructs in many threads concurrently. TEST(StressTest, CanUseGMockWithThreads) { void (*test_routines[])(Dummy dummy) = { + &TestConcurrentCopyAndReadLinkedPtr, + &TestConcurrentWriteToEqualLinkedPtr, &TestConcurrentMockObjects, &TestConcurrentCallsOnSameObject, &TestPartiallyOrderedExpectationsWithThreads, diff --git a/googletest/CMakeLists.txt b/googletest/CMakeLists.txt index e33718b..4c0d648 100644 --- a/googletest/CMakeLists.txt +++ b/googletest/CMakeLists.txt @@ -195,6 +195,7 @@ $env:Path = \"$project_bin;$env:Path\" cxx_test(googletest-death-test-test gtest_main) cxx_test(gtest_environment_test gtest) cxx_test(googletest-filepath-test gtest_main) + cxx_test(googletest-linked-ptr-test gtest_main) cxx_test(googletest-listener-test gtest_main) cxx_test(gtest_main_unittest gtest_main) cxx_test(googletest-message-test gtest_main) diff --git a/googletest/include/gtest/internal/gtest-linked_ptr.h b/googletest/include/gtest/internal/gtest-linked_ptr.h new file mode 100644 index 0000000..d25f7e9 --- /dev/null +++ b/googletest/include/gtest/internal/gtest-linked_ptr.h @@ -0,0 +1,243 @@ +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// FIXME: rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +// GOOGLETEST_CM0001 DO NOT DELETE + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + +#include "gtest/internal/gtest-port.h" + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + void join(linked_ptr_internal const* ptr) + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) { + assert(p->next_ != this && + "Trying to join() a linked ring we are already in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + bool depart() + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) { + assert(p->next_ != next_ && + "Trying to depart() a linked ring we are not in. " + "Is GMock thread safety enabled?"); + p = p->next_; + } + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = nullptr) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = nullptr) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ diff --git a/googletest/include/gtest/internal/gtest-param-util-generated.h b/googletest/include/gtest/internal/gtest-param-util-generated.h index f3c1e16..78bf65f 100644 --- a/googletest/include/gtest/internal/gtest-param-util-generated.h +++ b/googletest/include/gtest/internal/gtest-param-util-generated.h @@ -47,8 +47,6 @@ #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#include - #include "gtest/internal/gtest-param-util.h" #include "gtest/internal/gtest-port.h" @@ -164,7 +162,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -295,7 +293,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -445,7 +443,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -611,7 +609,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -795,7 +793,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -997,7 +995,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -1218,7 +1216,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -1456,7 +1454,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -1711,7 +1709,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. diff --git a/googletest/include/gtest/internal/gtest-param-util-generated.h.pump b/googletest/include/gtest/internal/gtest-param-util-generated.h.pump index 5dea7b2..67d1b34 100644 --- a/googletest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/googletest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -43,8 +43,6 @@ $var maxtuple = 10 $$ Maximum number of Combine arguments we want to support. // GOOGLETEST_CM0001 DO NOT DELETE -#include - #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ @@ -175,7 +173,7 @@ $for j [[ typename ParamGenerator::iterator current$(j)_; ]] - std::shared_ptr current_value_; + linked_ptr current_value_; }; // class CartesianProductGenerator$i::Iterator // No implementation - assignment is unsupported. diff --git a/googletest/include/gtest/internal/gtest-param-util.h b/googletest/include/gtest/internal/gtest-param-util.h index 9eb98b1..d5d4da9 100644 --- a/googletest/include/gtest/internal/gtest-param-util.h +++ b/googletest/include/gtest/internal/gtest-param-util.h @@ -38,13 +38,13 @@ #include #include -#include #include #include #include #include #include "gtest/internal/gtest-internal.h" +#include "gtest/internal/gtest-linked_ptr.h" #include "gtest/internal/gtest-port.h" #include "gtest/gtest-printers.h" @@ -193,7 +193,7 @@ class ParamGenerator { iterator end() const { return iterator(impl_->End()); } private: - std::shared_ptr > impl_; + linked_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -519,8 +519,9 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { - tests_.push_back(std::shared_ptr( - new TestInfo(test_case_name, test_base_name, meta_factory))); + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. @@ -540,7 +541,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - std::shared_ptr test_info = *test_it; + linked_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { @@ -604,7 +605,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { const std::string test_base_name; const scoped_ptr > test_meta_factory; }; - using TestInfoContainer = ::std::vector >; + typedef ::std::vector > TestInfoContainer; // Records data received from INSTANTIATE_TEST_CASE_P macros: // diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index 082aaff..aa98ddb 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -31,11 +31,10 @@ #include "gtest/internal/gtest-port.h" #include -#include #include +#include #include #include -#include #if GTEST_OS_WINDOWS # include @@ -476,7 +475,7 @@ class ThreadLocalRegistryImpl { thread_local_values .insert(std::make_pair( thread_local_instance, - std::shared_ptr( + linked_ptr( thread_local_instance->NewValueForCurrentThread()))) .first; } @@ -485,7 +484,7 @@ class ThreadLocalRegistryImpl { static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { - std::vector > value_holders; + std::vector > value_holders; // Clean up the ThreadLocalValues data structure while holding the lock, but // defer the destruction of the ThreadLocalValueHolderBases. { @@ -513,7 +512,7 @@ class ThreadLocalRegistryImpl { static void OnThreadExit(DWORD thread_id) { GTEST_CHECK_(thread_id != 0) << ::GetLastError(); - std::vector > value_holders; + std::vector > value_holders; // Clean up the ThreadIdToThreadLocals data structure while holding the // lock, but defer the destruction of the ThreadLocalValueHolderBases. { @@ -540,8 +539,7 @@ class ThreadLocalRegistryImpl { private: // In a particular thread, maps a ThreadLocal object to its value. typedef std::map > - ThreadLocalValues; + linked_ptr > ThreadLocalValues; // Stores all ThreadIdToThreadLocals having values in a thread, indexed by // thread's ID. typedef std::map ThreadIdToThreadLocals; diff --git a/googletest/src/gtest.cc b/googletest/src/gtest.cc index afd7d1b..332b3e9 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -423,6 +423,9 @@ void AssertHelper::operator=(const Message& message) const { ); // NOLINT } +// Mutex for linked pointers. +GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + // A copy of all command line arguments. Set by InitGoogleTest(). static ::std::vector g_argvs; diff --git a/googletest/test/googletest-linked-ptr-test.cc b/googletest/test/googletest-linked-ptr-test.cc new file mode 100644 index 0000000..f680253 --- /dev/null +++ b/googletest/test/googletest-linked-ptr-test.cc @@ -0,0 +1,151 @@ +// Copyright 2003, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include + +#include "gtest/internal/gtest-linked_ptr.h" +#include "gtest/gtest.h" + +namespace { + +using testing::Message; +using testing::internal::linked_ptr; + +int num; +Message* history = nullptr; + +// Class which tracks allocation/deallocation +class A { + public: + A(): mynum(num++) { *history << "A" << mynum << " ctor\n"; } + virtual ~A() { *history << "A" << mynum << " dtor\n"; } + virtual void Use() { *history << "A" << mynum << " use\n"; } + protected: + int mynum; +}; + +// Subclass +class B : public A { + public: + B() { *history << "B" << mynum << " ctor\n"; } + ~B() { *history << "B" << mynum << " dtor\n"; } + virtual void Use() { *history << "B" << mynum << " use\n"; } +}; + +class LinkedPtrTest : public testing::Test { + public: + LinkedPtrTest() { + num = 0; + history = new Message; + } + + virtual ~LinkedPtrTest() { + delete history; + history = nullptr; + } +}; + +TEST_F(LinkedPtrTest, GeneralTest) { + { + linked_ptr a0, a1, a2; + // Use explicit function call notation here to suppress self-assign warning. + a0.operator=(a0); + a1 = a2; + ASSERT_EQ(a0.get(), static_cast(nullptr)); + ASSERT_EQ(a1.get(), static_cast(nullptr)); + ASSERT_EQ(a2.get(), static_cast(nullptr)); + ASSERT_TRUE(a0 == nullptr); + ASSERT_TRUE(a1 == nullptr); + ASSERT_TRUE(a2 == nullptr); + + { + linked_ptr a3(new A); + a0 = a3; + ASSERT_TRUE(a0 == a3); + ASSERT_TRUE(a0 != nullptr); + ASSERT_TRUE(a0.get() == a3); + ASSERT_TRUE(a0 == a3.get()); + linked_ptr a4(a0); + a1 = a4; + linked_ptr a5(new A); + ASSERT_TRUE(a5.get() != a3); + ASSERT_TRUE(a5 != a3.get()); + a2 = a5; + linked_ptr b0(new B); + linked_ptr a6(b0); + ASSERT_TRUE(b0 == a6); + ASSERT_TRUE(a6 == b0); + ASSERT_TRUE(b0 != nullptr); + a5 = b0; + a5 = b0; + a3->Use(); + a4->Use(); + a5->Use(); + a6->Use(); + b0->Use(); + (*b0).Use(); + b0.get()->Use(); + } + + a0->Use(); + a1->Use(); + a2->Use(); + + a1 = a2; + a2.reset(new A); + a0.reset(); + + linked_ptr a7; + } + + ASSERT_STREQ( + "A0 ctor\n" + "A1 ctor\n" + "A2 ctor\n" + "B2 ctor\n" + "A0 use\n" + "A0 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 use\n" + "B2 dtor\n" + "A2 dtor\n" + "A0 use\n" + "A0 use\n" + "A1 use\n" + "A3 ctor\n" + "A0 dtor\n" + "A3 dtor\n" + "A1 dtor\n", + history->GetString().c_str()); +} + +} // Unnamed namespace diff --git a/googletest/test/gtest_all_test.cc b/googletest/test/gtest_all_test.cc index 615b29b..f948a10 100644 --- a/googletest/test/gtest_all_test.cc +++ b/googletest/test/gtest_all_test.cc @@ -33,6 +33,7 @@ // Sometimes it's desirable to build most of Google Test's own tests // by compiling a single file. This file serves this purpose. #include "test/googletest-filepath-test.cc" +#include "test/googletest-linked-ptr-test.cc" #include "test/googletest-message-test.cc" #include "test/googletest-options-test.cc" #include "test/googletest-port-test.cc" -- cgit v0.12