aboutsummaryrefslogtreecommitdiff
path: root/include/EASTL/shared_ptr.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/EASTL/shared_ptr.h')
-rw-r--r--include/EASTL/shared_ptr.h1696
1 files changed, 1696 insertions, 0 deletions
diff --git a/include/EASTL/shared_ptr.h b/include/EASTL/shared_ptr.h
new file mode 100644
index 0000000..5535adf
--- /dev/null
+++ b/include/EASTL/shared_ptr.h
@@ -0,0 +1,1696 @@
+///////////////////////////////////////////////////////////////////////////////
+// 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>
+#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
+ {
+ int32_t mRefCount; /// Reference count on the contained pointer. Starts as 1 by default.
+ 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; // To figure out: is this right?
+ }
+
+ inline void ref_count_sp::addref() EA_NOEXCEPT
+ {
+ Internal::atomic_increment(&mRefCount);
+ Internal::atomic_increment(&mWeakRefCount);
+ }
+
+ inline void ref_count_sp::release()
+ {
+ EASTL_ASSERT((mRefCount > 0) && (mWeakRefCount > 0));
+ if(Internal::atomic_decrement(&mRefCount) == 0)
+ free_value();
+
+ if(Internal::atomic_decrement(&mWeakRefCount) == 0)
+ free_ref_count_sp();
+ }
+
+ inline void ref_count_sp::weak_addref() EA_NOEXCEPT
+ {
+ Internal::atomic_increment(&mWeakRefCount);
+ }
+
+ inline void ref_count_sp::weak_release()
+ {
+ EASTL_ASSERT(mWeakRefCount > 0);
+ if(Internal::atomic_decrement(&mWeakRefCount) == 0)
+ free_ref_count_sp();
+ }
+
+ inline ref_count_sp* ref_count_sp::lock() EA_NOEXCEPT
+ {
+ for(int32_t refCountTemp = mRefCount; refCountTemp != 0; refCountTemp = mRefCount)
+ {
+ if(Internal::atomic_compare_and_swap(&mRefCount, refCountTemp + 1, refCountTemp))
+ {
+ Internal::atomic_increment(&mWeakRefCount);
+ 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->mRefCount : 0;
+ }
+
+ /// unique
+ /// Returns: use_count() == 1.
+ bool unique() const EA_NOEXCEPT
+ {
+ return (mpRefCount && (mpRefCount->mRefCount == 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());
+ }
+
+ 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);
+ }
+
+ template <typename T>
+ inline bool operator==(const shared_ptr<T>& a, std::nullptr_t) EA_NOEXCEPT
+ {
+ return !a;
+ }
+
+ 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);
+ }
+
+
+
+
+ /// 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->mRefCount : 0;
+ }
+
+ // Returns: use_count() == 0
+ bool expired() const EA_NOEXCEPT
+ {
+ return (!mpRefCount || (mpRefCount->mRefCount == 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