/** * @file llpointer.h * @brief A reference-counted pointer for objects derived from LLRefCount * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLPOINTER_H #define LLPOINTER_H #include "llerror.h" // *TODO: consider eliminating this #include "llmutex.h" //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s // NOTE: LLPointer x = new LLFoo(); MAY NOT BE THREAD SAFE // if LLFoo::LLFoo() does anything like put itself in an update queue. // The queue may get accessed before it gets assigned to x. // The correct implementation is: // LLPointer x = new LLFoo; // constructor does not do anything interesting // x->instantiate(); // does stuff like place x into an update queue // see llthread.h for LLThreadSafeRefCount //---------------------------------------------------------------------------- // Note: relies on Type having ref() and unref() methods template class LLPointer { public: template friend class LLPointer; LLPointer() : mPointer(nullptr) { } LLPointer(Type* ptr) : mPointer(ptr) { ref(); } LLPointer(const LLPointer& ptr) : mPointer(ptr.mPointer) { ref(); } LLPointer(LLPointer&& ptr) noexcept { mPointer = ptr.mPointer; ptr.mPointer = nullptr; } // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template LLPointer(const LLPointer& ptr) : mPointer(ptr.get()) { ref(); } template LLPointer(LLPointer&& ptr) noexcept : mPointer(ptr.get()) { ptr.mPointer = nullptr; } ~LLPointer() { unref(); } Type* get() const { return mPointer; } const Type* operator->() const { return mPointer; } Type* operator->() { return mPointer; } const Type& operator*() const { return *mPointer; } Type& operator*() { return *mPointer; } operator BOOL() const { return (mPointer != nullptr); } operator bool() const { return (mPointer != nullptr); } bool operator!() const { return (mPointer == nullptr); } bool isNull() const { return (mPointer == nullptr); } bool notNull() const { return (mPointer != nullptr); } operator Type*() const { return mPointer; } bool operator !=(Type* ptr) const { return (mPointer != ptr); } bool operator ==(Type* ptr) const { return (mPointer == ptr); } bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } LLPointer& operator =(Type* ptr) { assign(ptr); return *this; } LLPointer& operator =(const LLPointer& ptr) { assign(ptr); return *this; } LLPointer& operator =(LLPointer&& ptr) { if (mPointer != ptr.mPointer) { unref(); mPointer = ptr.mPointer; ptr.mPointer = nullptr; } return *this; } // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template LLPointer& operator =(const LLPointer& ptr) { assign(ptr.get()); return *this; } template LLPointer& operator =(LLPointer&& ptr) { if (mPointer != ptr.mPointer) { unref(); mPointer = ptr.mPointer; ptr.mPointer = nullptr; } return *this; } // Just exchange the pointers, which will not change the reference counts. static void swap(LLPointer& a, LLPointer& b) { Type* temp = a.mPointer; a.mPointer = b.mPointer; b.mPointer = temp; } protected: #ifdef LL_LIBRARY_INCLUDE void ref(); void unref(); #else void ref() { if (mPointer) { mPointer->ref(); } } void unref() { if (mPointer) { Type *temp = mPointer; mPointer = nullptr; temp->unref(); if (mPointer != nullptr) { LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } } #endif // LL_LIBRARY_INCLUDE void assign(const LLPointer& ptr) { if (mPointer != ptr.mPointer) { unref(); mPointer = ptr.mPointer; ref(); } } protected: Type* mPointer; }; template class LLConstPointer { template friend class LLConstPointer; public: LLConstPointer() : mPointer(nullptr) { } LLConstPointer(const Type* ptr) : mPointer(ptr) { ref(); } LLConstPointer(const LLConstPointer& ptr) : mPointer(ptr.mPointer) { ref(); } LLConstPointer(LLConstPointer&& ptr) noexcept { mPointer = ptr.mPointer; ptr.mPointer = nullptr; } // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template LLConstPointer(const LLConstPointer& ptr) : mPointer(ptr.get()) { ref(); } template LLConstPointer(LLConstPointer&& ptr) noexcept : mPointer(ptr.get()) { ptr.mPointer = nullptr; } ~LLConstPointer() { unref(); } const Type* get() const { return mPointer; } const Type* operator->() const { return mPointer; } const Type& operator*() const { return *mPointer; } operator BOOL() const { return (mPointer != nullptr); } operator bool() const { return (mPointer != nullptr); } bool operator!() const { return (mPointer == nullptr); } bool isNull() const { return (mPointer == nullptr); } bool notNull() const { return (mPointer != nullptr); } operator const Type*() const { return mPointer; } bool operator !=(const Type* ptr) const { return (mPointer != ptr); } bool operator ==(const Type* ptr) const { return (mPointer == ptr); } bool operator ==(const LLConstPointer& ptr) const { return (mPointer == ptr.mPointer); } bool operator < (const LLConstPointer& ptr) const { return (mPointer < ptr.mPointer); } bool operator > (const LLConstPointer& ptr) const { return (mPointer > ptr.mPointer); } LLConstPointer& operator =(const Type* ptr) { if( mPointer != ptr ) { unref(); mPointer = ptr; ref(); } return *this; } LLConstPointer& operator =(const LLConstPointer& ptr) { if( mPointer != ptr.mPointer ) { unref(); mPointer = ptr.mPointer; ref(); } return *this; } LLConstPointer& operator =(LLConstPointer&& ptr) { if (mPointer != ptr.mPointer) { unref(); mPointer = ptr.mPointer; ptr.mPointer = nullptr; } return *this; } // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template LLConstPointer& operator =(const LLConstPointer& ptr) { if( mPointer != ptr.get() ) { unref(); mPointer = ptr.get(); ref(); } return *this; } template LLConstPointer& operator =(LLConstPointer&& ptr) { if (mPointer != ptr.mPointer) { unref(); mPointer = ptr.mPointer; ptr.mPointer = nullptr; } return *this; } // Just exchange the pointers, which will not change the reference counts. static void swap(LLConstPointer& a, LLConstPointer& b) { const Type* temp = a.mPointer; a.mPointer = b.mPointer; b.mPointer = temp; } protected: #ifdef LL_LIBRARY_INCLUDE void ref(); void unref(); #else // LL_LIBRARY_INCLUDE void ref() { if (mPointer) { mPointer->ref(); } } void unref() { if (mPointer) { const Type *temp = mPointer; mPointer = nullptr; temp->unref(); if (mPointer != nullptr) { LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } } #endif // LL_LIBRARY_INCLUDE protected: const Type* mPointer; }; template class LLCopyOnWritePointer : public LLPointer { public: typedef LLCopyOnWritePointer self_t; typedef LLPointer pointer_t; LLCopyOnWritePointer() : mStayUnique(false) {} LLCopyOnWritePointer(Type* ptr) : LLPointer(ptr), mStayUnique(false) {} LLCopyOnWritePointer(LLPointer& ptr) : LLPointer(ptr), mStayUnique(false) { if (ptr.mStayUnique) { makeUnique(); } } Type* write() { makeUnique(); return pointer_t::mPointer; } void makeUnique() { if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) { *(pointer_t* )(this) = new Type(*pointer_t::mPointer); } } const Type* operator->() const { return pointer_t::mPointer; } const Type& operator*() const { return *pointer_t::mPointer; } void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } private: bool mStayUnique; }; template bool operator!=(Type* lhs, const LLPointer& rhs) { return (lhs != rhs.get()); } template bool operator==(Type* lhs, const LLPointer& rhs) { return (lhs == rhs.get()); } // boost hash adapter template struct boost::hash> { typedef LLPointer argument_type; typedef std::size_t result_type; result_type operator()(argument_type const& s) const { return (std::size_t) s.get(); } }; // Adapt boost hash to std hash namespace std { template struct hash> { std::size_t operator()(LLPointer const& s) const noexcept { return boost::hash>()(s); } }; } #endif