From a50e4f05b3d84c6a014c59a24263328242cc8236 Mon Sep 17 00:00:00 2001 From: misterg Date: Wed, 24 Oct 2018 17:02:11 -0400 Subject: [PATCH 1/3] Googletest export Remove linked_ptr and use std::shared_ptr instead PiperOrigin-RevId: 218571466 --- googlemock/include/gmock/gmock-actions.h | 21 +- .../include/gmock/gmock-cardinalities.h | 8 +- .../include/gmock/gmock-generated-actions.h | 3 +- .../gmock/gmock-generated-actions.h.pump | 3 +- googlemock/include/gmock/gmock-matchers.h | 25 +- .../include/gmock/gmock-spec-builders.h | 31 +-- .../gmock/internal/gmock-internal-utils.h | 9 - .../include/gmock/internal/gmock-port.h | 1 - googlemock/src/gmock-spec-builders.cc | 3 +- .../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 ------------------ .../internal/gtest-param-util-generated.h | 20 +- .../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, 84 insertions(+), 624 deletions(-) delete mode 100644 googletest/include/gtest/internal/gtest-linked_ptr.h delete 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 d4af9490..e4af9d2d 100644 --- a/googlemock/include/gmock/gmock-actions.h +++ b/googlemock/include/gmock/gmock-actions.h @@ -42,6 +42,7 @@ #endif #include +#include #include #include @@ -346,9 +347,7 @@ 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 -// linked_ptr to const ActionInterface, so copying is fairly cheap. -// Don't inherit from Action! -// +// std::shared_ptr to const ActionInterface. 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. @@ -425,7 +424,7 @@ class Action { #if GTEST_LANG_CXX11 ::std::function fun_; #endif - internal::linked_ptr > impl_; + std::shared_ptr> impl_; }; // The PolymorphicAction class template makes it easy to implement a @@ -519,7 +518,7 @@ class ActionAdaptor : public ActionInterface { } private: - const internal::linked_ptr > impl_; + const std::shared_ptr> impl_; GTEST_DISALLOW_ASSIGN_(ActionAdaptor); }; @@ -601,7 +600,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 linked_ptr& value) + explicit Impl(const std::shared_ptr& value) : value_before_cast_(*value), value_(ImplicitCast_(value_before_cast_)) {} @@ -626,7 +625,7 @@ class ReturnAction { typedef typename Function::Result Result; typedef typename Function::ArgumentTuple ArgumentTuple; - explicit Impl(const linked_ptr& wrapper) + explicit Impl(const std::shared_ptr& wrapper) : performed_(false), wrapper_(wrapper) {} virtual Result Perform(const ArgumentTuple&) { @@ -638,12 +637,12 @@ class ReturnAction { private: bool performed_; - const linked_ptr wrapper_; + const std::shared_ptr wrapper_; GTEST_DISALLOW_ASSIGN_(Impl); }; - const linked_ptr value_; + const std::shared_ptr value_; GTEST_DISALLOW_ASSIGN_(ReturnAction); }; @@ -866,7 +865,7 @@ class SetArgumentPointeeAction { } private: - const internal::linked_ptr proto_; + const std::shared_ptr proto_; GTEST_DISALLOW_ASSIGN_(SetArgumentPointeeAction); }; @@ -931,7 +930,7 @@ class InvokeCallbackWithoutArgsAction { Result Perform(const ArgumentTuple&) const { return callback_->Run(); } private: - const internal::linked_ptr callback_; + const std::shared_ptr callback_; GTEST_DISALLOW_ASSIGN_(InvokeCallbackWithoutArgsAction); }; diff --git a/googlemock/include/gmock/gmock-cardinalities.h b/googlemock/include/gmock/gmock-cardinalities.h index f9169315..8fa25ebb 100644 --- a/googlemock/include/gmock/gmock-cardinalities.h +++ b/googlemock/include/gmock/gmock-cardinalities.h @@ -40,6 +40,7 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_CARDINALITIES_H_ #include +#include #include // NOLINT #include "gmock/internal/gmock-port.h" #include "gtest/gtest.h" @@ -81,9 +82,8 @@ 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 linked_ptr -// to const CardinalityInterface, so copying is fairly cheap. -// Don't inherit from Cardinality! +// be called. The implementation of Cardinality is just a std::shared_ptr +// to const CardinalityInterface. 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: - internal::linked_ptr impl_; + std::shared_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 0845b221..8966f05c 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h +++ b/googlemock/include/gmock/gmock-generated-actions.h @@ -41,6 +41,7 @@ #ifndef GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ #define GMOCK_INCLUDE_GMOCK_GMOCK_GENERATED_ACTIONS_H_ +#include #include #include "gmock/gmock-actions.h" @@ -348,7 +349,7 @@ class InvokeCallbackAction { callback_.get(), args); } private: - const linked_ptr callback_; + const std::shared_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 bc22be8e..09a39ca8 100644 --- a/googlemock/include/gmock/gmock-generated-actions.h.pump +++ b/googlemock/include/gmock/gmock-generated-actions.h.pump @@ -43,6 +43,7 @@ $$}} 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" @@ -118,7 +119,7 @@ class InvokeCallbackAction { callback_.get(), args); } private: - const linked_ptr callback_; + const std::shared_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 6e8bc036..95bc22c5 100644 --- a/googlemock/include/gmock/gmock-matchers.h +++ b/googlemock/include/gmock/gmock-matchers.h @@ -43,14 +43,15 @@ #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 @@ -338,29 +339,15 @@ class MatcherBase { virtual ~MatcherBase() {} private: - // 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_; + std::shared_ptr> 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 linked_ptr to const -// MatcherInterface, so copying is fairly cheap. Don't inherit -// from Matcher! +// implementation of Matcher is just a std::shared_ptr to const +// MatcherInterface. Don't inherit from Matcher! template class Matcher : public internal::MatcherBase { public: @@ -1586,7 +1573,7 @@ class MatchesRegexMatcher { } private: - const internal::linked_ptr regex_; + const std::shared_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 5d4b73ba..7759cb35 100644 --- a/googlemock/include/gmock/gmock-spec-builders.h +++ b/googlemock/include/gmock/gmock-spec-builders.h @@ -62,6 +62,7 @@ #define GMOCK_INCLUDE_GMOCK_GMOCK_SPEC_BUILDERS_H_ #include +#include #include #include #include @@ -219,8 +220,7 @@ class GTEST_API_ UntypedFunctionMockerBase { protected: typedef std::vector UntypedOnCallSpecs; - typedef std::vector > - UntypedExpectations; + using UntypedExpectations = std::vector>; // Returns an Expectation object that references and co-owns exp, // which must be an expectation on this mock function. @@ -498,12 +498,7 @@ 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. @@ -555,16 +550,15 @@ class GTEST_API_ Expectation { typedef ::std::set Set; Expectation( - const internal::linked_ptr& expectation_base); + const std::shared_ptr& expectation_base); // Returns the expectation this object references. - const internal::linked_ptr& - expectation_base() const { + const std::shared_ptr& expectation_base() const { return expectation_base_; } - // A linked_ptr that co-owns the expectation this handle references. - internal::linked_ptr expectation_base_; + // A shared_ptr that co-owns the expectation this handle references. + std::shared_ptr expectation_base_; }; // A set of expectation handles. Useful in the .After() clause of @@ -646,11 +640,8 @@ class GTEST_API_ Sequence { void AddExpectation(const Expectation& expectation) const; private: - // 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_; + // The last expectation in this sequence. + std::shared_ptr last_expectation_; }; // class Sequence // An object of this type causes all EXPECT_CALL() statements @@ -873,7 +864,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 linked_ptr in the set because we want an + // expectation. We use std::shared_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. @@ -1631,7 +1622,7 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { Mock::RegisterUseByOnCallOrExpectCall(MockObject(), file, line); TypedExpectation* const expectation = new TypedExpectation(this, file, line, source_text, m); - const linked_ptr untyped_expectation(expectation); + const std::shared_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 fd33c004..7514635e 100644 --- a/googlemock/include/gmock/internal/gmock-internal-utils.h +++ b/googlemock/include/gmock/internal/gmock-internal-utils.h @@ -92,15 +92,6 @@ 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 fda27dba..c5932493 100644 --- a/googlemock/include/gmock/internal/gmock-port.h +++ b/googlemock/include/gmock/internal/gmock-port.h @@ -52,7 +52,6 @@ // 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 5c20ed14..c93b2b5d 100644 --- a/googlemock/src/gmock-spec-builders.cc +++ b/googlemock/src/gmock-spec-builders.cc @@ -38,6 +38,7 @@ #include #include // NOLINT #include +#include #include #include #include @@ -848,7 +849,7 @@ void Mock::ClearDefaultActionsLocked(void* mock_obj) Expectation::Expectation() {} Expectation::Expectation( - const internal::linked_ptr& an_expectation_base) + const std::shared_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 2d663a5e..3111d859 100644 --- a/googlemock/test/gmock-generated-actions_test.cc +++ b/googlemock/test/gmock-generated-actions_test.cc @@ -35,6 +35,7 @@ #include "gmock/gmock-generated-actions.h" #include +#include #include #include #include "gmock/gmock.h" @@ -1129,9 +1130,9 @@ ACTION_TEMPLATE(ReturnSmartPointer, } TEST(ActionTemplateTest, WorksForTemplateTemplateParameters) { - using ::testing::internal::linked_ptr; - const Action()> a = ReturnSmartPointer(42); - linked_ptr p = a.Perform(std::make_tuple()); + const Action()> a = + ReturnSmartPointer(42); + std::shared_ptr p = a.Perform(std::make_tuple()); EXPECT_EQ(42, *p); } @@ -1161,11 +1162,10 @@ ACTION_TEMPLATE(ReturnGiant, } TEST(ActionTemplateTest, WorksFor10TemplateParameters) { - 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); + using Giant = GiantTemplate, bool, double, 5, true, 6, + char, unsigned, int>; + const Action a = ReturnGiant(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 41498f0e..aa0162b8 100644 --- a/googlemock/test/gmock-internal-utils_test.cc +++ b/googlemock/test/gmock-internal-utils_test.cc @@ -123,8 +123,6 @@ TEST(ConvertIdentifierNameToWordsTest, WorksWhenNameIsMixture) { } TEST(PointeeOfTest, WorksForSmartPointers) { - CompileAssertTypesEqual >::type>(); #if GTEST_HAS_STD_UNIQUE_PTR_ CompileAssertTypesEqual >::type>(); #endif // GTEST_HAS_STD_UNIQUE_PTR_ @@ -151,10 +149,6 @@ 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) { @@ -687,7 +681,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 f4e9e9f7..45006bfb 100644 --- a/googlemock/test/gmock-matchers_test.cc +++ b/googlemock/test/gmock-matchers_test.cc @@ -143,13 +143,11 @@ 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; @@ -1177,24 +1175,6 @@ 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(); @@ -1226,18 +1206,18 @@ TEST(NotNullTest, MatchesNonNullPointer) { } TEST(NotNullTest, LinkedPtr) { - const Matcher > m = NotNull(); - const linked_ptr null_p; - const linked_ptr non_null_p(new int); + const Matcher> m = NotNull(); + const std::shared_ptr null_p; + const std::shared_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 linked_ptr null_p; - const linked_ptr non_null_p(new double); + const Matcher&> m = NotNull(); + const std::shared_ptr null_p; + const std::shared_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 521f3058..b4e0fc30 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,7 +61,6 @@ 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 @@ -529,14 +528,6 @@ 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 65c9fcc4..6502be74 100644 --- a/googlemock/test/gmock-spec-builders_test.cc +++ b/googlemock/test/gmock-spec-builders_test.cc @@ -34,6 +34,7 @@ #include "gmock/gmock-spec-builders.h" +#include #include // NOLINT #include #include @@ -99,7 +100,6 @@ 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(linked_ptr*)); + MOCK_METHOD1(AcceptReference, void(std::shared_ptr*)); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ReferenceHoldingMock); @@ -2619,7 +2619,7 @@ TEST(VerifyAndClearTest, DoesNotAffectOtherMockObjects) { TEST(VerifyAndClearTest, DestroyingChainedMocksDoesNotDeadlockThroughExpectations) { - linked_ptr a(new MockA); + std::shared_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) { - linked_ptr a(new MockA); + std::shared_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 9ae0b1e5..20725d69 100644 --- a/googlemock/test/gmock_stress_test.cc +++ b/googlemock/test/gmock_stress_test.cc @@ -60,87 +60,8 @@ 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. @@ -275,8 +196,6 @@ 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 4c0d6487..e33718b1 100644 --- a/googletest/CMakeLists.txt +++ b/googletest/CMakeLists.txt @@ -195,7 +195,6 @@ $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 deleted file mode 100644 index d25f7e96..00000000 --- a/googletest/include/gtest/internal/gtest-linked_ptr.h +++ /dev/null @@ -1,243 +0,0 @@ -// 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 78bf65f6..f3c1e16e 100644 --- a/googletest/include/gtest/internal/gtest-param-util-generated.h +++ b/googletest/include/gtest/internal/gtest-param-util-generated.h @@ -47,6 +47,8 @@ #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" @@ -162,7 +164,7 @@ class CartesianProductGenerator2 const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. @@ -293,7 +295,7 @@ class CartesianProductGenerator3 const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. @@ -443,7 +445,7 @@ class CartesianProductGenerator4 const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. @@ -609,7 +611,7 @@ class CartesianProductGenerator5 const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. @@ -793,7 +795,7 @@ class CartesianProductGenerator6 const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. @@ -995,7 +997,7 @@ class CartesianProductGenerator7 const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. @@ -1216,7 +1218,7 @@ class CartesianProductGenerator8 const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. @@ -1454,7 +1456,7 @@ class CartesianProductGenerator9 const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; - linked_ptr current_value_; + std::shared_ptr current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. @@ -1709,7 +1711,7 @@ class CartesianProductGenerator10 const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; - linked_ptr current_value_; + std::shared_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 67d1b34b..5dea7b29 100644 --- a/googletest/include/gtest/internal/gtest-param-util-generated.h.pump +++ b/googletest/include/gtest/internal/gtest-param-util-generated.h.pump @@ -43,6 +43,8 @@ $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_ @@ -173,7 +175,7 @@ $for j [[ typename ParamGenerator::iterator current$(j)_; ]] - linked_ptr current_value_; + std::shared_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 d5d4da95..9eb98b16 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: - linked_ptr > impl_; + std::shared_ptr > impl_; }; // Generates values from a range of two comparable values. Can be used to @@ -519,9 +519,8 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { void AddTestPattern(const char* test_case_name, const char* test_base_name, TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); + tests_.push_back(std::shared_ptr( + new TestInfo(test_case_name, test_base_name, meta_factory))); } // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information // about a generator. @@ -541,7 +540,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { virtual void RegisterTests() { for (typename TestInfoContainer::iterator test_it = tests_.begin(); test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; + std::shared_ptr test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { @@ -605,7 +604,7 @@ class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { const std::string test_base_name; const scoped_ptr > test_meta_factory; }; - typedef ::std::vector > TestInfoContainer; + using TestInfoContainer = ::std::vector >; // Records data received from INSTANTIATE_TEST_CASE_P macros: // diff --git a/googletest/src/gtest-port.cc b/googletest/src/gtest-port.cc index aa98ddb1..082aaff4 100644 --- a/googletest/src/gtest-port.cc +++ b/googletest/src/gtest-port.cc @@ -31,10 +31,11 @@ #include "gtest/internal/gtest-port.h" #include -#include #include +#include #include #include +#include #if GTEST_OS_WINDOWS # include @@ -475,7 +476,7 @@ class ThreadLocalRegistryImpl { thread_local_values .insert(std::make_pair( thread_local_instance, - linked_ptr( + std::shared_ptr( thread_local_instance->NewValueForCurrentThread()))) .first; } @@ -484,7 +485,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. { @@ -512,7 +513,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. { @@ -539,7 +540,8 @@ class ThreadLocalRegistryImpl { private: // In a particular thread, maps a ThreadLocal object to its value. typedef std::map > ThreadLocalValues; + std::shared_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 332b3e9b..afd7d1be 100644 --- a/googletest/src/gtest.cc +++ b/googletest/src/gtest.cc @@ -423,9 +423,6 @@ 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 deleted file mode 100644 index f6802534..00000000 --- a/googletest/test/googletest-linked-ptr-test.cc +++ /dev/null @@ -1,151 +0,0 @@ -// 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 f948a104..615b29b7 100644 --- a/googletest/test/gtest_all_test.cc +++ b/googletest/test/gtest_all_test.cc @@ -33,7 +33,6 @@ // 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" From b57c703963be1ca9749b902c49083beac56648aa Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 24 Oct 2018 22:04:43 -0400 Subject: [PATCH 2/3] Googletest export Remove linked_ptr and use std::shared_ptr instead PiperOrigin-RevId: 218618184 --- googlemock/include/gmock/gmock-actions.h | 21 +- .../include/gmock/gmock-cardinalities.h | 8 +- .../include/gmock/gmock-generated-actions.h | 3 +- .../gmock/gmock-generated-actions.h.pump | 3 +- googlemock/include/gmock/gmock-matchers.h | 25 +- .../include/gmock/gmock-spec-builders.h | 31 ++- .../gmock/internal/gmock-internal-utils.h | 9 + .../include/gmock/internal/gmock-port.h | 1 + googlemock/src/gmock-spec-builders.cc | 3 +- .../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 ++++++++++++++++++ .../internal/gtest-param-util-generated.h | 20 +- .../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 e4af9d2d..d4af9490 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 8fa25ebb..f9169315 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 8966f05c..0845b221 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 09a39ca8..bc22be8e 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 95bc22c5..6e8bc036 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 7759cb35..5d4b73ba 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 7514635e..fd33c004 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 c5932493..fda27dba 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 c93b2b5d..5c20ed14 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 3111d859..2d663a5e 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 aa0162b8..41498f0e 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 45006bfb..f4e9e9f7 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 b4e0fc30..521f3058 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 6502be74..65c9fcc4 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 20725d69..9ae0b1e5 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 e33718b1..4c0d6487 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 00000000..d25f7e96 --- /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 f3c1e16e..78bf65f6 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 5dea7b29..67d1b34b 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 9eb98b16..d5d4da95 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 082aaff4..aa98ddb1 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 afd7d1be..332b3e9b 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 00000000..f6802534 --- /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 615b29b7..f948a104 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" From 2e308484d9693f8251748c295f6ed7ed25d767eb Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Fri, 26 Oct 2018 16:19:25 -0400 Subject: [PATCH 3/3] Googletest export [Fuchsia] Make the child process stderr redirection use a socket. This changes the stderr redirection mechanism for the child process in Fuchsia death tests to use a Zircon socket rather than fd redirection. This should improve performance and reliability of the redirection process. This also includes some minor style cleanups. PiperOrigin-RevId: 218903196 --- googletest/src/gtest-death-test.cc | 160 +++++++++++++++++++---------- 1 file changed, 108 insertions(+), 52 deletions(-) diff --git a/googletest/src/gtest-death-test.cc b/googletest/src/gtest-death-test.cc index b3a572a1..2c15fdcc 100644 --- a/googletest/src/gtest-death-test.cc +++ b/googletest/src/gtest-death-test.cc @@ -64,6 +64,10 @@ # if GTEST_OS_FUCHSIA # include # include +# include +# include +# include +# include # include # include # include @@ -422,6 +426,9 @@ class DeathTestImpl : public DeathTest { // case of unexpected codes. void ReadAndInterpretStatusByte(); + // Returns stderr output from the child process. + virtual std::string GetErrorLogs(); + private: // The textual content of the code this object is testing. This class // doesn't own this string and should not attempt to delete it. @@ -490,6 +497,10 @@ void DeathTestImpl::ReadAndInterpretStatusByte() { set_read_fd(-1); } +std::string DeathTestImpl::GetErrorLogs() { + return GetCapturedStderr(); +} + // Signals that the death test code which should have exited, didn't. // Should be called only in a death test child process. // Writes a status byte to the child's status file descriptor, then @@ -558,7 +569,7 @@ bool DeathTestImpl::Passed(bool status_ok) { if (!spawned()) return false; - const std::string error_message = GetCapturedStderr(); + const std::string error_message = GetErrorLogs(); bool success = false; Message buffer; @@ -810,12 +821,6 @@ class FuchsiaDeathTest : public DeathTestImpl { const char* file, int line) : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - virtual ~FuchsiaDeathTest() { - zx_status_t status = zx_handle_close(child_process_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_handle_close(port_); - GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - } // All of these virtual functions are inherited from DeathTest. virtual int Wait(); @@ -826,9 +831,12 @@ class FuchsiaDeathTest : public DeathTestImpl { const char* const file_; // The line number on which the death test is located. const int line_; + // The stderr data captured by the child process. + std::string captured_stderr_; - zx_handle_t child_process_ = ZX_HANDLE_INVALID; - zx_handle_t port_ = ZX_HANDLE_INVALID; + zx::process child_process_; + zx::port port_; + zx::socket stderr_socket_; }; // Utility class for accumulating command-line arguments. @@ -872,51 +880,74 @@ class Arguments { // status, or 0 if no child process exists. As a side effect, sets the // outcome data member. int FuchsiaDeathTest::Wait() { + const int kProcessKey = 0; + const int kSocketKey = 1; + if (!spawned()) return 0; // Register to wait for the child process to terminate. zx_status_t status_zx; - status_zx = zx_object_wait_async(child_process_, - port_, - 0 /* key */, - ZX_PROCESS_TERMINATED, - ZX_WAIT_ASYNC_ONCE); + status_zx = child_process_.wait_async( + port_, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + // Register to wait for the socket to be readable or closed. + status_zx = stderr_socket_.wait_async( + port_, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, + ZX_WAIT_ASYNC_REPEATING); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Wait for it to terminate, or an exception to be received. - zx_port_packet_t packet; - status_zx = zx_port_wait(port_, ZX_TIME_INFINITE, &packet); - GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - - if (ZX_PKT_IS_EXCEPTION(packet.type)) { - // Process encountered an exception. Kill it directly rather than letting - // other handlers process the event. - status_zx = zx_task_kill(child_process_); + bool process_terminated = false; + bool socket_closed = false; + do { + zx_port_packet_t packet = {}; + status_zx = port_.wait(zx::time::infinite(), &packet); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - // Now wait for |child_process_| to terminate. - zx_signals_t signals = 0; - status_zx = zx_object_wait_one( - child_process_, ZX_PROCESS_TERMINATED, ZX_TIME_INFINITE, &signals); - GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); - GTEST_DEATH_TEST_CHECK_(signals & ZX_PROCESS_TERMINATED); - } else { - // Process terminated. - GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); - GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); - } + if (packet.key == kProcessKey) { + if (ZX_PKT_IS_EXCEPTION(packet.type)) { + // Process encountered an exception. Kill it directly rather than + // letting other handlers process the event. We will get a second + // kProcessKey event when the process actually terminates. + status_zx = child_process_.kill(); + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); + } else { + // Process terminated. + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_ONE(packet.type)); + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_PROCESS_TERMINATED); + process_terminated = true; + } + } else if (packet.key == kSocketKey) { + GTEST_DEATH_TEST_CHECK_(ZX_PKT_IS_SIGNAL_REP(packet.type)); + if (packet.signal.observed & ZX_SOCKET_READABLE) { + // Read data from the socket. + constexpr size_t kBufferSize = 1024; + do { + size_t old_length = captured_stderr_.length(); + size_t bytes_read = 0; + captured_stderr_.resize(old_length + kBufferSize); + status_zx = stderr_socket_.read( + 0, &captured_stderr_.front() + old_length, kBufferSize, + &bytes_read); + captured_stderr_.resize(old_length + bytes_read); + } while (status_zx == ZX_OK); + if (status_zx == ZX_ERR_PEER_CLOSED) { + socket_closed = true; + } else { + GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); + } + } else { + GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); + socket_closed = true; + } + } + } while (!process_terminated && !socket_closed); ReadAndInterpretStatusByte(); zx_info_process_t buffer; - status_zx = zx_object_get_info( - child_process_, - ZX_INFO_PROCESS, - &buffer, - sizeof(buffer), - nullptr, - nullptr); + status_zx = child_process_.get_info( + ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); GTEST_DEATH_TEST_CHECK_(buffer.exited); @@ -943,7 +974,6 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { return EXECUTE_TEST; } - CaptureStderr(); // Flush the log buffers since the log streams are shared with the child. FlushInfoLog(); @@ -970,29 +1000,55 @@ DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { set_read_fd(status); // Set the pipe handle for the child. - fdio_spawn_action_t add_handle_action = {}; - add_handle_action.action = FDIO_SPAWN_ACTION_ADD_HANDLE; - add_handle_action.h.id = PA_HND(type, kFuchsiaReadPipeFd); - add_handle_action.h.handle = child_pipe_handle; + fdio_spawn_action_t spawn_actions[2] = {}; + fdio_spawn_action_t* add_handle_action = &spawn_actions[0]; + add_handle_action->action = FDIO_SPAWN_ACTION_ADD_HANDLE; + add_handle_action->h.id = PA_HND(type, kFuchsiaReadPipeFd); + add_handle_action->h.handle = child_pipe_handle; + + // Create a socket pair will be used to receive the child process' stderr. + zx::socket stderr_producer_socket; + status = + zx::socket::create(0, &stderr_producer_socket, &stderr_socket_); + GTEST_DEATH_TEST_CHECK_(status >= 0); + int stderr_producer_fd = -1; + zx_handle_t producer_handle[1] = { stderr_producer_socket.release() }; + uint32_t producer_handle_type[1] = { PA_FDIO_SOCKET }; + status = fdio_create_fd( + producer_handle, producer_handle_type, 1, &stderr_producer_fd); + GTEST_DEATH_TEST_CHECK_(status >= 0); + + // Make the stderr socket nonblocking. + GTEST_DEATH_TEST_CHECK_(fcntl(stderr_producer_fd, F_SETFL, 0) == 0); + + fdio_spawn_action_t* add_stderr_action = &spawn_actions[1]; + add_stderr_action->action = FDIO_SPAWN_ACTION_CLONE_FD; + add_stderr_action->fd.local_fd = stderr_producer_fd; + add_stderr_action->fd.target_fd = STDERR_FILENO; // Spawn the child process. - status = fdio_spawn_etc(ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, - args.Argv()[0], args.Argv(), nullptr, 1, - &add_handle_action, &child_process_, nullptr); + status = fdio_spawn_etc( + ZX_HANDLE_INVALID, FDIO_SPAWN_CLONE_ALL, args.Argv()[0], args.Argv(), + nullptr, 2, spawn_actions, child_process_.reset_and_get_address(), + nullptr); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); // Create an exception port and attach it to the |child_process_|, to allow // us to suppress the system default exception handler from firing. - status = zx_port_create(0, &port_); + status = zx::port::create(0, &port_); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); - status = zx_task_bind_exception_port( - child_process_, port_, 0 /* key */, 0 /*options */); + status = child_process_.bind_exception_port( + port_, 0 /* key */, 0 /*options */); GTEST_DEATH_TEST_CHECK_(status == ZX_OK); set_spawned(true); return OVERSEE_TEST; } +std::string FuchsiaDeathTest::GetErrorLogs() { + return captured_stderr_; +} + #else // We are neither on Windows, nor on Fuchsia. // ForkingDeathTest provides implementations for most of the abstract