diff options
Diffstat (limited to 'include/EASTL/shared_ptr.h')
-rw-r--r-- | include/EASTL/shared_ptr.h | 1717 |
1 files changed, 0 insertions, 1717 deletions
diff --git a/include/EASTL/shared_ptr.h b/include/EASTL/shared_ptr.h deleted file mode 100644 index e7eb778..0000000 --- a/include/EASTL/shared_ptr.h +++ /dev/null @@ -1,1717 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// Copyright (c) Electronic Arts Inc. All rights reserved. -/////////////////////////////////////////////////////////////////////////////// - -/////////////////////////////////////////////////////////////////////////////// -// This class implements the C++11 shared_ptr template. A shared_ptr is like -// the C++ Standard Library unique_ptr except that it allows sharing of pointers -// between instances via reference counting. shared_ptr objects can safely be -// copied and can safely be used in containers such as vector or list. -// -// Notes regarding safe usage of shared_ptr: -// - http://www.boost.org/doc/libs/1_53_0/libs/smart_ptr/shared_ptr.htm#ThreadSafety -// - If you construct a shared_ptr with a raw pointer, you cannot construct another shared_ptr -// with just that raw pointer. Insted you need to construct additional shared_ptrs with -// the originally created shared_ptr. Otherwise you will get a crash. -// - Usage of shared_ptr is thread-safe, but what it points to isn't automatically thread safe. -// Multiple shared_ptrs that refer to the same object can be used arbitrarily by multiple threads. -// - You can use a single shared_ptr between multiple threads in all ways except one: assigment -// to that shared_ptr. The following is not thread-safe, and needs to be guarded by a mutex -// or the shared_ptr atomic functions: -// shared_ptr<Foo> pFoo; -// // Thread 1: -// shared_ptr<Foo> pFoo2 = pFoo; -// // Thread 2: -// pFoo = make_shared<Foo>(); -// -// Compatibility note: -// This version of shared_ptr updates the previous version to have full C++11 -// compatibility. However, in order to add C++11 compatibility there needed to -// be a few breaking changes which may affect some users. It's likely that most -// or all breaking changes can be rectified by doing the same thing in a slightly -// different way. Here's a list of the primary signficant breaking changes: -// - shared_ptr now takes just one template parameter instead of three. -// (allocator and deleter). You now specify the allocator and deleter -// as part of the shared_ptr constructor at runtime. -// - shared_ptr has thread safety, which -// -/////////////////////////////////////////////////////////////////////////////// - - -#ifndef EASTL_SHARED_PTR_H -#define EASTL_SHARED_PTR_H - - -#include <EASTL/internal/config.h> -#include <EASTL/internal/smart_ptr.h> -#include <EASTL/internal/thread_support.h> -#include <EASTL/unique_ptr.h> -#include <EASTL/functional.h> -#include <EASTL/allocator.h> -#include <EASTL/atomic.h> -#if EASTL_RTTI_ENABLED - #include <typeinfo> -#endif -#if EASTL_EXCEPTIONS_ENABLED - #include <exception> -#endif - -EA_DISABLE_ALL_VC_WARNINGS() -#include <new> -#include <stddef.h> -EA_RESTORE_ALL_VC_WARNINGS() - -EA_DISABLE_VC_WARNING(4530); // C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc -EA_DISABLE_VC_WARNING(4571); // catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught. - -#if defined(EA_PRAGMA_ONCE_SUPPORTED) - #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. -#endif - - - -namespace eastl -{ - /////////////////////////////////////////////////////////////////////////// - // shared_ptr - /////////////////////////////////////////////////////////////////////////// - - /// EASTL_SHARED_PTR_DEFAULT_NAME - /// - /// Defines a default container name in the absence of a user-provided name. - /// - #ifndef EASTL_SHARED_PTR_DEFAULT_NAME - #define EASTL_SHARED_PTR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " shared_ptr" // Unless the user overrides something, this is "EASTL shared_ptr". - #endif - - - /// EASTL_SHARED_PTR_DEFAULT_ALLOCATOR - /// - #ifndef EASTL_SHARED_PTR_DEFAULT_ALLOCATOR - #define EASTL_SHARED_PTR_DEFAULT_ALLOCATOR EASTLAllocatorType(EASTL_SHARED_PTR_DEFAULT_NAME) - #endif - - - // Forward declarations - template <typename T, typename Deleter> class unique_ptr; - template <typename T> class weak_ptr; - template <typename T> class enable_shared_from_this; - - - - #if EASTL_EXCEPTIONS_ENABLED - // We define eastl::bad_weak_ptr as opposed to std::bad_weak_ptr. The reason is that - // we can't easily know of std::bad_weak_ptr exists and we would have to #include <memory> - // to use it. EASTL "owns" the types that are defined in EASTL headers, and std::bad_weak_ptr - // is declared in <memory>. - - struct bad_weak_ptr : std::exception - { - const char* what() const EA_NOEXCEPT EA_OVERRIDE - { return "bad weak_ptr"; } - }; - #endif - - - /// ref_count_sp - /// - /// This is a small utility class used by shared_ptr and weak_ptr. - struct ref_count_sp - { - atomic<int32_t> mRefCount; /// Reference count on the contained pointer. Starts as 1 by default. - atomic<int32_t> mWeakRefCount; /// Reference count on contained pointer plus this ref_count_sp object itself. Starts as 1 by default. - - public: - ref_count_sp(int32_t refCount = 1, int32_t weakRefCount = 1) EA_NOEXCEPT; - virtual ~ref_count_sp() EA_NOEXCEPT {} - - int32_t use_count() const EA_NOEXCEPT; - void addref() EA_NOEXCEPT; - void release(); - void weak_addref() EA_NOEXCEPT; - void weak_release(); - ref_count_sp* lock() EA_NOEXCEPT; - - virtual void free_value() EA_NOEXCEPT = 0; // Release the contained object. - virtual void free_ref_count_sp() EA_NOEXCEPT = 0; // Release this instance. - - #if EASTL_RTTI_ENABLED - virtual void* get_deleter(const std::type_info& type) const EA_NOEXCEPT = 0; - #else - virtual void* get_deleter() const EA_NOEXCEPT = 0; - #endif - }; - - - inline ref_count_sp::ref_count_sp(int32_t refCount, int32_t weakRefCount) EA_NOEXCEPT - : mRefCount(refCount), mWeakRefCount(weakRefCount) {} - - inline int32_t ref_count_sp::use_count() const EA_NOEXCEPT - { - return mRefCount.load(memory_order_relaxed); // To figure out: is this right? - } - - inline void ref_count_sp::addref() EA_NOEXCEPT - { - mRefCount.fetch_add(1, memory_order_relaxed); - mWeakRefCount.fetch_add(1, memory_order_relaxed); - } - - inline void ref_count_sp::release() - { - EASTL_ASSERT((mRefCount.load(memory_order_relaxed) > 0)); - if(mRefCount.fetch_sub(1, memory_order_release) == 1) - { - atomic_thread_fence(memory_order_acquire); - free_value(); - } - - weak_release(); - } - - inline void ref_count_sp::weak_addref() EA_NOEXCEPT - { - mWeakRefCount.fetch_add(1, memory_order_relaxed); - } - - inline void ref_count_sp::weak_release() - { - EASTL_ASSERT(mWeakRefCount.load(memory_order_relaxed) > 0); - if(mWeakRefCount.fetch_sub(1, memory_order_release) == 1) - { - atomic_thread_fence(memory_order_acquire); - free_ref_count_sp(); - } - } - - inline ref_count_sp* ref_count_sp::lock() EA_NOEXCEPT - { - for(int32_t refCountTemp = mRefCount.load(memory_order_relaxed); refCountTemp != 0; ) - { - if(mRefCount.compare_exchange_weak(refCountTemp, refCountTemp + 1, memory_order_relaxed)) - { - mWeakRefCount.fetch_add(1, memory_order_relaxed); - return this; - } - } - - return nullptr; - } - - - - /// ref_count_sp_t - /// - /// This is a version of ref_count_sp which is used to delete the contained pointer. - template <typename T, typename Allocator, typename Deleter> - class ref_count_sp_t : public ref_count_sp - { - public: - typedef ref_count_sp_t<T, Allocator, Deleter> this_type; - typedef T value_type; - typedef Allocator allocator_type; - typedef Deleter deleter_type; - - value_type mValue; // This is expected to be a pointer. - deleter_type mDeleter; - allocator_type mAllocator; - - ref_count_sp_t(value_type value, deleter_type deleter, allocator_type allocator) - : ref_count_sp(), mValue(value), mDeleter(eastl::move(deleter)), mAllocator(eastl::move(allocator)) - {} - - void free_value() EA_NOEXCEPT - { - mDeleter(mValue); - mValue = nullptr; - } - - void free_ref_count_sp() EA_NOEXCEPT - { - allocator_type allocator = mAllocator; - this->~ref_count_sp_t(); - EASTLFree(allocator, this, sizeof(*this)); - } - - #if EASTL_RTTI_ENABLED - void* get_deleter(const std::type_info& type) const EA_NOEXCEPT - { - return (type == typeid(deleter_type)) ? (void*)&mDeleter : nullptr; - } - #else - void* get_deleter() const EA_NOEXCEPT - { - return (void*)&mDeleter; - } - #endif - }; - - /// ref_count_sp_t_inst - /// - /// This is a version of ref_count_sp which is used to actually hold an instance of - /// T (instead of a pointer). This is useful to allocate the object and ref count - /// in a single memory allocation. - template<typename T, typename Allocator> - class ref_count_sp_t_inst : public ref_count_sp - { - public: - typedef ref_count_sp_t_inst<T, Allocator> this_type; - typedef T value_type; - typedef Allocator allocator_type; - typedef typename aligned_storage<sizeof(T), eastl::alignment_of<T>::value>::type storage_type; - - storage_type mMemory; - allocator_type mAllocator; - - value_type* GetValue() { return static_cast<value_type*>(static_cast<void*>(&mMemory)); } - - template <typename... Args> - ref_count_sp_t_inst(allocator_type allocator, Args&&... args) - : ref_count_sp(), mAllocator(eastl::move(allocator)) - { - new (&mMemory) value_type(eastl::forward<Args>(args)...); - } - - void free_value() EA_NOEXCEPT - { - GetValue()->~value_type(); - } - - void free_ref_count_sp() EA_NOEXCEPT - { - allocator_type allocator = mAllocator; - this->~ref_count_sp_t_inst(); - EASTLFree(allocator, this, sizeof(*this)); - } - - #if EASTL_RTTI_ENABLED - void* get_deleter(const std::type_info&) const EA_NOEXCEPT - { - return nullptr; // Default base implementation. - } - #else - void* get_deleter() const EA_NOEXCEPT - { - return nullptr; - } - #endif - }; - - - /// do_enable_shared_from_this - /// - /// If a user calls this function, it sets up mWeakPtr member of - /// the enable_shared_from_this parameter to point to the ref_count_sp - /// object that's passed in. Normally, the user doesn't need to call - /// this function, as the shared_ptr constructor will do it for them. - /// - template <typename T, typename U> - void do_enable_shared_from_this(const ref_count_sp* pRefCount, - const enable_shared_from_this<T>* pEnableSharedFromThis, - const U* pValue) - { - if (pEnableSharedFromThis) - pEnableSharedFromThis->mWeakPtr.assign(const_cast<U*>(pValue), const_cast<ref_count_sp*>(pRefCount)); - } - - inline void do_enable_shared_from_this(const ref_count_sp*, ...) {} // Empty specialization. This no-op version is - // called by shared_ptr when shared_ptr's T type - // is anything but an enabled_shared_from_this - // class. - - - /// shared_ptr_traits - /// This exists for the sole purpose of creating a typedef called - /// reference_type which is specialized for type void. The reason - /// for this is that shared_ptr::operator*() returns a reference - /// to T but if T is void, it needs to return void, not *void, - /// as the latter is not valid C++. - template <typename T> struct shared_ptr_traits - { typedef T& reference_type; }; - - template <> struct shared_ptr_traits<void> - { typedef void reference_type; }; - - template <> struct shared_ptr_traits<void const> - { typedef void reference_type; }; - - template <> struct shared_ptr_traits<void volatile> - { typedef void reference_type; }; - - template <> struct shared_ptr_traits<void const volatile> - { typedef void reference_type; }; - - - - /// shared_ptr - /// - /// This class implements the C++11 shared_ptr template. A shared_ptr is like the C++ - /// Standard Library unique_ptr except that it allows sharing of pointers between - /// instances via reference counting. shared_ptr objects can safely be copied and - /// can safely be used in C++ Standard Library containers such as std::vector or - /// std::list. - /// - /// This class is not thread safe in that you cannot use an instance of it from - /// two threads at the same time and cannot use two separate instances of it, which - /// own the same pointer, at the same time. Use standard multithread mutex techniques - /// to address the former problems and use shared_ptr_mt to address the latter. - /// Note that this is contrary to the C++11 standard. - /// - /// As of this writing, arrays aren't supported, but they are planned in the future - /// based on the C++17 proposal: http://isocpp.org/files/papers/N3920.html - /// - template <typename T> - class shared_ptr - { - public: - typedef shared_ptr<T> this_type; - typedef T element_type; - typedef typename shared_ptr_traits<T>::reference_type reference_type; // This defines what a reference to a T is. It's always simply T&, except for the case where T is void, whereby the reference is also just void. - typedef EASTLAllocatorType default_allocator_type; - typedef default_delete<T> default_deleter_type; - typedef weak_ptr<T> weak_type; - - protected: - element_type* mpValue; - ref_count_sp* mpRefCount; /// Base pointer to Reference count for owned pointer and the owned pointer. - - public: - /// Initializes and "empty" shared_ptr. - /// Postcondition: use_count() == zero and get() == 0 - shared_ptr() EA_NOEXCEPT - : mpValue(nullptr), - mpRefCount(nullptr) - { - // Intentionally leaving mpRefCount as NULL. Can't allocate here due to noexcept. - } - - /// Takes ownership of the pointer and sets the reference count - /// to the pointer to 1. It is OK if the input pointer is null. - /// The shared reference count is allocated on the heap using the - /// default eastl allocator. - /// Throws: bad_alloc, or an implementation-defined exception when - /// a resource other than memory could not be obtained. - /// Exception safety: If an exception is thrown, delete p is called. - /// Postcondition in the event of no exception: use_count() == 1 && get() == p - template <typename U> - explicit shared_ptr(U* pValue, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(nullptr), mpRefCount(nullptr) // alloc_internal will set this. - { - // We explicitly use default_delete<U>. You can use the other version of this constructor to provide a - // custom version. - alloc_internal(pValue, default_allocator_type(), - default_delete<U>()); // Problem: We want to be able to use default_deleter_type() instead of - // default_delete<U>, but if default_deleter_type's type is void or - // otherwise mismatched then this will fail to compile. What we really - // want to be able to do is "rebind" default_allocator_type to U - // instead of its original type. - } - - - shared_ptr(std::nullptr_t) EA_NOEXCEPT - : mpValue(nullptr), - mpRefCount(nullptr) - { - // Intentionally leaving mpRefCount as NULL. Can't allocate here due to noexcept. - } - - - /// Takes ownership of the pointer and sets the reference count - /// to the pointer to 1. It is OK if the input pointer is null. - /// The shared reference count is allocated on the heap using the - /// default eastl allocator. The pointer will be disposed using the - /// provided deleter. - /// If an exception occurs during the allocation of the shared - /// reference count, the owned pointer is deleted and the exception - /// is rethrown. - /// Postcondition: use_count() == 1 && get() == p - template <typename U, typename Deleter> - shared_ptr(U* pValue, - Deleter deleter, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(nullptr), mpRefCount(nullptr) - { - alloc_internal(pValue, default_allocator_type(), eastl::move(deleter)); - } - - template <typename Deleter> - shared_ptr(std::nullptr_t, Deleter deleter) - : mpValue(nullptr), mpRefCount(nullptr) // alloc_internal will set this. - { - alloc_internal(nullptr, default_allocator_type(), eastl::move(deleter)); - } - - - /// Takes ownership of the pointer and sets the reference count - /// to the pointer to 1. It is OK if the input pointer is null. - /// The shared reference count is allocated on the heap using the - /// supplied allocator. The pointer will be disposed using the - /// provided deleter. - /// If an exception occurs during the allocation of the shared - /// reference count, the owned pointer is deleted and the exception - /// is rethrown. - /// Postcondition: use_count() == 1 && get() == p - template <typename U, typename Deleter, typename Allocator> - explicit shared_ptr(U* pValue, - Deleter deleter, - const Allocator& allocator, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(nullptr), mpRefCount(nullptr) // alloc_internal will set this. - { - alloc_internal(pValue, eastl::move(allocator), eastl::move(deleter)); - } - - template <typename Deleter, typename Allocator> - shared_ptr(std::nullptr_t, Deleter deleter, Allocator allocator) - : mpValue(nullptr), - mpRefCount(nullptr) // alloc_internal will set this. - { - alloc_internal(nullptr, eastl::move(allocator), eastl::move(deleter)); - } - - - /// shared_ptr - /// construction with self type. - /// If we want a shared_ptr constructor that is templated on shared_ptr<U>, - /// then we need to make it in addition to this function, as otherwise - /// the compiler will generate this function and things will go wrong. - /// To accomplish this in a thread-safe way requires use of shared_ptr atomic_store. - shared_ptr(const shared_ptr& sharedPtr) EA_NOEXCEPT - : mpValue(sharedPtr.mpValue), - mpRefCount(sharedPtr.mpRefCount) - { - if(mpRefCount) - mpRefCount->addref(); - } - - - /// shared_ptr - /// Shares ownership of a pointer with another instance of shared_ptr. - /// This function increments the shared reference count on the pointer. - /// To accomplish this in a thread-safe way requires use of shared_ptr atomic_store. - template <typename U> - shared_ptr(const shared_ptr<U>& sharedPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - : mpValue(sharedPtr.mpValue), - mpRefCount(sharedPtr.mpRefCount) - { - if (mpRefCount) - mpRefCount->addref(); - } - - - /// shared_ptr - /// - /// 20.7.2.2.1p13: Constructs a shared_ptr instance that stores p and shares ownership with r. - /// Postconditions: get() == pValue && use_count() == sharedPtr.use_count(). - /// To avoid the possibility of a dangling pointer, the user of this constructor must - /// ensure that pValue remains valid at least until the ownership group of sharedPtr is destroyed. - /// This constructor allows creation of an empty shared_ptr instance with a non-NULL stored pointer. - /// - /// Shares ownership of a pointer with another instance of shared_ptr while storing a potentially - /// different pointer. This function increments the shared reference count on the sharedPtr if it exists. - /// If sharedPtr has no shared reference then a shared reference is not created an pValue is not - /// deleted in our destructor and effectively the pointer is not actually shared. - /// - /// To accomplish this in a thread-safe way requires the user to maintain the lifetime of sharedPtr - /// as described above. - /// - template <typename U> - shared_ptr(const shared_ptr<U>& sharedPtr, element_type* pValue) EA_NOEXCEPT - : mpValue(pValue), - mpRefCount(sharedPtr.mpRefCount) - { - if(mpRefCount) - mpRefCount->addref(); - } - - - shared_ptr(shared_ptr&& sharedPtr) EA_NOEXCEPT - : mpValue(sharedPtr.mpValue), - mpRefCount(sharedPtr.mpRefCount) - { - sharedPtr.mpValue = nullptr; - sharedPtr.mpRefCount = nullptr; - } - - - template <typename U> - shared_ptr(shared_ptr<U>&& sharedPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - : mpValue(sharedPtr.mpValue), - mpRefCount(sharedPtr.mpRefCount) - { - sharedPtr.mpValue = nullptr; - sharedPtr.mpRefCount = nullptr; - } - - // unique_ptr constructor - template <typename U, typename Deleter> - shared_ptr(unique_ptr<U, Deleter>&& uniquePtr, - typename eastl::enable_if<!eastl::is_array<U>::value && !is_lvalue_reference<Deleter>::value && - eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(nullptr), mpRefCount(nullptr) - { - alloc_internal(uniquePtr.release(), default_allocator_type(), uniquePtr.get_deleter()); - } - - // unique_ptr constructor - // The following is not in the C++11 Standard. - template <typename U, typename Deleter, typename Allocator> - shared_ptr(unique_ptr<U, Deleter>&& uniquePtr, - const Allocator& allocator, - typename eastl::enable_if<!eastl::is_array<U>::value && !is_lvalue_reference<Deleter>::value && - eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(nullptr), mpRefCount(nullptr) - { - alloc_internal(uniquePtr.release(), allocator, uniquePtr.get_deleter()); - } - - - /// shared_ptr(weak_ptr) - /// Shares ownership of a pointer with an instance of weak_ptr. - /// This function increments the shared reference count on the pointer. - template <typename U> - explicit shared_ptr(const weak_ptr<U>& weakPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) - : mpValue(weakPtr.mpValue) - , mpRefCount(weakPtr.mpRefCount ? - weakPtr.mpRefCount->lock() : - weakPtr.mpRefCount) // mpRefCount->lock() addref's the return value for us. - { - if (!mpRefCount) - { - mpValue = nullptr; // Question: Is it right for us to NULL this or not? - - #if EASTL_EXCEPTIONS_ENABLED - throw eastl::bad_weak_ptr(); - #else - EASTL_FAIL_MSG("eastl::shared_ptr -- bad_weak_ptr"); - #endif - } - } - - - /// ~shared_ptr - /// Decrements the reference count for the owned pointer. If the - /// reference count goes to zero, the owned pointer is deleted and - /// the shared reference count is deleted. - ~shared_ptr() - { - if (mpRefCount) - { - mpRefCount->release(); - } - // else if mpValue is non-NULL then we just lose it because it wasn't actually shared (can happen with - // shared_ptr(const shared_ptr<U>& sharedPtr, element_type* pValue) constructor). - - #if EASTL_DEBUG - mpValue = nullptr; - mpRefCount = nullptr; - #endif - } - - - // The following is disabled because it is not specified by the C++11 Standard, as it leads to - // potential collisions. Use the reset(p) and reset() functions instead. - // - // template <typename U> - // typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - // operator=(const U* pValue) EA_NOEXCEPT - // { - // reset(pValue); - // return *this; - // } - // - // template <typename U> - // this_type& operator=(std::nullptr_t) EA_NOEXCEPT - // { - // reset(); - // return *this; - // } - - - /// operator= - /// Assignment to self type. - /// If we want a shared_ptr operator= that is templated on shared_ptr<U>, - /// then we need to make it in addition to this function, as otherwise - /// the compiler will generate this function and things will go wrong. - shared_ptr& operator=(const shared_ptr& sharedPtr) EA_NOEXCEPT - { - if(&sharedPtr != this) - this_type(sharedPtr).swap(*this); - - return *this; - } - - - /// operator= - /// Copies another shared_ptr to this object. Note that this object - /// may already own a shared pointer with another different pointer - /// (but still of the same type) before this call. In that case, - /// this function releases the old pointer, decrementing its reference - /// count and deleting it if zero, takes shared ownership of the new - /// pointer and increments its reference count. - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { - if(!equivalent_ownership(sharedPtr)) - this_type(sharedPtr).swap(*this); - return *this; - } - - - /// operator= - /// Assignment to self type. - /// If we want a shared_ptr operator= that is templated on shared_ptr<U>, - /// then we need to make it in addition to this function, as otherwise - /// the compiler will generate this function and things will go wrong. - this_type& operator=(shared_ptr&& sharedPtr) EA_NOEXCEPT - { - if(&sharedPtr != this) - this_type(eastl::move(sharedPtr)).swap(*this); - - return *this; - } - - - /// operator= - /// Moves another shared_ptr to this object. Note that this object - /// may already own a shared pointer with another different pointer - /// (but still of the same type) before this call. In that case, - /// this function releases the old pointer, decrementing its reference - /// count and deleting it if zero, takes shared ownership of the new - /// pointer and increments its reference count. - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(shared_ptr<U>&& sharedPtr) EA_NOEXCEPT - { - if(!equivalent_ownership(sharedPtr)) - shared_ptr(eastl::move(sharedPtr)).swap(*this); - return *this; - } - - - // unique_ptr operator= - template <typename U, typename Deleter> - typename eastl::enable_if<!eastl::is_array<U>::value && eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(unique_ptr<U, Deleter>&& uniquePtr) - { - // Note that this will use the default EASTL allocator - this_type(eastl::move(uniquePtr)).swap(*this); - return *this; - } - - - /// reset - /// Releases the owned pointer. - void reset() EA_NOEXCEPT - { - this_type().swap(*this); - } - - - /// reset - /// Releases the owned pointer and takes ownership of the - /// passed in pointer. - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, void>::type - reset(U* pValue) - { - this_type(pValue).swap(*this); - } - - - /// reset - /// Releases the owned pointer and takes ownership of the - /// passed in pointer. - template <typename U, typename Deleter> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, void>::type - reset(U* pValue, Deleter deleter) - { - shared_ptr(pValue, deleter).swap(*this); - } - - - /// reset - /// Resets the shared_ptr - template <typename U, typename Deleter, typename Allocator> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, void>::type - reset(U* pValue, Deleter deleter, const Allocator& allocator) - { - shared_ptr(pValue, deleter, allocator).swap(*this); - } - - - /// swap - /// Exchanges the owned pointer between two shared_ptr objects. - /// This function is not intrinsically thread-safe. You must use atomic_exchange(shared_ptr<T>*, shared_ptr<T>) - /// or manually coordinate the swap. - void swap(this_type& sharedPtr) EA_NOEXCEPT - { - element_type* const pValue = sharedPtr.mpValue; - sharedPtr.mpValue = mpValue; - mpValue = pValue; - - ref_count_sp* const pRefCount = sharedPtr.mpRefCount; - sharedPtr.mpRefCount = mpRefCount; - mpRefCount = pRefCount; - } - - - /// operator* - /// Returns the owner pointer dereferenced. - /// Example usage: - /// shared_ptr<int> ptr(new int(3)); - /// int x = *ptr; - reference_type operator*() const EA_NOEXCEPT - { - return *mpValue; - } - - /// operator-> - /// Allows access to the owned pointer via operator->() - /// Example usage: - /// struct X{ void DoSomething(); }; - /// shared_ptr<int> ptr(new X); - /// ptr->DoSomething(); - element_type* operator->() const EA_NOEXCEPT - { - // assert(mpValue); - return mpValue; - } - - /// operator[] - /// Index into the array pointed to by the owned pointer. - /// The behaviour is undefined if the owned pointer is nullptr, if the user specified index is negative, or if - /// the index is outside the referred array bounds. - /// - /// When T is not an array type, it is unspecified whether this function is declared. If the function is declared, - /// it is unspecified what its return type is, except that the declaration (although not necessarily the - /// definition) of the function is guaranteed to be legal. - // - // TODO(rparolin): This is disabled because eastl::shared_ptr needs array support. - // element_type& operator[](ptrdiff_t idx) - // { - // return get()[idx]; - // } - - /// get - /// Returns the owned pointer. Note that this class does - /// not provide an operator T() function. This is because such - /// a thing (automatic conversion) is deemed unsafe. - /// Example usage: - /// struct X{ void DoSomething(); }; - /// shared_ptr<int> ptr(new X); - /// X* pX = ptr.get(); - /// pX->DoSomething(); - element_type* get() const EA_NOEXCEPT - { - return mpValue; - } - - /// use_count - /// Returns: the number of shared_ptr objects, *this included, that share ownership with *this, or 0 when *this is empty. - int use_count() const EA_NOEXCEPT - { - return mpRefCount ? mpRefCount->use_count() : 0; - } - - /// unique - /// Returns: use_count() == 1. - bool unique() const EA_NOEXCEPT - { - return (mpRefCount && (mpRefCount->use_count() == 1)); - } - - - /// owner_before - /// C++11 function for ordering. - template <typename U> - bool owner_before(const shared_ptr<U>& sharedPtr) const EA_NOEXCEPT - { - return (mpRefCount < sharedPtr.mpRefCount); - } - - template <typename U> - bool owner_before(const weak_ptr<U>& weakPtr) const EA_NOEXCEPT - { - return (mpRefCount < weakPtr.mpRefCount); - } - - - template <typename Deleter> - Deleter* get_deleter() const EA_NOEXCEPT - { - #if EASTL_RTTI_ENABLED - return mpRefCount ? static_cast<Deleter*>(mpRefCount->get_deleter(typeid(typename remove_cv<Deleter>::type))) : nullptr; - #else - // This is probably unsafe but without typeid there is no way to ensure that the - // stored deleter is actually of the templated Deleter type. - return nullptr; - - // Alternatively: - // return mpRefCount ? static_cast<Deleter*>(mpRefCount->get_deleter()) : nullptr; - #endif - } - - #ifdef EA_COMPILER_NO_EXPLICIT_CONVERSION_OPERATORS - /// Note that below we do not use operator bool(). The reason for this - /// is that booleans automatically convert up to short, int, float, etc. - /// The result is that this: if(sharedPtr == 1) would yield true (bad). - typedef T* (this_type::*bool_)() const; - operator bool_() const EA_NOEXCEPT - { - if(mpValue) - return &this_type::get; - return nullptr; - } - - bool operator!() const EA_NOEXCEPT - { - return (mpValue == nullptr); - } - #else - /// Explicit operator bool - /// Allows for using a shared_ptr as a boolean. - /// Example usage: - /// shared_ptr<int> ptr(new int(3)); - /// if(ptr) - /// ++*ptr; - explicit operator bool() const EA_NOEXCEPT - { - return (mpValue != nullptr); - } - #endif - - /// Returns true if the given shared_ptr ows the same T pointer that we do. - template <typename U> - bool equivalent_ownership(const shared_ptr<U>& sharedPtr) const - { - // We compare mpRefCount instead of mpValue, because it's feasible that there are two sets of shared_ptr - // objects that are unconnected to each other but happen to own the same value pointer. - return (mpRefCount == sharedPtr.mpRefCount); - } - - protected: - // Friend declarations. - template <typename U> friend class shared_ptr; - template <typename U> friend class weak_ptr; - template <typename U> friend void allocate_shared_helper(shared_ptr<U>&, ref_count_sp*, U*); - - // Handles the allocating of mpRefCount, while assigning mpValue. - // The provided pValue may be NULL, as with constructing with a deleter and allocator but NULL pointer. - template <typename U, typename Allocator, typename Deleter> - void alloc_internal(U pValue, Allocator allocator, Deleter deleter) - { - typedef ref_count_sp_t<U, Allocator, Deleter> ref_count_type; - - #if EASTL_EXCEPTIONS_ENABLED - try - { - void* const pMemory = EASTLAlloc(allocator, sizeof(ref_count_type)); - if(!pMemory) - throw std::bad_alloc(); - mpRefCount = ::new(pMemory) ref_count_type(pValue, eastl::move(deleter), eastl::move(allocator)); - mpValue = pValue; - do_enable_shared_from_this(mpRefCount, pValue, pValue); - } - catch(...) // The exception would usually be std::bad_alloc. - { - deleter(pValue); // 20.7.2.2.1 p7: If an exception is thrown, delete p is called. - throw; // Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could not be obtained. - } - #else - void* const pMemory = EASTLAlloc(allocator, sizeof(ref_count_type)); - if(pMemory) - { - mpRefCount = ::new(pMemory) ref_count_type(pValue, eastl::move(deleter), eastl::move(allocator)); - mpValue = pValue; - do_enable_shared_from_this(mpRefCount, pValue, pValue); - } - else - { - deleter(pValue); // We act the same as we do above with exceptions enabled. - } - #endif - } - - }; // class shared_ptr - - - /// get_pointer - /// returns shared_ptr::get() via the input shared_ptr. - template <typename T> - inline typename shared_ptr<T>::element_type* get_pointer(const shared_ptr<T>& sharedPtr) EA_NOEXCEPT - { - return sharedPtr.get(); - } - - /// get_deleter - /// returns the deleter in the input shared_ptr. - template <typename Deleter, typename T> - Deleter* get_deleter(const shared_ptr<T>& sharedPtr) EA_NOEXCEPT - { - return sharedPtr.template get_deleter<Deleter>(); - } - - /// swap - /// Exchanges the owned pointer beween two shared_ptr objects. - /// This non-member version is useful for compatibility of shared_ptr - /// objects with the C++ Standard Library and other libraries. - template <typename T> - inline void swap(shared_ptr<T>& a, shared_ptr<T>& b) EA_NOEXCEPT - { - a.swap(b); - } - - - /// shared_ptr comparison operators - template <typename T, typename U> - inline bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - // assert((a.get() != b.get()) || (a.use_count() == b.use_count())); - return (a.get() == b.get()); - } - -#if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template <typename T, typename U> - std::strong_ordering operator<=>(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - return a.get() <=> b.get(); - } -#else - template <typename T, typename U> - inline bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - // assert((a.get() != b.get()) || (a.use_count() == b.use_count())); - return (a.get() != b.get()); - } - - template <typename T, typename U> - inline bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - //typedef typename eastl::common_type<T*, U*>::type CPointer; - //return less<CPointer>()(a.get(), b.get()); - - typedef typename eastl::common_type<T*, U*>::type CPointer; // We currently need to make these temporary variables, as otherwise clang complains about CPointer being int*&&&. - CPointer pT = a.get(); // I wonder if there's something wrong with our common_type type trait implementation. - CPointer pU = b.get(); // "in instantiation of function template specialization 'eastl::operator<<int, int>, no known conversion from 'element_type *' (aka 'int *') to 'int *&&&' for 1st argument" - return less<CPointer>()(pT, pU); // It looks like common_type is making CPointer be (e.g.) int*&& instead of int*, though the problem may be in how less<> deals with that. - } - - template <typename T, typename U> - inline bool operator>(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - return (b < a); - } - - template <typename T, typename U> - inline bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - return !(b < a); - } - - template <typename T, typename U> - inline bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b) EA_NOEXCEPT - { - return !(a < b); - } -#endif - - template <typename T> - inline bool operator==(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return !a; - } - - #if defined(EA_COMPILER_HAS_THREE_WAY_COMPARISON) - template <typename T> - inline std::strong_ordering operator<=>(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return a.get() <=> nullptr; - } - #else - template <typename T> - inline bool operator==(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return !b; - } - - template <typename T> - inline bool operator!=(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return static_cast<bool>(a); - } - - template <typename T> - inline bool operator!=(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return static_cast<bool>(b); - } - - template <typename T> - inline bool operator<(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return less<T*>()(a.get(), nullptr); - } - - template <typename T> - inline bool operator<(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return less<T*>()(nullptr, b.get()); - } - - template <typename T> - inline bool operator>(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return (nullptr < a); - } - - template <typename T> - inline bool operator>(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return (b < nullptr); - } - - template <typename T> - inline bool operator<=(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return !(nullptr < a); - } - - template <typename T> - inline bool operator<=(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return !(b < nullptr); - } - - template <typename T> - inline bool operator>=(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT - { - return !(a < nullptr); - } - - template <typename T> - inline bool operator>=(std::nullptr_t, const shared_ptr<T>& b) EA_NOEXCEPT - { - return !(nullptr < b); - } -#endif - - - - /// reinterpret_pointer_cast - /// - /// Returns a shared_ptr<T> reinterpret-casted from a const shared_ptr<U>&. - /// http://isocpp.org/files/papers/N3920.html - /// - /// Requires: The expression reinterpret_cast<T*>(sharedPtr.get()) shall be well formed. - /// Returns: If sharedPtr is empty, an empty shared_ptr<T>; otherwise, a shared_ptr<T> - /// object that stores const_cast<T*>(sharedPtr.get()) and shares ownership with sharedPtr. - /// Postconditions: w.get() == const_cast<T*>(sharedPtr.get()) and w.use_count() == sharedPtr.use_count(), - /// where w is the return value. - template <typename T, typename U> - inline shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const& sharedPtr) EA_NOEXCEPT - { - return shared_ptr<T>(sharedPtr, reinterpret_cast<T*>(sharedPtr.get())); - } - - - /// static_pointer_cast - /// - /// Returns a shared_ptr<T> static-casted from a shared_ptr<U>&. - /// - /// Requires: The expression const_cast<T*>(sharedPtr.get()) shall be well formed. - /// Returns: If sharedPtr is empty, an empty shared_ptr<T>; otherwise, a shared_ptr<T> - /// object that stores const_cast<T*>(sharedPtr.get()) and shares ownership with sharedPtr. - /// Postconditions: w.get() == const_cast<T*>(sharedPtr.get()) and w.use_count() == sharedPtr.use_count(), - /// where w is the return value. - template <typename T, typename U> - inline shared_ptr<T> static_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { - return shared_ptr<T>(sharedPtr, static_cast<T*>(sharedPtr.get())); - } - - template <typename T, typename U> // Retained for support for pre-C++11 shared_ptr. - inline shared_ptr<T> static_shared_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { return static_pointer_cast<T, U>(sharedPtr); } - - - - /// const_pointer_cast - /// - /// Returns a shared_ptr<T> const-casted from a const shared_ptr<U>&. - /// Normally, this means that the source shared_ptr holds a const data type. - // - /// Requires: The expression const_cast<T*>(sharedPtr.get()) shall be well formed. - /// Returns: If sharedPtr is empty, an empty shared_ptr<T>; otherwise, a shared_ptr<T> - /// object that stores const_cast<T*>(sharedPtr.get()) and shares ownership with sharedPtr. - /// Postconditions: w.get() == const_cast<T*>(sharedPtr.get()) and w.use_count() == sharedPtr.use_count(), - /// where w is the return value. - template <typename T, typename U> - inline shared_ptr<T> const_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { - return shared_ptr<T>(sharedPtr, const_cast<T*>(sharedPtr.get())); - } - - template <typename T, typename U> // Retained for support for pre-C++11 shared_ptr. - inline shared_ptr<T> const_shared_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { return const_pointer_cast<T, U>(sharedPtr); } - - - - #if EASTL_RTTI_ENABLED - /// dynamic_pointer_cast - /// - /// Returns a shared_ptr<T> dynamic-casted from a const shared_ptr<U>&. - /// - /// Requires: The expression dynamic_cast<T*>(sharedPtr.get()) shall be well formed and shall have well defined behavior. - /// Returns: When dynamic_cast<T*>(sharedPtr.get()) returns a nonzero value, a shared_ptr<T> object that stores - /// a copy of it and shares ownership with sharedPtr; Otherwise, an empty shared_ptr<T> object. - /// Postcondition: w.get() == dynamic_cast<T*>(sharedPtr.get()), where w is the return value - /// - template <typename T, typename U> - inline shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { - if(T* p = dynamic_cast<T*>(sharedPtr.get())) - return shared_ptr<T>(sharedPtr, p); - return shared_ptr<T>(); - } - - template <typename T, typename U> // Retained for support for pre-C++11 shared_ptr. - inline typename eastl::enable_if<!eastl::is_array<T>::value && !eastl::is_array<U>::value, shared_ptr<T> >::type - dynamic_shared_pointer_cast(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { return dynamic_pointer_cast<T, U>(sharedPtr); } - #endif - - - /// hash specialization for shared_ptr. - /// It simply returns eastl::hash(x.get()). If your unique_ptr pointer type (the return value of shared_ptr<T>::get) is - /// a custom type and not a built-in pointer type then you will need to independently define eastl::hash for that type. - template <typename T> - struct hash< shared_ptr<T> > - { - size_t operator()(const shared_ptr<T>& x) const EA_NOEXCEPT - { return eastl::hash<T*>()(x.get()); } - }; - - - template <typename T> - void allocate_shared_helper(eastl::shared_ptr<T>& sharedPtr, ref_count_sp* pRefCount, T* pValue) - { - sharedPtr.mpRefCount = pRefCount; - sharedPtr.mpValue = pValue; - do_enable_shared_from_this(pRefCount, pValue, pValue); - } - - template <typename T, typename Allocator, typename... Args> - shared_ptr<T> allocate_shared(const Allocator& allocator, Args&&... args) - { - typedef ref_count_sp_t_inst<T, Allocator> ref_count_type; - shared_ptr<T> ret; - void* const pMemory = EASTLAlloc(const_cast<Allocator&>(allocator), sizeof(ref_count_type)); - if(pMemory) - { - ref_count_type* pRefCount = ::new(pMemory) ref_count_type(allocator, eastl::forward<Args>(args)...); - allocate_shared_helper(ret, pRefCount, pRefCount->GetValue()); - } - return ret; - } - - template <typename T, typename... Args> - shared_ptr<T> make_shared(Args&&... args) - { - // allocate with the default allocator. - return eastl::allocate_shared<T>(EASTL_SHARED_PTR_DEFAULT_ALLOCATOR, eastl::forward<Args>(args)...); - } - - - - /////////////////////////////////////////////////////////////////////////// - // shared_ptr atomic access - // - // These functions allow shared_ptr to act like other C++11 atomic operations. - // So the same way you can use atomic_load on a raw pointer, you can also - // use it on a shared_ptr. This allows for transparent use of shared_ptr in - // place of raw pointers (e.g. in templates). You do not need to use these - // functions for regular thread-safe direct usage of shared_ptr construction - // and copying, as it's intrinsically thread-safe for that already. - // - // That being said, the following is not thread-safe and needs to be guarded by - // a mutex or the following atomic functions, as it's assigning the *same* - // shared_ptr object from multiple threads as opposed to different shared_ptr - // objects underlying object: - // shared_ptr<Foo> pFoo; - // // Thread 1: - // shared_ptr<Foo> pFoo2 = pFoo; - // // Thread 2: - // pFoo = make_shared<Foo>(); - /////////////////////////////////////////////////////////////////////////// - - template <typename T> - inline bool atomic_is_lock_free(const shared_ptr<T>*) - { - // Return true if atomic access to the provided shared_ptr instance is lock-free, false otherwise. - // For this to be lock-free, we would have to be able to copy shared_ptr objects in an atomic way - // as opposed to wrapping it with a mutex like we do below. Given the nature of shared_ptr, it's - // probably not feasible to implement these operations without a mutex. atomic_is_lock_free exists - // in the C++11 Standard because it also applies to other types such as built-in types which can - // be lock-free in their access. - return false; - } - - template <typename T> - inline shared_ptr<T> atomic_load(const shared_ptr<T>* pSharedPtr) - { - Internal::shared_ptr_auto_mutex autoMutex(pSharedPtr); - return *pSharedPtr; - } - - template <typename T> - inline shared_ptr<T> atomic_load_explicit(const shared_ptr<T>* pSharedPtr, ... /*std::memory_order memoryOrder*/) - { - return atomic_load(pSharedPtr); - } - - template <typename T> - inline void atomic_store(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB) - { - Internal::shared_ptr_auto_mutex autoMutex(pSharedPtrA); - pSharedPtrA->swap(sharedPtrB); - } - - template <typename T> - inline void atomic_store_explicit(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB, ... /*std::memory_order memoryOrder*/) - { - atomic_store(pSharedPtrA, sharedPtrB); - } - - template <typename T> - shared_ptr<T> atomic_exchange(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB) - { - Internal::shared_ptr_auto_mutex autoMutex(pSharedPtrA); - pSharedPtrA->swap(sharedPtrB); - return sharedPtrB; - } - - template <typename T> - inline shared_ptr<T> atomic_exchange_explicit(shared_ptr<T>* pSharedPtrA, shared_ptr<T> sharedPtrB, ... /*std::memory_order memoryOrder*/) - { - return atomic_exchange(pSharedPtrA, sharedPtrB); - } - - // Compares the shared pointers pointed-to by p and expected. If they are equivalent (share ownership of the - // same pointer and refer to the same pointer), assigns sharedPtrNew into *pSharedPtr using the memory ordering constraints - // specified by success and returns true. If they are not equivalent, assigns *pSharedPtr into *pSharedPtrCondition using the - // memory ordering constraints specified by failure and returns false. - template <typename T> - bool atomic_compare_exchange_strong(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew) - { - Internal::shared_ptr_auto_mutex autoMutex(pSharedPtr); - - if(pSharedPtr->equivalent_ownership(*pSharedPtrCondition)) - { - *pSharedPtr = sharedPtrNew; - return true; - } - - *pSharedPtrCondition = *pSharedPtr; - return false; - } - - template <typename T> - inline bool atomic_compare_exchange_weak(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew) - { - return atomic_compare_exchange_strong(pSharedPtr, pSharedPtrCondition, sharedPtrNew); - } - - template <typename T> // Returns true if pSharedPtr was equivalent to *pSharedPtrCondition. - inline bool atomic_compare_exchange_strong_explicit(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew, ... /*memory_order memoryOrderSuccess, memory_order memoryOrderFailure*/) - { - return atomic_compare_exchange_strong(pSharedPtr, pSharedPtrCondition, sharedPtrNew); - } - - template <typename T> - inline bool atomic_compare_exchange_weak_explicit(shared_ptr<T>* pSharedPtr, shared_ptr<T>* pSharedPtrCondition, shared_ptr<T> sharedPtrNew, ... /*memory_order memoryOrderSuccess, memory_order memoryOrderFailure*/) - { - return atomic_compare_exchange_weak(pSharedPtr, pSharedPtrCondition, sharedPtrNew); - } - - - - - /////////////////////////////////////////////////////////////////////////// - // weak_ptr - /////////////////////////////////////////////////////////////////////////// - - /// EASTL_WEAK_PTR_DEFAULT_NAME - /// - /// Defines a default container name in the absence of a user-provided name. - /// - #ifndef EASTL_WEAK_PTR_DEFAULT_NAME - #define EASTL_WEAK_PTR_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " weak_ptr" // Unless the user overrides something, this is "EASTL weak_ptr". - #endif - - - /// EASTL_WEAK_PTR_DEFAULT_ALLOCATOR - /// - #ifndef EASTL_WEAK_PTR_DEFAULT_ALLOCATOR - #define EASTL_WEAK_PTR_DEFAULT_ALLOCATOR allocator_type(EASTL_WEAK_PTR_DEFAULT_NAME) - #endif - - - /// weak_ptr - /// - /// The weak_ptr class template stores a "weak reference" to an object - /// that's already managed by a shared_ptr. To access the object, a weak_ptr - /// can be converted to a shared_ptr using the shared_ptr constructor or - /// the lock() member function. When the last shared_ptr to the object goes - /// away and the object is deleted, the attempt to obtain a shared_ptr - /// from the weak_ptr instances that refer to the deleted object will fail via - /// lock() returning an empty shared_ptr. - /// - /// The Allocator template argument manages the memory of the shared reference - /// count and not the stored object. weak_ptr will not delete the stored object - /// but instead can only delete the reference count on that object. - /// - template <typename T> - class weak_ptr - { - public: - typedef weak_ptr<T> this_type; - typedef T element_type; - - public: - /// weak_ptr - weak_ptr() EA_NOEXCEPT - : mpValue(nullptr), - mpRefCount(nullptr) - { - } - - - /// weak_ptr - /// Construction with self type. - weak_ptr(const this_type& weakPtr) EA_NOEXCEPT - : mpValue(weakPtr.mpValue), - mpRefCount(weakPtr.mpRefCount) - { - if(mpRefCount) - mpRefCount->weak_addref(); - } - - - /// weak_ptr - /// Move construction with self type. - weak_ptr(this_type&& weakPtr) EA_NOEXCEPT - : mpValue(weakPtr.mpValue), - mpRefCount(weakPtr.mpRefCount) - { - weakPtr.mpValue = nullptr; - weakPtr.mpRefCount = nullptr; - } - - - /// weak_ptr - /// Constructs a weak_ptr from another weak_ptr. - template <typename U> - weak_ptr(const weak_ptr<U>& weakPtr, typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - : mpValue(weakPtr.mpValue), - mpRefCount(weakPtr.mpRefCount) - { - if(mpRefCount) - mpRefCount->weak_addref(); - } - - - /// weak_ptr - /// Move constructs a weak_ptr from another weak_ptr. - template <typename U> - weak_ptr(weak_ptr<U>&& weakPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - : mpValue(weakPtr.mpValue), - mpRefCount(weakPtr.mpRefCount) - { - weakPtr.mpValue = nullptr; - weakPtr.mpRefCount = nullptr; - } - - - /// weak_ptr - /// Constructs a weak_ptr from a shared_ptr. - template <typename U> - weak_ptr(const shared_ptr<U>& sharedPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - : mpValue(sharedPtr.mpValue), - mpRefCount(sharedPtr.mpRefCount) - { - if (mpRefCount) - mpRefCount->weak_addref(); - } - - - /// ~weak_ptr - ~weak_ptr() - { - if(mpRefCount) - mpRefCount->weak_release(); - } - - - /// operator=(weak_ptr) - /// assignment to self type. - this_type& operator=(const this_type& weakPtr) EA_NOEXCEPT - { - assign(weakPtr); - return *this; - } - - - this_type& operator=(this_type&& weakPtr) EA_NOEXCEPT - { - weak_ptr(eastl::move(weakPtr)).swap(*this); - return *this; - } - - - /// operator=(weak_ptr) - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(const weak_ptr<U>& weakPtr) EA_NOEXCEPT - { - assign(weakPtr); - return *this; - } - - - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(weak_ptr<U>&& weakPtr) EA_NOEXCEPT - { - weak_ptr(eastl::move(weakPtr)).swap(*this); - return *this; - } - - - /// operator=(shared_ptr) - /// Assigns to a weak_ptr from a shared_ptr. - template <typename U> - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value, this_type&>::type - operator=(const shared_ptr<U>& sharedPtr) EA_NOEXCEPT - { - if(mpRefCount != sharedPtr.mpRefCount) // This check encompasses assignment to self. - { - // Release old reference - if(mpRefCount) - mpRefCount->weak_release(); - - mpValue = sharedPtr.mpValue; - mpRefCount = sharedPtr.mpRefCount; - if(mpRefCount) - mpRefCount->weak_addref(); - } - return *this; - } - - shared_ptr<T> lock() const EA_NOEXCEPT - { - // We can't just return shared_ptr<T>(*this), as the object may go stale while we are doing this. - shared_ptr<T> temp; - temp.mpRefCount = mpRefCount ? mpRefCount->lock() : mpRefCount; // mpRefCount->lock() addref's the return value for us. - if(temp.mpRefCount) - temp.mpValue = mpValue; - return temp; - } - - // Returns: 0 if *this is empty ; otherwise, the number of shared_ptr instances that share ownership with *this. - int use_count() const EA_NOEXCEPT - { - return mpRefCount ? mpRefCount->use_count() : 0; - } - - // Returns: use_count() == 0 - bool expired() const EA_NOEXCEPT - { - return (!mpRefCount || (mpRefCount->use_count() == 0)); - } - - void reset() - { - if(mpRefCount) - mpRefCount->weak_release(); - - mpValue = nullptr; - mpRefCount = nullptr; - } - - void swap(this_type& weakPtr) - { - T* const pValue = weakPtr.mpValue; - weakPtr.mpValue = mpValue; - mpValue = pValue; - - ref_count_sp* const pRefCount = weakPtr.mpRefCount; - weakPtr.mpRefCount = mpRefCount; - mpRefCount = pRefCount; - } - - - /// assign - /// - /// Assignment via another weak_ptr. - /// - template <typename U> - void assign(const weak_ptr<U>& weakPtr, - typename eastl::enable_if<eastl::is_convertible<U*, element_type*>::value>::type* = 0) EA_NOEXCEPT - { - if(mpRefCount != weakPtr.mpRefCount) // This check encompasses assignment to self. - { - // Release old reference - if(mpRefCount) - mpRefCount->weak_release(); - - // Add new reference - mpValue = weakPtr.mpValue; - mpRefCount = weakPtr.mpRefCount; - if(mpRefCount) - mpRefCount->weak_addref(); - } - } - - - /// owner_before - /// C++11 function for ordering. - template <typename U> - bool owner_before(const weak_ptr<U>& weakPtr) const EA_NOEXCEPT - { - return (mpRefCount < weakPtr.mpRefCount); - } - - /// owner_before - template <typename U> - bool owner_before(const shared_ptr<U>& sharedPtr) const EA_NOEXCEPT - { - return (mpRefCount < sharedPtr.mpRefCount); - } - - - /// less_than - /// For compatibility with pre-C++11 weak_ptr. Use owner_before instead. - template <typename U> - bool less_than(const weak_ptr<U>& weakPtr) const EA_NOEXCEPT - { - return (mpRefCount < weakPtr.mpRefCount); - } - - - /// assign - /// - /// Assignment through a T/ref_count_sp pair. This is used by - /// external utility functions. - /// - void assign(element_type* pValue, ref_count_sp* pRefCount) - { - mpValue = pValue; - - if(pRefCount != mpRefCount) - { - if(mpRefCount) - mpRefCount->weak_release(); - - mpRefCount = pRefCount; - - if(mpRefCount) - mpRefCount->weak_addref(); - } - } - - protected: - element_type* mpValue; /// The (weakly) owned pointer. - ref_count_sp* mpRefCount; /// Reference count for owned pointer. - - // Friend declarations - template <typename U> friend class shared_ptr; - template <typename U> friend class weak_ptr; - - }; // class weak_ptr - - - - /// Note that the C++11 Standard does not specify that weak_ptr has comparison operators, - /// though it does specify that the owner_before function exists in weak_ptr. - template <typename T, typename U> - inline bool operator<(const weak_ptr<T>& weakPtr1, const weak_ptr<U>& weakPtr2) - { - return weakPtr1.owner_before(weakPtr2); - } - - - template <typename T> - void swap(weak_ptr<T>& weakPtr1, weak_ptr<T>& weakPtr2) - { - weakPtr1.swap(weakPtr2); - } - - - - - - - /////////////////////////////////////////////////////////////////////////// - // owner_less - // - // Implements less (operator <) for shared_ptr and thus allows it to participate - // in algorithms and containers that use strict weak ordering, such as map. - /////////////////////////////////////////////////////////////////////////// - - template <typename T> - struct owner_less; - - template <typename T> - struct owner_less< shared_ptr<T> > - : public eastl::binary_function<shared_ptr<T>, shared_ptr<T>, bool> - { - typedef bool result_type; - - bool operator()(shared_ptr<T> const& a, shared_ptr<T> const& b) const - { return a.owner_before(b); } - - bool operator()(shared_ptr<T> const& a, weak_ptr<T> const& b) const - { return a.owner_before(b); } - - bool operator()(weak_ptr<T> const& a, shared_ptr<T> const& b) const - { return a.owner_before(b); } - }; - - template <typename T> - struct owner_less< weak_ptr<T> > - : public eastl::binary_function<weak_ptr<T>, weak_ptr<T>, bool> - { - typedef bool result_type; - - bool operator()(weak_ptr<T> const& a, weak_ptr<T> const& b) const - { return a.owner_before(b); } - - bool operator()(weak_ptr<T> const& a, shared_ptr<T> const& b) const - { return a.owner_before(b); } - - bool operator()(shared_ptr<T> const& a, weak_ptr<T> const& b) const - { return a.owner_before(b); } - }; - - -} // namespace eastl - - -EA_RESTORE_VC_WARNING(); -EA_RESTORE_VC_WARNING(); - - -// We have to either #include enable_shared.h here or we need to move the enable_shared source code to here. -#include <EASTL/internal/enable_shared.h> - - -#endif // Header include guard |