From e53f50716254e63bd60f2037190741c9b21e50b3 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 24 Sep 2024 12:53:33 -0400 Subject: Make `LLPointer` equality comparisons accept not-identical types. That is, both `LLPointer::operator==()` and `operator!=()` and the free function `operator==()` and `operator!=()` now accept pointer types other than the type of the subject `LLPointer`, letting the compiler apply implicit pointer conversions or diagnose an error. --- indra/llcommon/llpointer.h | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 048547e4cc..a886d6538e 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -105,11 +105,16 @@ public: 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); } + template + bool operator !=(Type1* ptr) const { return (mPointer != ptr); } + template + bool operator ==(Type1* ptr) const { return (mPointer == ptr); } + template + bool operator !=(const LLPointer& ptr) const { return (mPointer != ptr.mPointer); } + template + 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) { @@ -418,14 +423,14 @@ private: bool mStayUnique; }; -template -bool operator!=(Type* lhs, const LLPointer& rhs) +template +bool operator!=(Type0* lhs, const LLPointer& rhs) { return (lhs != rhs.get()); } -template -bool operator==(Type* lhs, const LLPointer& rhs) +template +bool operator==(Type0* lhs, const LLPointer& rhs) { return (lhs == rhs.get()); } -- cgit v1.3 From a3ef0fa3541b799d70b13100b8acb7f57f55313d Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Tue, 24 Sep 2024 13:41:02 -0400 Subject: LLConstPointer is the same as LLPointer. Instead of restating the whole class, requiring changes to be made in parallel (which has already failed), just make a template alias. --- indra/llcommon/llpointer.h | 166 +-------------------------------------------- 1 file changed, 2 insertions(+), 164 deletions(-) (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index a886d6538e..bbe3595435 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -210,170 +210,8 @@ 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 +using LLConstPointer = LLPointer; template class LLCopyOnWritePointer : public LLPointer -- cgit v1.3 From 3fc5b69b2a6c04db9854f0758ecbb03f6da22a13 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 25 Sep 2024 09:43:43 -0400 Subject: Use copy-and-swap idiom for LLPointer's assignment operators. This affords strong exception safety. Also, eliminating the conditional may improve speed. --- indra/llcommon/llpointer.h | 53 ++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 28 deletions(-) (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index bbe3595435..c5dd5532cc 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -28,6 +28,7 @@ #include "llerror.h" // *TODO: consider eliminating this #include "llmutex.h" +#include // std::swap() //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s @@ -118,24 +119,26 @@ public: LLPointer& operator =(Type* ptr) { - assign(ptr); + // copy-and-swap idiom, see http://gotw.ca/gotw/059.htm + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } LLPointer& operator =(const LLPointer& ptr) { - assign(ptr); + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } LLPointer& operator =(LLPointer&& ptr) { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } + LLPointer temp(std::move(ptr)); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } @@ -143,28 +146,32 @@ public: template LLPointer& operator =(const LLPointer& ptr) { - assign(ptr.get()); + LLPointer temp(ptr); + using std::swap; // per Swappable convention + swap(*this, temp); return *this; } template LLPointer& operator =(LLPointer&& ptr) { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ptr.mPointer = nullptr; - } + LLPointer temp(std::move(ptr)); + using std::swap; // per Swappable convention + swap(*this, temp); 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; + using std::swap; // per Swappable convention + swap(a.mPointer, b.mPointer); + } + + // Put swap() overload in the global namespace, per Swappable convention + friend void swap(LLPointer& a, LLPointer& b) + { + LLPointer::swap(a, b); } protected: @@ -196,16 +203,6 @@ protected: } #endif // LL_LIBRARY_INCLUDE - void assign(const LLPointer& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - } - protected: Type* mPointer; }; -- cgit v1.3 From bedd3da7c60c1615cd5102438822e8f186d4426a Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 25 Sep 2024 10:15:20 -0400 Subject: Explain why apparently redundant LLPointer methods are necessary. Given templated constructors and assignment operators, it's tempting to remove specific constructors and assignment operators with the same LLPointer parameters. That turns out to be a mistake. Add comments to warn future maintainers. --- indra/llcommon/llpointer.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index c5dd5532cc..71c955c4c5 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -61,6 +61,13 @@ public: ref(); } + // Even though the template constructors below accepting + // (const LLPointer&) and (LLPointer&&) appear to + // subsume these specific (const LLPointer&) and (LLPointer&&) + // constructors, the compiler recognizes these as The Copy Constructor and + // The Move Constructor, respectively. In other words, even in the + // presence of the LLPointer constructors, we still must specify + // the LLPointer constructors. LLPointer(const LLPointer& ptr) : mPointer(ptr.mPointer) { @@ -126,6 +133,13 @@ public: return *this; } + // Even though the template assignment operators below accepting + // (const LLPointer&) and (LLPointer&&) appear to + // subsume these specific (const LLPointer&) and (LLPointer&&) + // assignment operators, the compiler recognizes these as Copy Assignment + // and Move Assignment, respectively. In other words, even in the presence + // of the LLPointer assignment operators, we still must specify + // the LLPointer operators. LLPointer& operator =(const LLPointer& ptr) { LLPointer temp(ptr); -- cgit v1.3 From 9d684bc9241cca4aae79d93886d0f95dcee26d65 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Fri, 27 Sep 2024 05:38:39 -0400 Subject: Migrate ~LLPointer()'s peculiar warning case to llpointer.cpp. This allows removing #include "llerror.h" from llpointer.h. Also remove #include "llmutex.h" as a heavy way to get . That requires adding #include "llmutex.h" to llimage.h, llnotifications.h, llwatchdog.cpp and llvolumemgr.cpp, which were inheriting it from llpointer.h. --- indra/llcommon/CMakeLists.txt | 1 + indra/llcommon/llpointer.cpp | 43 +++++++++++++++++++++++++++++++ indra/llcommon/llpointer.h | 19 ++++++++++---- indra/llimage/llimage.h | 5 ++-- indra/llmath/llvolumemgr.cpp | 1 + indra/llrender/lltexturemanagerbridge.cpp | 2 ++ indra/llui/llnotifications.h | 1 + indra/newview/llwatchdog.cpp | 1 + 8 files changed, 66 insertions(+), 7 deletions(-) create mode 100755 indra/llcommon/llpointer.cpp (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 2de9deea70..5adb0bf083 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -68,6 +68,7 @@ set(llcommon_SOURCE_FILES llmetricperformancetester.cpp llmortician.cpp llmutex.cpp + llpointer.cpp llptrto.cpp llpredicate.cpp llprocess.cpp diff --git a/indra/llcommon/llpointer.cpp b/indra/llcommon/llpointer.cpp new file mode 100755 index 0000000000..1bb7055b3a --- /dev/null +++ b/indra/llcommon/llpointer.cpp @@ -0,0 +1,43 @@ +/** + * @file llpointer.cpp + * @author Nat Goodspeed + * @date 2024-09-26 + * @brief Implementation for llpointer. + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +// Precompiled header +#include "linden_common.h" +// associated header +#include "llpointer.h" +// STL headers +// std headers +// external library headers +// other Linden headers +#include "llerror.h" + +void LLPointerBase::wild_dtor(std::string_view msg) +{ +// LL_WARNS() << msg << LL_ENDL; + llassert_msg(false, msg); +} diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 71c955c4c5..77c02fab11 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -26,8 +26,8 @@ #ifndef LLPOINTER_H #define LLPOINTER_H -#include "llerror.h" // *TODO: consider eliminating this -#include "llmutex.h" +#include +#include #include // std::swap() //---------------------------------------------------------------------------- @@ -43,8 +43,18 @@ //---------------------------------------------------------------------------- +class LLPointerBase +{ +protected: + // alert the coder that a referenced type's destructor did something very + // strange -- this is in a non-template base class so we can hide the + // implementation in llpointer.cpp + static void wild_dtor(std::string_view msg); +}; + // Note: relies on Type having ref() and unref() methods -template class LLPointer +template +class LLPointer: public LLPointerBase { public: template @@ -106,7 +116,6 @@ public: 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); } @@ -210,7 +219,7 @@ protected: temp->unref(); if (mPointer != nullptr) { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + wild_dtor("Unreference did assignment to non-NULL because of destructor"); unref(); } } diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h index 6b14b68c78..1fb61673bd 100644 --- a/indra/llimage/llimage.h +++ b/indra/llimage/llimage.h @@ -27,10 +27,11 @@ #ifndef LL_LLIMAGE_H #define LL_LLIMAGE_H -#include "lluuid.h" -#include "llstring.h" +#include "llmutex.h" #include "llpointer.h" +#include "llstring.h" #include "lltrace.h" +#include "lluuid.h" constexpr S32 MIN_IMAGE_MIP = 2; // 4x4, only used for expand/contract power of 2 constexpr S32 MAX_IMAGE_MIP = 12; // 4096x4096 diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp index bb0c94d513..d8f649140f 100644 --- a/indra/llmath/llvolumemgr.cpp +++ b/indra/llmath/llvolumemgr.cpp @@ -25,6 +25,7 @@ #include "linden_common.h" +#include "llmutex.h" #include "llvolumemgr.h" #include "llvolume.h" diff --git a/indra/llrender/lltexturemanagerbridge.cpp b/indra/llrender/lltexturemanagerbridge.cpp index c243f0697a..67838418bf 100644 --- a/indra/llrender/lltexturemanagerbridge.cpp +++ b/indra/llrender/lltexturemanagerbridge.cpp @@ -24,6 +24,8 @@ * $/LicenseInfo$ */ +#include "linden_common.h" + #include "lltexturemanagerbridge.h" // Define a null texture manager bridge. Applications must provide their own bridge implementaton. diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index d56c459560..c7c7435be2 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -93,6 +93,7 @@ #include "llinitparam.h" #include "llinstancetracker.h" #include "llmortician.h" +#include "llmutex.h" #include "llnotificationptr.h" #include "llpointer.h" #include "llrefcount.h" diff --git a/indra/newview/llwatchdog.cpp b/indra/newview/llwatchdog.cpp index 614d1afc2a..072743505f 100644 --- a/indra/newview/llwatchdog.cpp +++ b/indra/newview/llwatchdog.cpp @@ -27,6 +27,7 @@ #include "llviewerprecompiledheaders.h" #include "llwatchdog.h" +#include "llmutex.h" #include "llthread.h" #include "llappviewer.h" -- cgit v1.3 From 112f9b9e226049ca1abaecfaa8a6d1b67506e140 Mon Sep 17 00:00:00 2001 From: Rye Date: Mon, 5 Jan 2026 11:09:43 -0500 Subject: Remove unused boost::hash specialization from LLPointer and update std::hash specialization to use std::hash internally Signed-off-by: Rye --- indra/llcommon/llpointer.h | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) (limited to 'indra/llcommon/llpointer.h') diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 77c02fab11..d2dcf530e5 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -26,7 +26,7 @@ #ifndef LLPOINTER_H #define LLPOINTER_H -#include +#include #include #include // std::swap() @@ -293,26 +293,14 @@ bool operator==(Type0* 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 +// Specialize for std::hash namespace std { template struct hash> { std::size_t operator()(LLPointer const& s) const noexcept { - return boost::hash>()(s); + return std::hash()(s.get()); } }; } -- cgit v1.3