///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Electronic Arts Inc. All rights reserved.
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Note (March 2014): shared_array is not a full implementation of an array version
// of C++11 shared_ptr, and there currently are no plans to make it so. A future
// version of shared_ptr would likely take on the ability to store arrays,
// same as unique_ptr has array support. This class isn't deprecated, but it
// is frozen until some future decision is made on what to do about arrays.
//
///////////////////////////////////////////////////////////////////////////////
// This class implements a shared_array template. This is a class which is
// similar to the C++ shared_ptr template, except that it works with arrays
// instead of individual objects.
//
// Important notice:
// As of this writing (9/2003), the implementation provided here has
// limitations that you should be aware of. These limitations will be shortly
// rectified. Most significantly, this implementation has the following
// weaknesses:
// - It cannot safely deal with exceptions that occur during the
// construction of shared_ptr objects.
// - It cannot safely deal with recursive shared_ptr objects.
// If a shared_ptr holds a pointer to an instance of A and
// class A owns an instance of shared_ptr that refers to,
// the original instance, the memory will leak.
// - A template of type shared_ptr will not call the destructor
// for an object that it stores. You thus must declare a shared_ptr
// template specifically for the class type.
// - It doesn't safely handle multiple instances of shared_ptr
// which own the same pointer accessed from multiple threads.
// This weakness is by design, for performance reasons. You should
// use shared_ptr_mt for multi-thread safe access.
//
// The rectification of the above issues are discussed in the C++ standardization
// documents for the next C++ standard (as of 2003):
// http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1450.html#Implementation-difficulty
//
// This current implementation will be eventually (hopefully by 1/2004) rectified
// to be in line with the second generation C++ standard proposal.
//
// The intended design of this class is based somewhat on the design of the Boost
// shared_array template. This design is also being considered for the next C++
// standard (as of 2003). The C++ standard update proposal is currently available at:
// http://std.dkuug.dk/jtc1/sc22/wg21/docs/papers/2003/n1450.html
// Boost smart pointers, including shared_array are documented at:
// http://www.boost.org/libs/smart_ptr/
//
// As of this writing (10/2003), this class has received approval from EA legal
// for use. The potential issue is the similarity of the class name and class
// interface to existing open source code.
//
///////////////////////////////////////////////////////////////////////////////
#ifndef EASTL_SHARED_ARRAY_H
#define EASTL_SHARED_ARRAY_H
#include
#include // Defines smart_array_deleter
EA_DISABLE_ALL_VC_WARNINGS();
#include
#include
EA_RESTORE_ALL_VC_WARNINGS();
#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
{
/// EASTL_SHARED_ARRAY_DEFAULT_NAME
///
/// Defines a default container name in the absence of a user-provided name.
///
#ifndef EASTL_SHARED_ARRAY_DEFAULT_NAME
#define EASTL_SHARED_ARRAY_DEFAULT_NAME EASTL_DEFAULT_NAME_PREFIX " shared_array" // Unless the user overrides something, this is "EASTL shared_array".
#endif
/// EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR
///
#ifndef EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR
#define EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR allocator_type(EASTL_SHARED_ARRAY_DEFAULT_NAME)
#endif
/// class shared_array
/// A shared_array is the same as shared_ptr but for arrays.
template >
class shared_array
{
protected:
/// this_type
/// This is an alias for shared_array, this class.
typedef shared_array this_type;
/// allocator_type
typedef Allocator allocator_type;
/// deleter_type
typedef Deleter deleter_type;
/// ref_count
/// An internal reference count type. Must be convertable to int
/// so that the public use_count function can work.
typedef int ref_count;
T* mpArray; /// The owned pointer. Points to an array of T.
ref_count* mpRefCount; /// Reference count for owned pointer.
allocator_type mAllocator; /// The allocator used to manage new/delete of mpRefCount.
public:
typedef T element_type;
/// shared_array
/// 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 via operator new.
/// If an exception occurs during the allocation of the shared
/// reference count, the owned pointer is deleted and the exception
/// is rethrown. A null pointer is given a reference count of 1.
explicit shared_array(T* pArray = NULL, const allocator_type& allocator = EASTL_SHARED_ARRAY_DEFAULT_ALLOCATOR)
: mpArray(pArray),
mpRefCount(NULL),
mAllocator(allocator)
{
// Allocate memory for the reference count.
void* const pMemory = EASTLAlloc(mAllocator, sizeof(ref_count));
if(pMemory)
mpRefCount = ::new(pMemory) ref_count(1);
}
/// shared_array
/// Shares ownership of a pointer with another instance of shared_array.
/// This function increments the shared reference count on the pointer.
/// If we want a shared_array constructor that is templated on shared_array,
/// 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_array(const shared_array& sharedArray)
: mpArray(sharedArray.mpArray),
mpRefCount(sharedArray.mpRefCount),
mAllocator(sharedArray.mAllocator)
{
++*mpRefCount;
}
/// ~shared_array
/// 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_array()
{
const ref_count newRefCount(--*mpRefCount);
// assert(newRefCount >= 0);
if(newRefCount == 0)
{
EASTLFree(mAllocator, mpRefCount, sizeof(ref_count));
Deleter del;
del(mpArray);
}
}
/// operator=
/// Copies another shared_array 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.
/// If we want a shared_array operator= that is templated on shared_array,
/// 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_array& operator=(const shared_array& sharedArray)
{
if(mpArray != sharedArray.mpArray)
{
// The easiest thing to do is to create a temporary and
// copy ourselves ourselves into it. This is a standard
// method for switching pointer ownership in systems like this.
shared_array(sharedArray).swap(*this);
}
return *this;
}
/// operator=
/// Assigns a new pointer, while decrementing the reference count on
/// the current pointer. The new pointer can be NULL and the current
/// pointer can NULL. If the new pointer is equivalent to the current
/// pointer, then nothing is done.
shared_array& operator=(T* pValue)
{
reset(pValue);
return *this;
}
/// reset
/// Releases the owned pointer and takes ownership of the
/// passed in pointer. If the passed in pointer is the same
/// as the owned pointer, nothing is done. The passed in pointer
/// can be null, in which case the use count is set to 1.
void reset(T* pArray = NULL)
{
if(pArray != mpArray)
{
// The easiest thing to do is to create a temporary and
// copy ourselves ourselves into it. This is a standard
// method for switching pointer ownership in systems like this.
shared_array(pArray, mAllocator).swap(*this);
}
}
/// swap
/// Exchanges the owned pointer beween two shared_array objects.
void swap(this_type& sharedArray)
{
// We leave mAllocator as-is.
// eastl::swap(mpArray, sharedArray.mpArray);
T* const pArray = sharedArray.mpArray;
sharedArray.mpArray = mpArray;
mpArray = pArray;
// eastl::swap(mpRefCount, sharedArray.mpRefCount);
ref_count* const pRefCount = sharedArray.mpRefCount;
sharedArray.mpRefCount = mpRefCount;
mpRefCount = pRefCount;
}
/// operator[]
/// Returns a reference to the specified item in the owned pointer
/// array.
/// Example usage:
/// shared_array ptr = new int[6];
/// int x = ptr[2];
T& operator[](ptrdiff_t i) const
{
// assert(mpArray && (i >= 0));
return mpArray[i];
}
/// operator*
/// Returns the owner pointer dereferenced.
/// Example usage:
/// shared_array ptr = new int(3);
/// int x = *ptr;
T& operator*() const
{
// assert(mpArray);
return *mpArray;
}
/// operator->
/// Allows access to the owned pointer via operator->()
/// Example usage:
/// struct X{ void DoSomething(); };
/// shared_array ptr = new X;
/// ptr->DoSomething();
T* operator->() const EA_NOEXCEPT
{
// assert(mpArray);
return mpArray;
}
/// 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_array ptr = new X;
/// X* pX = ptr.get();
/// pX->DoSomething();
T* get() const EA_NOEXCEPT
{
return mpArray;
}
/// use_count
/// Returns the reference count on the owned pointer.
/// The return value is one if the owned pointer is null.
int use_count() const
{
// assert(mpRefCount);
return (int)*mpRefCount;
}
/// unique
/// Returns true if the reference count on the owned pointer is one.
/// The return value is true if the owned pointer is null.
bool unique() const
{
// assert(mpRefCount);
return (*mpRefCount == 1);
}
/// Implicit operator bool
/// Allows for using a scoped_ptr as a boolean.
/// Example usage:
/// shared_array ptr = new int(3);
/// if(ptr)
/// ++*ptr;
///
/// 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(sharedArray == 1) would yield true (bad).
typedef T* (this_type::*bool_)() const;
operator bool_() const EA_NOEXCEPT
{
if(mpArray)
return &this_type::get;
return NULL;
}
/// operator!
/// This returns the opposite of operator bool; it returns true if
/// the owned pointer is null. Some compilers require this and some don't.
/// shared_array ptr = new int(3);
/// if(!ptr)
/// assert(false);
bool operator!() const EA_NOEXCEPT
{
return (mpArray == NULL);
}
/// get_allocator
/// Returns the memory allocator associated with this class.
const allocator_type& get_allocator() const EA_NOEXCEPT
{
return mAllocator;
}
allocator_type& get_allocator() EA_NOEXCEPT
{
return mAllocator;
}
/// set_allocator
/// Sets the memory allocator associated with this class.
void set_allocator(const allocator_type& allocator)
{
mAllocator = allocator;
}
}; // class shared_array
/// get_pointer
/// returns shared_array::get() via the input shared_array.
template
inline T* get_pointer(const shared_array& sharedArray)
{
return sharedArray.get();
}
/// swap
/// Exchanges the owned pointer beween two shared_array objects.
/// This non-member version is useful for compatibility of shared_array
/// objects with the C++ Standard Library and other libraries.
template
inline void swap(shared_array& sharedArray1, shared_array& sharedArray2)
{
sharedArray1.swap(sharedArray2);
}
/// operator!=
/// Compares two shared_array objects for equality. Equality is defined as
/// being true when the pointer shared between two shared_array objects is equal.
/// It is debatable what the appropriate definition of equality is between two
/// shared_array objects, but we follow the current 2nd generation C++ standard proposal.
template
inline bool operator==(const shared_array& sharedArray1, const shared_array& sharedArray2)
{
// assert((sharedArray1.get() != sharedArray2.get()) || (sharedArray1.use_count() == sharedArray2.use_count()));
return (sharedArray1.get() == sharedArray2.get());
}
/// operator!=
/// Compares two shared_array objects for inequality. Equality is defined as
/// being true when the pointer shared between two shared_array objects is equal.
/// It is debatable what the appropriate definition of equality is between two
/// shared_array objects, but we follow the current 2nd generation C++ standard proposal.
template
inline bool operator!=(const shared_array& sharedArray1, const shared_array& sharedArray2)
{
// assert((sharedArray1.get() != sharedArray2.get()) || (sharedArray1.use_count() == sharedArray2.use_count()));
return (sharedArray1.get() != sharedArray2.get());
}
/// operator<
/// Returns which shared_array is 'less' than the other. Useful when storing
/// sorted containers of scoped_ptr objects.
template
inline bool operator<(const shared_array& sharedArray1, const shared_array& sharedArray2)
{
return (sharedArray1.get() < sharedArray2.get()); // Alternatively use: std::less(a.get(), b.get());
}
} // namespace eastl
#endif // Header include guard