227 lines
5.4 KiB
C++
227 lines
5.4 KiB
C++
// https://github.com/vinniefalco/LuaBridge
|
|
// Copyright 2021, Stefan Frings
|
|
// Copyright 2019, Dmitry Tarakanov
|
|
// Copyright 2012, Vinnie Falco <vinnie.falco@gmail.com>
|
|
// Copyright 2007, Nathan Reed
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
#pragma once
|
|
|
|
#include <cassert>
|
|
#include <unordered_map>
|
|
#include <utility>
|
|
|
|
namespace luabridge {
|
|
|
|
namespace detail {
|
|
|
|
//==============================================================================
|
|
/**
|
|
Support for our RefCountedPtr.
|
|
*/
|
|
struct RefCountedPtrBase
|
|
{
|
|
// Declaration of container for the refcounts
|
|
typedef std::unordered_map<const void*, int> RefCountsType;
|
|
|
|
protected:
|
|
RefCountsType& getRefCounts() const
|
|
{
|
|
static RefCountsType refcounts;
|
|
return refcounts;
|
|
}
|
|
};
|
|
|
|
} // namespace detail
|
|
|
|
//==============================================================================
|
|
/**
|
|
A reference counted smart pointer.
|
|
|
|
The api is compatible with boost::RefCountedPtr and std::RefCountedPtr, in the
|
|
sense that it implements a strict subset of the functionality.
|
|
|
|
This implementation uses a hash table to look up the reference count
|
|
associated with a particular pointer.
|
|
|
|
@tparam T The class type.
|
|
|
|
@todo Decompose RefCountedPtr using a policy. At a minimum, the underlying
|
|
reference count should be policy based (to support atomic operations)
|
|
and the delete behavior should be policy based (to support custom
|
|
disposal methods).
|
|
|
|
@todo Provide an intrusive version of RefCountedPtr.
|
|
*/
|
|
template<class T>
|
|
class RefCountedPtr : private detail::RefCountedPtrBase
|
|
{
|
|
public:
|
|
template<typename Other>
|
|
struct rebind
|
|
{
|
|
typedef RefCountedPtr<Other> other;
|
|
};
|
|
|
|
/** Construct as nullptr or from existing pointer to T.
|
|
|
|
@param p The optional, existing pointer to assign from.
|
|
*/
|
|
RefCountedPtr(T* const p = nullptr) : m_p(p)
|
|
{
|
|
if (m_p)
|
|
{
|
|
++getRefCounts()[m_p];
|
|
}
|
|
}
|
|
|
|
/** Construct from another RefCountedPtr.
|
|
|
|
@param rhs The RefCountedPtr to assign from.
|
|
*/
|
|
RefCountedPtr(RefCountedPtr<T> const& rhs) : RefCountedPtr(rhs.get()) {}
|
|
|
|
/** Construct from a RefCountedPtr of a different type.
|
|
|
|
@invariant A pointer to U must be convertible to a pointer to T.
|
|
|
|
@tparam U The other object type.
|
|
@param rhs The RefCountedPtr to assign from.
|
|
*/
|
|
template<typename U>
|
|
RefCountedPtr(RefCountedPtr<U> const& rhs) : RefCountedPtr(rhs.get())
|
|
{
|
|
}
|
|
|
|
/** Release the object.
|
|
|
|
If there are no more references then the object is deleted.
|
|
*/
|
|
~RefCountedPtr() { reset(); }
|
|
|
|
/** Assign from another RefCountedPtr.
|
|
|
|
@param rhs The RefCountedPtr to assign from.
|
|
@returns A reference to the RefCountedPtr.
|
|
*/
|
|
RefCountedPtr<T>& operator=(RefCountedPtr<T> const& rhs)
|
|
{
|
|
// NOTE Self assignment is handled gracefully
|
|
*this = rhs.get();
|
|
return *this;
|
|
}
|
|
|
|
/** Assign from another RefCountedPtr of a different type.
|
|
|
|
@note A pointer to U must be convertible to a pointer to T.
|
|
|
|
@tparam U The other object type.
|
|
@param rhs The other RefCountedPtr to assign from.
|
|
@returns A reference to the RefCountedPtr.
|
|
*/
|
|
template<typename U>
|
|
RefCountedPtr<T>& operator=(RefCountedPtr<U> const& rhs)
|
|
{
|
|
// NOTE Self assignment is handled gracefully
|
|
*this = rhs.get();
|
|
return *this;
|
|
}
|
|
|
|
RefCountedPtr<T>& operator=(T* const p)
|
|
{
|
|
if (p != m_p)
|
|
{
|
|
RefCountedPtr<T> tmp(p);
|
|
std::swap(m_p, tmp.m_p);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Retrieve the raw pointer.
|
|
|
|
@returns A pointer to the object.
|
|
*/
|
|
T* get() const { return m_p; }
|
|
|
|
/** Retrieve the raw pointer by conversion.
|
|
|
|
@returns A pointer to the object.
|
|
*/
|
|
operator T*() const { return m_p; }
|
|
|
|
/** Retrieve the raw pointer.
|
|
|
|
@returns A pointer to the object.
|
|
*/
|
|
T* operator*() const { return m_p; }
|
|
|
|
/** Retrieve the raw pointer.
|
|
|
|
@returns A pointer to the object.
|
|
*/
|
|
T* operator->() const { return m_p; }
|
|
|
|
/** Determine the number of references.
|
|
|
|
@note This is not thread-safe.
|
|
|
|
@returns The number of active references.
|
|
*/
|
|
RefCountsType::mapped_type use_count() const
|
|
{
|
|
if (!m_p)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
const auto itCounter = getRefCounts().find(m_p);
|
|
assert(itCounter != getRefCounts().end());
|
|
assert(itCounter->second > 0);
|
|
|
|
return itCounter->second;
|
|
}
|
|
|
|
/** Release the pointer.
|
|
|
|
The reference count is decremented. If the reference count reaches
|
|
zero, the object is deleted.
|
|
*/
|
|
void reset()
|
|
{
|
|
if (m_p)
|
|
{
|
|
const auto itCounter = getRefCounts().find(m_p);
|
|
assert(itCounter != getRefCounts().end());
|
|
assert(itCounter->second > 0);
|
|
|
|
if (--itCounter->second == 0)
|
|
{
|
|
delete m_p;
|
|
getRefCounts().erase(itCounter);
|
|
}
|
|
|
|
m_p = nullptr;
|
|
}
|
|
}
|
|
|
|
private:
|
|
T* m_p;
|
|
};
|
|
|
|
//==============================================================================
|
|
|
|
// forward declaration
|
|
template<class T>
|
|
struct ContainerTraits;
|
|
|
|
template<class T>
|
|
struct ContainerTraits<RefCountedPtr<T>>
|
|
{
|
|
typedef T Type;
|
|
|
|
static T* get(RefCountedPtr<T> const& c) { return c.get(); }
|
|
};
|
|
|
|
} // namespace luabridge
|