IGNITE-2981: CPP: Added "EnableSharedFromThis" entity. This closes #636.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/f5f90ecc Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/f5f90ecc Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/f5f90ecc Branch: refs/heads/ignite-1786 Commit: f5f90ecc88f0f467442506089116a6a153c77b50 Parents: 0460a35 Author: Igor Sapego <[email protected]> Authored: Wed Apr 27 11:34:44 2016 +0300 Committer: vozerov-gridgain <[email protected]> Committed: Wed Apr 27 11:34:44 2016 +0300 ---------------------------------------------------------------------- .../common/include/ignite/common/concurrent.h | 176 ++++++++++++++++--- modules/platforms/cpp/common/src/concurrent.cpp | 13 +- .../cpp/core-test/src/concurrent_test.cpp | 93 ++++++++++ 3 files changed, 253 insertions(+), 29 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/f5f90ecc/modules/platforms/cpp/common/include/ignite/common/concurrent.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/common/include/ignite/common/concurrent.h b/modules/platforms/cpp/common/include/ignite/common/concurrent.h index a4cc3f7..1c84cf5 100644 --- a/modules/platforms/cpp/common/include/ignite/common/concurrent.h +++ b/modules/platforms/cpp/common/include/ignite/common/concurrent.h @@ -18,6 +18,8 @@ #ifndef _IGNITE_COMMON_CONCURRENT #define _IGNITE_COMMON_CONCURRENT +#include <cassert> + #include "ignite/common/concurrent_os.h" namespace ignite @@ -43,12 +45,13 @@ namespace ignite class IGNITE_IMPORT_EXPORT SharedPointerImpl { public: + typedef void(*DeleterType)(void*); /** * Constructor. * * @param ptr Raw pointer. */ - SharedPointerImpl(void* ptr); + SharedPointerImpl(void* ptr, DeleterType deleter); /** * Get raw pointer. @@ -65,6 +68,13 @@ namespace ignite const void* Pointer() const; /** + * Get raw pointer. + * + * @return Raw pointer. + */ + DeleterType Deleter(); + + /** * Increment usage counter. */ void Increment(); @@ -79,12 +89,29 @@ namespace ignite /** Raw pointer. */ void* ptr; + /** Deleter. */ + DeleterType deleter; + /** Reference count. */ int32_t refCnt; IGNITE_NO_COPY_ASSIGNMENT(SharedPointerImpl) }; + /* Forward declaration. */ + template<typename T> + class IGNITE_IMPORT_EXPORT EnableSharedFromThis; + + /* Forward declaration. */ + template<typename T> + inline void ImplEnableShared(EnableSharedFromThis<T>* some, SharedPointerImpl* impl); + + // Do nothing if the instance is not derived from EnableSharedFromThis. + inline void ImplEnableShared(const volatile void*, const volatile void*) + { + // No-op. + } + /** * Shared pointer. */ @@ -92,10 +119,12 @@ namespace ignite class IGNITE_IMPORT_EXPORT SharedPointer { public: + friend class EnableSharedFromThis<T>; + /** * Constructor. */ - SharedPointer() : impl(NULL), deleter(NULL) + SharedPointer() : impl(0) { // No-op. } @@ -109,14 +138,11 @@ namespace ignite { if (ptr) { - impl = new SharedPointerImpl(ptr); - deleter = SharedPointerDefaultDeleter; + impl = new SharedPointerImpl(ptr, reinterpret_cast<SharedPointerImpl::DeleterType>(&SharedPointerDefaultDeleter<T>)); + ImplEnableShared(ptr, impl); } else - { - impl = NULL; - deleter = NULL; - } + impl = 0; } /** @@ -129,14 +155,11 @@ namespace ignite { if (ptr) { - this->impl = new SharedPointerImpl(ptr); - this->deleter = deleter; + impl = new SharedPointerImpl(ptr, reinterpret_cast<SharedPointerImpl::DeleterType>(deleter)); + ImplEnableShared(ptr, impl); } else - { - this->impl = NULL; - this->deleter = NULL; - } + impl = 0; } /** @@ -147,7 +170,6 @@ namespace ignite SharedPointer(const SharedPointer& other) { impl = other.impl; - deleter = other.deleter; if (impl) impl->Increment(); @@ -162,18 +184,9 @@ namespace ignite { if (this != &other) { - // 1. Create new instance. SharedPointer tmp(other); - // 2. Swap with temp. - SharedPointerImpl* impl0 = impl; - void(*deleter0)(T*) = deleter; - - impl = tmp.impl; - deleter = tmp.deleter; - - tmp.impl = impl0; - tmp.deleter = deleter0; + std::swap(impl, tmp.impl); } return *this; @@ -188,9 +201,11 @@ namespace ignite { T* ptr = Get(); - delete impl; + void(*deleter)(T*) = reinterpret_cast<void(*)(T*)>(impl->Deleter()); deleter(ptr); + + delete impl; } } @@ -226,10 +241,115 @@ namespace ignite private: /** Implementation. */ SharedPointerImpl* impl; + }; + + /** + * The class provides functionality that allows objects of derived + * classes to create instances of shared_ptr pointing to themselves + * and sharing ownership with existing shared_ptr objects. + */ + template<typename T> + class IGNITE_IMPORT_EXPORT EnableSharedFromThis + { + public: + /** + * Default constructor. + */ + EnableSharedFromThis() : self(0) + { + // No-op. + } + + /** + * Copy constructor. + */ + EnableSharedFromThis(const EnableSharedFromThis&) : self(0) + { + // No-op. + } + + /** + * Assignment operator. + */ + EnableSharedFromThis& operator=(const EnableSharedFromThis&) + { + return *this; + } + + /** + * Destructor. + */ + virtual ~EnableSharedFromThis() + { + // No-op. + } + + /** + * Create shared pointer for this instance. + * + * Can only be called on already shared object. + * @return New shared pointer instance. + */ + SharedPointer<T> SharedFromThis() + { + assert(self != 0); + + SharedPointer<T> ptr; + + ptr.impl = self; + + self->Increment(); + + return ptr; + } + + private: + template<typename T0> + friend void ImplEnableShared(EnableSharedFromThis<T0>*, SharedPointerImpl*); + + /** Shared pointer base. */ + SharedPointerImpl* self; + }; - /** Delete function. */ - void(*deleter)(T*); + // Implementation for instances derived from EnableSharedFromThis. + template<typename T> + inline void ImplEnableShared(EnableSharedFromThis<T>* some, SharedPointerImpl* impl) + { + if (some) + some->self = impl; + } + + /** + * Lock guard. + */ + template<typename T> + class LockGuard + { + public: + /** + * Constructor. + * + * @param lock Lockable object. + */ + LockGuard(T& lock) : + lock(lock) + { + lock.Enter(); + } + + /** + * Destructor. + */ + ~LockGuard() + { + lock.Leave(); + } + + private: + T& lock; }; + + typedef LockGuard<CriticalSection> CsLockGuard; } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/f5f90ecc/modules/platforms/cpp/common/src/concurrent.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/common/src/concurrent.cpp b/modules/platforms/cpp/common/src/concurrent.cpp index 3f85b65..5b62387 100644 --- a/modules/platforms/cpp/common/src/concurrent.cpp +++ b/modules/platforms/cpp/common/src/concurrent.cpp @@ -70,7 +70,8 @@ namespace ignite } } - SharedPointerImpl::SharedPointerImpl(void* ptr) : ptr(ptr), refCnt(1) + SharedPointerImpl::SharedPointerImpl(void* ptr, DeleterType deleter) : + ptr(ptr), deleter(deleter), refCnt(1) { Memory::Fence(); } @@ -80,6 +81,16 @@ namespace ignite return ptr; } + const void* SharedPointerImpl::Pointer() const + { + return ptr; + } + + SharedPointerImpl::DeleterType SharedPointerImpl::Deleter() + { + return deleter; + } + void SharedPointerImpl::Increment() { Atomics::IncrementAndGet32(&refCnt); http://git-wip-us.apache.org/repos/asf/ignite/blob/f5f90ecc/modules/platforms/cpp/core-test/src/concurrent_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core-test/src/concurrent_test.cpp b/modules/platforms/cpp/core-test/src/concurrent_test.cpp index 2d89b7a..173973d 100644 --- a/modules/platforms/cpp/core-test/src/concurrent_test.cpp +++ b/modules/platforms/cpp/core-test/src/concurrent_test.cpp @@ -183,4 +183,97 @@ BOOST_AUTO_TEST_CASE(TestSharedPointer) delete target; } +struct SharedPointerTargetFromThis : public EnableSharedFromThis<SharedPointerTargetFromThis> +{ + bool& deleted; + + SharedPointerTargetFromThis(bool& deleted) : deleted(deleted) + { + deleted = false; + } +}; + +void DeleteSharedPointerTarget(SharedPointerTargetFromThis* ptr) +{ + ptr->deleted = true; + delete ptr; +} + +BOOST_AUTO_TEST_CASE(TestEnableSharedFromThis) +{ + typedef SharedPointerTargetFromThis TestT; + + bool deleted; + + // 1. Test the simple scenario. + TestT* target = new TestT(deleted); + BOOST_CHECK(!deleted); + + SharedPointer<TestT>* ptr1 = new SharedPointer<TestT>(target, DeleteSharedPointerTarget); + BOOST_CHECK(!deleted); + + delete ptr1; + BOOST_CHECK(deleted); + + // 2. Test copy ctor. + target = new TestT(deleted); + BOOST_CHECK(!deleted); + + ptr1 = new SharedPointer<TestT>(target, DeleteSharedPointerTarget); + BOOST_CHECK(!deleted); + + SharedPointer<TestT>* ptr2 = new SharedPointer<TestT>(*ptr1); + BOOST_CHECK(!deleted); + + delete ptr1; + BOOST_CHECK(!deleted); + + delete ptr2; + BOOST_CHECK(deleted); + + // 3. Test assignment logic. + target = new TestT(deleted); + BOOST_CHECK(!deleted); + + ptr1 = new SharedPointer<TestT>(target, DeleteSharedPointerTarget); + BOOST_CHECK(!deleted); + + SharedPointer<TestT> ptr3 = *ptr1; + BOOST_CHECK(!deleted); + + delete ptr1; + BOOST_CHECK(!deleted); + + ptr3 = SharedPointer<TestT>(); + BOOST_CHECK(deleted); + + // 4. Test self-assignment. + target = new TestT(deleted); + BOOST_CHECK(!deleted); + + ptr1 = new SharedPointer<TestT>(target, DeleteSharedPointerTarget); + + *ptr1 = *ptr1; + + delete ptr1; + + BOOST_CHECK(deleted); + + // 5. Test shared from this + target = new TestT(deleted); + BOOST_CHECK(!deleted); + + ptr1 = new SharedPointer<TestT>(target, DeleteSharedPointerTarget); + BOOST_CHECK(!deleted); + + ptr3 = target->SharedFromThis(); + BOOST_CHECK(!deleted); + + delete ptr1; + BOOST_CHECK(!deleted); + + ptr3 = SharedPointer<TestT>(); + BOOST_CHECK(deleted); +} + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file
