mitsuba/include/mitsuba/core/ref.h

182 lines
5.0 KiB
C++

/*
This file is part of Mitsuba, a physically based rendering system.
Copyright (c) 2007-2014 by Wenzel Jakob and others.
Mitsuba is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License Version 3
as published by the Free Software Foundation.
Mitsuba is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if !defined(__MITSUBA_CORE_REF_H_)
#define __MITSUBA_CORE_REF_H_
#include "util.h"
#include <set>
MTS_NAMESPACE_BEGIN
/**
* \headerfile mitsuba/core/ref.h mitsuba/mitsuba.h
* \brief Reference counting helper
*
* The \a ref refeference template is a simple wrapper to store a
* pointer to an object. It takes care of increasing and decreasing
* the reference count of the object. When the last reference goes
* out of scope, the associated object will be deallocated.
*
* \author Wenzel Jakob
* \ingroup libcore
*/
template <typename T> class ref {
public:
/// Create a NULL reference
ref() : m_ptr(NULL) { }
/// Construct a reference from a pointer
ref(T *ptr) : m_ptr(ptr) { if (m_ptr) ((Object *) m_ptr)->incRef(); }
/// Copy-constructor
ref(const ref &pRef) : m_ptr(pRef.m_ptr) { if (m_ptr) ((Object *) m_ptr)->incRef(); }
/// Destroy this reference
~ref() { if (m_ptr) ((Object *) m_ptr)->decRef(); }
/// Overwrite this reference with another reference
inline ref& operator= (const ref& r) {
if (m_ptr == r.m_ptr)
return *this;
if (m_ptr)
((Object *) m_ptr)->decRef();
m_ptr = r.m_ptr;
if (m_ptr)
((Object *) m_ptr)->incRef();
return *this;
}
/// Overwrite this reference with a pointer to another object
inline ref& operator= (T *ptr) {
if (m_ptr == ptr)
return *this;
if (m_ptr)
((Object *) m_ptr)->decRef();
m_ptr = ptr;
if (m_ptr)
((Object *) m_ptr)->incRef();
return *this;
}
/// Compare this reference with another reference
inline bool operator== (const ref &pref) const { return (m_ptr == pref.m_ptr); }
/// Compare this reference with another reference
inline bool operator!= (const ref &pref) const { return (m_ptr != pref.m_ptr); }
/// Compare this reference with a pointer
inline bool operator== (const T* ptr) const { return (m_ptr == ptr); }
/// Compare this reference with a pointer
inline bool operator!= (const T* ptr) const { return (m_ptr != ptr); }
/// Check whether this is a NULL reference
inline bool operator!() const { return (m_ptr == NULL); }
/// Access the object referenced by this reference
inline T* operator-> () { return m_ptr; }
/// Access the object referenced by this reference
inline const T* operator-> () const { return m_ptr; }
/// Return a C++ reference to the referenced object
inline T& operator*() { return *m_ptr; }
/// Return a C++ reference to the referenced object
inline const T& operator*() const { return *m_ptr; }
/// Return a pointer to the referenced object
inline operator T* () { return m_ptr; }
/// Return a pointer to the referenced object
inline T* get() { return m_ptr; }
/// Return a pointer to the referenced object
inline const T* get() const { return m_ptr; }
/**
* Return a string representation of this reference
*/
inline std::string toString() const {
if (m_ptr == NULL)
return formatString("ref<%s>[null]",
T::m_theClass->getName().c_str());
else
return formatString("ref<%s>[ref=%i, ptr=%s]",
m_ptr->getClass()->getName().c_str(),
m_ptr->getRefCount(), m_ptr->toString().c_str());
}
private:
T *m_ptr;
};
/// \cond
/// Comparison operator for references
template <typename T> struct ref_comparator {
bool operator() (const ref<T>& lhs, const ref<T>& rhs) const {
return lhs.get() < rhs.get();
}
};
/// \endcond
/**
* \brief Simple reference-counted vector container based on \c std::vector and \ref ref
*/
template <typename T> class ref_vector : public std::vector< ref<T> > {
public:
typedef std::vector< ref<T> > parent_type;
ref_vector() : parent_type() {}
ref_vector(size_t size) : parent_type(size) {}
ref_vector(const ref_vector &vec) : parent_type(vec) {}
/// Remove all duplicates without changing the order
inline void ensureUnique() {
std::set<T *> seen;
typename parent_type::iterator it1 = this->begin(), it2 = this->begin();
for (; it1 < this->end(); ++it1) {
if (seen.find(it1->get()) != seen.end())
continue;
seen.insert(it1->get());
if (it1 != it2)
*it2++ = *it1;
else
it2++;
}
this->erase(it2, this->end());
}
/// Check if a certain pointer is contained in the vector
inline bool contains(const T *ptr) const {
for (typename parent_type::const_iterator it = this->begin();
it != this->end(); ++it)
if (it->get() == ptr)
return true;
return false;
}
};
MTS_NAMESPACE_END
#endif /* __MITSUBA_CORE_REF_H_ */