182 lines
5.0 KiB
C++
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_ */
|