fart/src/util/refptr.h

116 lines
2.6 KiB
C++

#ifndef REFPTR_H
#define REFPTR_H REFPTR_H
#include <stdlib.h> /* NULL */
#include <atomic> /* std::atomic */
template <typename T>
class refptr
{
public:
refptr();
refptr(T * ptr);
refptr(const refptr<T> & orig);
refptr & operator=(const refptr<T> & orig);
refptr & operator=(T * ptr);
~refptr();
T & operator*() const;
T * operator->() const;
bool isNull() const { return m_ptr == NULL; }
bool operator==(const refptr<T> & right) const;
bool operator!=(const refptr<T> & right) const;
private:
void cloneFrom(const refptr<T> & orig);
void destroy();
T * m_ptr;
/* reference count is atomic so that refptr copies may be made
* concurrently from multiple threads (e.g. the multithreaded
* renderer) without corrupting the count */
std::atomic<int> * m_refCount;
};
template <typename T> refptr<T>::refptr()
{
m_ptr = NULL;
m_refCount = NULL;
}
template <typename T> refptr<T>::refptr(T * ptr)
{
m_ptr = ptr;
m_refCount = new std::atomic<int>(1);
}
template <typename T> refptr<T>::refptr(const refptr<T> & orig)
{
cloneFrom(orig);
}
template <typename T> refptr<T> & refptr<T>::operator=(const refptr<T> & orig)
{
destroy();
cloneFrom(orig);
return *this;
}
template <typename T> refptr<T> & refptr<T>::operator=(T * ptr)
{
destroy();
m_ptr = ptr;
m_refCount = new std::atomic<int>(1);
return *this;
}
template <typename T> void refptr<T>::cloneFrom(const refptr<T> & orig)
{
this->m_ptr = orig.m_ptr;
this->m_refCount = orig.m_refCount;
if (m_refCount != NULL)
m_refCount->fetch_add(1, std::memory_order_relaxed);
}
template <typename T> refptr<T>::~refptr()
{
destroy();
}
template <typename T> void refptr<T>::destroy()
{
if (m_refCount != NULL)
{
/* fetch_sub returns the value prior to the decrement; if it was 1
* then this was the last reference and we own the cleanup */
if (m_refCount->fetch_sub(1, std::memory_order_acq_rel) == 1)
{
delete m_ptr;
delete m_refCount;
}
}
}
template <typename T> T & refptr<T>::operator*() const
{
return *m_ptr;
}
template <typename T> T * refptr<T>::operator->() const
{
return m_ptr;
}
template <typename T> bool refptr<T>::operator==(const refptr<T> & right) const
{
return m_ptr == right.m_ptr;
}
template <typename T> bool refptr<T>::operator!=(const refptr<T> & right) const
{
return m_ptr != right.m_ptr;
}
#endif