summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/CMakeLists.txt1
-rw-r--r--indra/llcommon/indra_constants.h22
-rw-r--r--indra/llcommon/llapp.cpp1
-rw-r--r--indra/llcommon/llapp.h2
-rw-r--r--indra/llcommon/lldate.cpp7
-rw-r--r--indra/llcommon/llerror.cpp6
-rw-r--r--indra/llcommon/llerrorcontrol.h1
-rw-r--r--indra/llcommon/llfile.cpp29
-rw-r--r--indra/llcommon/llheteromap.cpp2
-rw-r--r--indra/llcommon/llheteromap.h27
-rw-r--r--indra/llcommon/llinitparam.h129
-rwxr-xr-xindra/llcommon/llpointer.cpp43
-rw-r--r--indra/llcommon/llpointer.h291
-rw-r--r--indra/llcommon/llpounceable.h4
-rw-r--r--indra/llcommon/llprocess.cpp13
-rw-r--r--indra/llcommon/llregistry.h26
-rw-r--r--indra/llcommon/llsd.cpp162
-rw-r--r--indra/llcommon/llsd.h39
-rw-r--r--indra/llcommon/llsdjson.cpp4
-rw-r--r--indra/llcommon/llsdserialize.cpp52
-rw-r--r--indra/llcommon/llsdserialize_xml.cpp32
-rw-r--r--indra/llcommon/llsingleton.h4
-rw-r--r--indra/llcommon/llstaticstringtable.h5
-rw-r--r--indra/llcommon/llstl.h38
-rw-r--r--indra/llcommon/lluuid.h19
-rw-r--r--indra/llcommon/llwatchdog.cpp1
-rw-r--r--indra/llcommon/workqueue.cpp22
27 files changed, 544 insertions, 438 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 2bafef5d1e..0aaa7433ce 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -66,6 +66,7 @@ set(llcommon_SOURCE_FILES
llmetricperformancetester.cpp
llmortician.cpp
llmutex.cpp
+ llpointer.cpp
llptrto.cpp
llpredicate.cpp
llprocess.cpp
diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h
index a0394da281..404e0c71ce 100644
--- a/indra/llcommon/indra_constants.h
+++ b/indra/llcommon/indra_constants.h
@@ -163,6 +163,28 @@ constexpr U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only
constexpr U8 SIM_ACCESS_DOWN = 254;
constexpr U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT;
+// map item types
+constexpr U32 MAP_ITEM_TELEHUB = 0x01;
+constexpr U32 MAP_ITEM_PG_EVENT = 0x02;
+constexpr U32 MAP_ITEM_MATURE_EVENT = 0x03;
+// constexpr U32 MAP_ITEM_POPULAR = 0x04; // No longer supported, 2009-03-02 KLW
+// constexpr U32 MAP_ITEM_AGENT_COUNT = 0x05;
+constexpr U32 MAP_ITEM_AGENT_LOCATIONS = 0x06;
+constexpr U32 MAP_ITEM_LAND_FOR_SALE = 0x07;
+constexpr U32 MAP_ITEM_CLASSIFIED = 0x08;
+constexpr U32 MAP_ITEM_ADULT_EVENT = 0x09;
+constexpr U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a;
+
+// Region map layer numbers
+constexpr S32 MAP_SIM_OBJECTS = 0;
+constexpr S32 MAP_SIM_TERRAIN = 1;
+constexpr S32 MAP_SIM_LAND_FOR_SALE = 2; // Transparent alpha overlay of land for sale
+constexpr S32 MAP_SIM_IMAGE_TYPES = 3; // Number of map layers
+constexpr S32 MAP_SIM_INFO_MASK = 0x00FFFFFF; // Agent access may be stuffed into upper byte
+constexpr S32 MAP_SIM_LAYER_MASK = 0x0000FFFF; // Layer info is in lower 16 bits
+constexpr S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000;
+constexpr S32 MAP_SIM_PRELUDE = 0x00020000;
+
// attachment constants
constexpr U8 ATTACHMENT_ADD = 0x80;
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index c532620daa..f92bb98ba6 100644
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -93,6 +93,7 @@ bool LLApp::sDisableCrashlogger = false;
LLScalarCond<LLApp::EAppStatus> LLApp::sStatus{LLApp::APP_STATUS_STOPPED};
LLAppErrorHandler LLApp::sErrorHandler = NULL;
+bool gDisconnected = false;
LLApp::LLApp()
{
diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h
index 57f5a112d9..ce09c566a9 100644
--- a/indra/llcommon/llapp.h
+++ b/indra/llcommon/llapp.h
@@ -50,6 +50,8 @@ void clear_signals();
#endif
+extern bool gDisconnected;
+
class LL_COMMON_API LLApp
{
public:
diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp
index 5205699b92..5545bb71af 100644
--- a/indra/llcommon/lldate.cpp
+++ b/indra/llcommon/lldate.cpp
@@ -41,6 +41,9 @@
#include "llstring.h"
#include "llfasttimer.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
static const F64 LL_APR_USEC_PER_SEC = 1000000.0;
// should be APR_USEC_PER_SEC, but that relies on INT64_C which
// isn't defined in glib under our build set up for some reason
@@ -64,7 +67,7 @@ std::string LLDate::asString() const
{
std::ostringstream stream;
toStream(stream);
- return stream.str();
+ return std::move(stream).str();
}
//@ brief Converts time in seconds since EPOCH
@@ -184,7 +187,7 @@ bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *se
bool LLDate::fromString(const std::string& iso8601_date)
{
- std::istringstream stream(iso8601_date);
+ boost::iostreams::stream<boost::iostreams::array_source> stream(iso8601_date.data(), iso8601_date.size());
return fromStream(stream);
}
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index b14464382b..6f5e57c3de 100644
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -480,7 +480,7 @@ namespace
}
- typedef std::map<std::string, LLError::ELevel> LevelMap;
+ typedef std::unordered_map<std::string, LLError::ELevel> LevelMap;
typedef std::vector<LLError::RecorderPtr> Recorders;
typedef std::vector<LLError::CallSite*> CallSiteVector;
@@ -501,7 +501,7 @@ namespace
LevelMap mClassLevelMap;
LevelMap mFileLevelMap;
LevelMap mTagLevelMap;
- std::map<std::string, unsigned int> mUniqueLogMessages;
+ std::unordered_map<std::string, unsigned int> mUniqueLogMessages;
LLError::FatalFunction mCrashFunction;
LLError::TimeFunction mTimeFunction;
@@ -1404,7 +1404,7 @@ namespace LLError
{
std::ostringstream message_stream;
- std::map<std::string, unsigned int>::iterator messageIter = s->mUniqueLogMessages.find(message);
+ auto messageIter = s->mUniqueLogMessages.find(message);
if (messageIter != s->mUniqueLogMessages.end())
{
messageIter->second++;
diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h
index d254fa5407..3c58d1df22 100644
--- a/indra/llcommon/llerrorcontrol.h
+++ b/indra/llcommon/llerrorcontrol.h
@@ -70,7 +70,6 @@ namespace LLError
Setting a level means log messages at that level or above.
*/
- LL_COMMON_API void setPrintLocation(bool);
LL_COMMON_API void setDefaultLevel(LLError::ELevel);
LL_COMMON_API ELevel getDefaultLevel();
LL_COMMON_API void setAlwaysFlush(bool flush);
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index a539e4fe28..f752e31563 100644
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -187,13 +187,34 @@ static unsigned short get_fileattr(const std::wstring& utf16path, bool dontFollo
CloseHandle(file_handle);
return st_mode;
}
+ // Retrieve last error before calling CloseHandle()
+ DWORD last_error = GetLastError();
+ CloseHandle(file_handle);
+ set_errno_from_oserror(last_error);
+ }
+ else
+ {
+ set_errno_from_oserror(GetLastError());
}
- // Retrieve last error and set errno before calling CloseHandle()
- set_errno_from_oserror(GetLastError());
- if (file_handle != INVALID_HANDLE_VALUE)
+ // If CreateFileW approach failed (e.g., exFAT), try the simpler GetFileAttributesW()
+ // GetFileAttributesW() always follows symlinks, so we skip this fallback when dontFollowSymLink is true.
+ if (!dontFollowSymLink)
{
- CloseHandle(file_handle);
+ DWORD attributes = GetFileAttributesW(utf16path.c_str());
+ if (attributes != INVALID_FILE_ATTRIBUTES)
+ {
+ bool is_directory = (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ unsigned short st_mode = is_directory ? S_IFDIR : S_IFREG;
+ st_mode |= (attributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE;
+
+ // propagate user bits to group/other fields:
+ st_mode |= (st_mode & 0700) >> 3;
+ st_mode |= (st_mode & 0700) >> 6;
+
+ return st_mode;
+ }
+ set_errno_from_oserror(GetLastError());
}
return 0;
}
diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp
index 823bea7a3c..03dd7856b6 100644
--- a/indra/llcommon/llheteromap.cpp
+++ b/indra/llcommon/llheteromap.cpp
@@ -27,6 +27,6 @@ LLHeteroMap::~LLHeteroMap()
// pair.second is the std::pair; pair.second.first is the void*;
// pair.second.second points to the deleter function
(pair.second.second)(pair.second.first);
- pair.second.first = NULL;
+ pair.second.first = nullptr;
}
}
diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h
index d8e6fefb17..211dfaae83 100644
--- a/indra/llcommon/llheteromap.h
+++ b/indra/llcommon/llheteromap.h
@@ -12,9 +12,10 @@
#if ! defined(LL_LLHETEROMAP_H)
#define LL_LLHETEROMAP_H
+#include <typeindex>
#include <typeinfo>
#include <utility> // std::pair
-#include <map>
+#include <unordered_map>
/**
* LLHeteroMap addresses an odd requirement. Usually when you want to put
@@ -43,7 +44,7 @@ public:
// Look up map entry by typeid(T). We don't simply use mMap[typeid(T)]
// because that requires default-constructing T on every lookup. For
// some kinds of T, that could be expensive.
- TypeMap::iterator found = mMap.find(&typeid(T));
+ TypeMap::iterator found = mMap.find(typeid(T));
if (found == mMap.end())
{
// Didn't find typeid(T). Create an entry. Because we're storing
@@ -52,8 +53,8 @@ public:
void* ptr = new T();
void (*dlfn)(void*) = &deleter<T>;
std::pair<TypeMap::iterator, bool> inserted =
- mMap.insert(TypeMap::value_type(&typeid(T),
- TypeMap::mapped_type(ptr, dlfn)));
+ mMap.emplace(typeid(T),
+ TypeMap::mapped_type(ptr, dlfn));
// Okay, now that we have an entry, claim we found it.
found = inserted.first;
}
@@ -71,23 +72,9 @@ private:
delete static_cast<T*>(p);
}
- // Comparing two std::type_info* values is tricky, because the standard
- // does not guarantee that there will be only one type_info instance for a
- // given type. In other words, &typeid(A) in one part of the program may
- // not always equal &typeid(A) in some other part. Use special comparator.
- struct type_info_ptr_comp
- {
- bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
- {
- return lhs->before(*rhs);
- }
- };
-
- // What we actually store is a map from std::type_info (permitting lookup
+ // What we actually store is a map from std::type_index (permitting lookup
// by object type) to a void* pointer to the object PLUS its deleter.
- typedef std::map<
- const std::type_info*, std::pair<void*, void (*)(void*)>,
- type_info_ptr_comp>
+ typedef std::unordered_map<std::type_index, std::pair<void*, void (*)(void*)>>
TypeMap;
TypeMap mMap;
};
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index b01ea0bfb1..b220afadfc 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -34,7 +34,6 @@
#include <list>
#include <unordered_map>
#include <boost/function.hpp>
-#include <boost/unordered_map.hpp>
#include "llerror.h"
#include "llstl.h"
@@ -267,7 +266,7 @@ namespace LLInitParam
private:
struct Inaccessable{};
public:
- typedef std::map<std::string, T> value_name_map_t;
+ typedef std::unordered_map<std::string, T> value_name_map_t;
typedef Inaccessable name_t;
typedef TypeValues<T> type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -294,7 +293,7 @@ namespace LLInitParam
static std::vector<std::string>* getPossibleValues()
{
- return NULL;
+ return nullptr;
}
void assignNamedValue(const Inaccessable& name)
@@ -310,7 +309,7 @@ namespace LLInitParam
return param_value_t::getValue();
}
- static value_name_map_t* getValueNames() {return NULL;}
+ static value_name_map_t* getValueNames() { return nullptr; }
};
// helper class to implement name value lookups
@@ -321,7 +320,7 @@ namespace LLInitParam
{
typedef TypeValuesHelper<T, DERIVED_TYPE, IS_SPECIALIZED> self_t;
public:
- typedef typename std::map<std::string, T> value_name_map_t;
+ typedef typename std::unordered_map<std::string, T> value_name_map_t;
typedef std::string name_t;
typedef self_t type_value_t;
typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t;
@@ -497,9 +496,9 @@ namespace LLInitParam
typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);
typedef std::function<void (name_stack_t&, S32, S32, const possible_values_t*)> parser_inspect_func_t;
- typedef std::map<const std::type_info*, parser_read_func_t> parser_read_func_map_t;
- typedef std::map<const std::type_info*, parser_write_func_t> parser_write_func_map_t;
- typedef std::map<const std::type_info*, parser_inspect_func_t> parser_inspect_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_read_func_t> parser_read_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_write_func_t> parser_write_func_map_t;
+ typedef std::unordered_map<std::type_index, parser_inspect_func_t> parser_inspect_func_map_t;
public:
@@ -514,7 +513,7 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<!std::is_enum_v<T>>* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
@@ -525,14 +524,14 @@ namespace LLInitParam
template <typename T> bool readValue(T& param, typename std::enable_if_t<std::is_enum_v<T> >* dummy = 0)
{
- parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
+ parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(typeid(T));
if (found_it != mParserReadFuncs->end())
{
return found_it->second(*this, (void*)&param);
}
else
{
- found_it = mParserReadFuncs->find(&typeid(S32));
+ found_it = mParserReadFuncs->find(typeid(S32));
if (found_it != mParserReadFuncs->end())
{
S32 int_value;
@@ -546,7 +545,7 @@ namespace LLInitParam
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
{
- parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
+ parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(typeid(T));
if (found_it != mParserWriteFuncs->end())
{
return found_it->second(*this, (const void*)&param, name_stack);
@@ -557,7 +556,7 @@ namespace LLInitParam
// dispatch inspection to registered inspection functions, for each parameter in a param block
template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values)
{
- parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
+ parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(typeid(T));
if (found_it != mParserInspectFuncs->end())
{
found_it->second(name_stack, min_count, max_count, possible_values);
@@ -574,16 +573,16 @@ namespace LLInitParam
protected:
template <typename T>
- void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
+ void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = nullptr)
{
- mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
- mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
+ mParserReadFuncs->emplace(typeid(T), read_func);
+ mParserWriteFuncs->emplace(typeid(T), write_func);
}
template <typename T>
void registerInspectFunc(parser_inspect_func_t inspect_func)
{
- mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
+ mParserInspectFuncs->emplace(typeid(T), inspect_func);
}
bool mParseSilently;
@@ -614,7 +613,7 @@ namespace LLInitParam
{
struct UserData
{
- virtual ~UserData() {}
+ virtual ~UserData() = default;
};
typedef bool(*merge_func_t)(Param&, const Param&, bool);
@@ -665,7 +664,7 @@ namespace LLInitParam
void aggregateBlockData(BlockDescriptor& src_block_data);
void addParam(ParamDescriptorPtr param, const char* name);
- typedef boost::unordered_map<const std::string, ParamDescriptorPtr> param_map_t;
+ typedef std::unordered_map<std::string, ParamDescriptorPtr, ll::string_hash, std::equal_to<>> param_map_t;
typedef std::vector<ParamDescriptorPtr> param_list_t;
typedef std::list<ParamDescriptorPtr> all_params_list_t;
typedef std::vector<std::pair<param_handle_t, ParamDescriptor::validation_func_t> > param_validation_list_t;
@@ -679,38 +678,26 @@ namespace LLInitParam
class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed
};
- //TODO: implement in terms of owned_ptr
- template<typename T>
+ // TODO: implement in terms of owned_ptr
+ template<typename T>
class LazyValue
- {
- public:
- LazyValue()
- : mPtr(NULL)
- {}
+ {
+ public:
+ LazyValue() = default;
- ~LazyValue()
- {
- delete mPtr;
- }
+ ~LazyValue() { delete mPtr; }
- LazyValue(const T& value)
- {
- mPtr = new T(value);
- }
+ LazyValue(const T& value) { mPtr = new T(value); }
- LazyValue(const LazyValue& other)
- : mPtr(NULL)
- {
- *this = other;
- }
+ LazyValue(const LazyValue& other) : mPtr(nullptr) { *this = other; }
- LazyValue& operator = (const LazyValue& other)
- {
+ LazyValue& operator=(const LazyValue& other)
+ {
if (!other.mPtr)
{
delete mPtr;
- mPtr = NULL;
- }
+ mPtr = nullptr;
+ }
else
{
if (!mPtr)
@@ -721,23 +708,21 @@ namespace LLInitParam
{
*mPtr = *(other.mPtr);
}
- }
- return *this;
}
+ return *this;
+ }
bool operator==(const LazyValue& other) const
{
- if (empty() || other.empty()) return false;
+ if (empty() || other.empty())
+ return false;
return *mPtr == *other.mPtr;
}
- bool empty() const
- {
- return mPtr == NULL;
- }
+ bool empty() const { return mPtr == nullptr; }
- void set(const T& other)
- {
+ void set(const T& other)
+ {
if (!mPtr)
{
mPtr = new T(other);
@@ -748,36 +733,26 @@ namespace LLInitParam
}
}
- const T& get() const
- {
- return *ensureInstance();
- }
+ const T& get() const { return *ensureInstance(); }
- T& get()
- {
- return *ensureInstance();
- }
+ T& get() { return *ensureInstance(); }
- operator const T&() const
- {
- return get();
- }
+ operator const T&() const { return get(); }
- private:
- // lazily allocate an instance of T
- T* ensureInstance() const
+ private:
+ // lazily allocate an instance of T
+ T* ensureInstance() const
+ {
+ if (mPtr == nullptr)
{
- if (mPtr == NULL)
- {
- mPtr = new T();
- }
- return mPtr;
+ mPtr = new T();
}
+ return mPtr;
+ }
- private:
-
- mutable T* mPtr;
- };
+ private:
+ mutable T* mPtr = nullptr;
+ };
// root class of all parameter blocks
@@ -864,7 +839,7 @@ namespace LLInitParam
mParamProvided(false)
{}
- virtual ~BaseBlock() {}
+ virtual ~BaseBlock() = default;
bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false);
param_handle_t getHandleFromParam(const Param* param) const;
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 048547e4cc..d2dcf530e5 100644
--- a/indra/llcommon/llpointer.h
+++ b/indra/llcommon/llpointer.h
@@ -26,8 +26,9 @@
#ifndef LLPOINTER_H
#define LLPOINTER_H
-#include "llerror.h" // *TODO: consider eliminating this
-#include "llmutex.h"
+#include <functional>
+#include <string_view>
+#include <utility> // std::swap()
//----------------------------------------------------------------------------
// RefCount objects should generally only be accessed by way of LLPointer<>'s
@@ -42,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 Type> class LLPointer
+template <class Type>
+class LLPointer: public LLPointerBase
{
public:
template<typename Subclass>
@@ -60,6 +71,13 @@ public:
ref();
}
+ // Even though the template constructors below accepting
+ // (const LLPointer<Subclass>&) and (LLPointer<Subclass>&&) appear to
+ // subsume these specific (const LLPointer<Type>&) and (LLPointer<Type>&&)
+ // constructors, the compiler recognizes these as The Copy Constructor and
+ // The Move Constructor, respectively. In other words, even in the
+ // presence of the LLPointer<Subclass> constructors, we still must specify
+ // the LLPointer<Type> constructors.
LLPointer(const LLPointer<Type>& ptr) :
mPointer(ptr.mPointer)
{
@@ -98,39 +116,52 @@ 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); }
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<Type>& ptr) const { return (mPointer == ptr.mPointer); }
- bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
- bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
+ template <typename Type1>
+ bool operator !=(Type1* ptr) const { return (mPointer != ptr); }
+ template <typename Type1>
+ bool operator ==(Type1* ptr) const { return (mPointer == ptr); }
+ template <typename Type1>
+ bool operator !=(const LLPointer<Type1>& ptr) const { return (mPointer != ptr.mPointer); }
+ template <typename Type1>
+ bool operator ==(const LLPointer<Type1>& ptr) const { return (mPointer == ptr.mPointer); }
+ bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
+ bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
LLPointer<Type>& 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;
}
+ // Even though the template assignment operators below accepting
+ // (const LLPointer<Subclass>&) and (LLPointer<Subclass>&&) appear to
+ // subsume these specific (const LLPointer<Type>&) and (LLPointer<Type>&&)
+ // assignment operators, the compiler recognizes these as Copy Assignment
+ // and Move Assignment, respectively. In other words, even in the presence
+ // of the LLPointer<Subclass> assignment operators, we still must specify
+ // the LLPointer<Type> operators.
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
{
- assign(ptr);
+ LLPointer temp(ptr);
+ using std::swap; // per Swappable convention
+ swap(*this, temp);
return *this;
}
LLPointer<Type>& operator =(LLPointer<Type>&& 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;
}
@@ -138,28 +169,32 @@ public:
template<typename Subclass>
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
{
- assign(ptr.get());
+ LLPointer temp(ptr);
+ using std::swap; // per Swappable convention
+ swap(*this, temp);
return *this;
}
template<typename Subclass>
LLPointer<Type>& operator =(LLPointer<Subclass>&& 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<Type>& a, LLPointer<Type>& 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<Type>& a, LLPointer<Type>& b)
+ {
+ LLPointer<Type>::swap(a, b);
}
protected:
@@ -184,191 +219,19 @@ 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();
}
}
}
#endif // LL_LIBRARY_INCLUDE
- void assign(const LLPointer<Type>& ptr)
- {
- if (mPointer != ptr.mPointer)
- {
- unref();
- mPointer = ptr.mPointer;
- ref();
- }
- }
-
protected:
Type* mPointer;
};
-template <class Type> class LLConstPointer
-{
- template<typename Subclass>
- friend class LLConstPointer;
-public:
- LLConstPointer() :
- mPointer(nullptr)
- {
- }
-
- LLConstPointer(const Type* ptr) :
- mPointer(ptr)
- {
- ref();
- }
-
- LLConstPointer(const LLConstPointer<Type>& ptr) :
- mPointer(ptr.mPointer)
- {
- ref();
- }
-
- LLConstPointer(LLConstPointer<Type>&& ptr) noexcept
- {
- mPointer = ptr.mPointer;
- ptr.mPointer = nullptr;
- }
-
- // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
- template<typename Subclass>
- LLConstPointer(const LLConstPointer<Subclass>& ptr) :
- mPointer(ptr.get())
- {
- ref();
- }
-
- template<typename Subclass>
- LLConstPointer(LLConstPointer<Subclass>&& 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<Type>& ptr) const { return (mPointer == ptr.mPointer); }
- bool operator < (const LLConstPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
- bool operator > (const LLConstPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
-
- LLConstPointer<Type>& operator =(const Type* ptr)
- {
- if( mPointer != ptr )
- {
- unref();
- mPointer = ptr;
- ref();
- }
-
- return *this;
- }
-
- LLConstPointer<Type>& operator =(const LLConstPointer<Type>& ptr)
- {
- if( mPointer != ptr.mPointer )
- {
- unref();
- mPointer = ptr.mPointer;
- ref();
- }
- return *this;
- }
-
- LLConstPointer<Type>& operator =(LLConstPointer<Type>&& 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<typename Subclass>
- LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr)
- {
- if( mPointer != ptr.get() )
- {
- unref();
- mPointer = ptr.get();
- ref();
- }
- return *this;
- }
-
- template<typename Subclass>
- LLConstPointer<Type>& operator =(LLConstPointer<Subclass>&& 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<Type>& a, LLConstPointer<Type>& 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 <typename Type>
+using LLConstPointer = LLPointer<const Type>;
template<typename Type>
class LLCopyOnWritePointer : public LLPointer<Type>
@@ -418,38 +281,26 @@ private:
bool mStayUnique;
};
-template<typename Type>
-bool operator!=(Type* lhs, const LLPointer<Type>& rhs)
+template<typename Type0, typename Type1>
+bool operator!=(Type0* lhs, const LLPointer<Type1>& rhs)
{
return (lhs != rhs.get());
}
-template<typename Type>
-bool operator==(Type* lhs, const LLPointer<Type>& rhs)
+template<typename Type0, typename Type1>
+bool operator==(Type0* lhs, const LLPointer<Type1>& rhs)
{
return (lhs == rhs.get());
}
-// boost hash adapter
-template <class Type>
-struct boost::hash<LLPointer<Type>>
-{
- typedef LLPointer<Type> 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<class Type> struct hash<LLPointer<Type>>
{
std::size_t operator()(LLPointer<Type> const& s) const noexcept
{
- return boost::hash<LLPointer<Type>>()(s);
+ return std::hash<Type*>()(s.get());
}
};
}
diff --git a/indra/llcommon/llpounceable.h b/indra/llcommon/llpounceable.h
index e86098f20b..20561b0c65 100644
--- a/indra/llcommon/llpounceable.h
+++ b/indra/llcommon/llpounceable.h
@@ -38,9 +38,9 @@
#include "llsingleton.h"
#include <boost/call_traits.hpp>
#include <boost/utility/value_init.hpp>
-#include <boost/unordered_map.hpp>
#include <boost/signals2/signal.hpp>
+#include <unordered_map>
#include <type_traits>
// Forward declare the user template, since we want to be able to point to it
@@ -86,7 +86,7 @@ class LLPounceableQueueSingleton:
// instance will call on the SAME LLPounceableQueueSingleton instance --
// given how class statics work. We must keep a separate queue for each
// LLPounceable instance. Use a hash map for that.
- typedef boost::unordered_map<owner_ptr, signal_t> map_t;
+ typedef std::unordered_map<owner_ptr, signal_t> map_t;
public:
// Disambiguate queues belonging to different LLPounceables.
diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp
index 3120fa0100..cbba2ceb87 100644
--- a/indra/llcommon/llprocess.cpp
+++ b/indra/llcommon/llprocess.cpp
@@ -176,13 +176,13 @@ public:
// In general, our streambuf might contain a number of different
// physical buffers; iterate over those.
bool keepwriting = true;
- for (auto bufi = buffer_sequence_begin(bufs), bufend = buffer_sequence_end(bufs);
+ for (auto bufi(boost::asio::buffer_sequence_begin(bufs)), bufend(boost::asio::buffer_sequence_end(bufs));
bufi != bufend && keepwriting; ++bufi)
{
// http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents
// Although apr_file_write() accepts const void*, we
// manipulate const char* so we can increment the pointer.
- const char* remainptr = static_cast<const char*>((*bufi).data());
+ const char* remainptr = static_cast<const char*>(bufi->data());
std::size_t remainlen = boost::asio::buffer_size(*bufi);
while (remainlen)
{
@@ -377,14 +377,14 @@ public:
// In general, the mutable_buffer_sequence returned by prepare() might
// contain a number of different physical buffers; iterate over those.
std::size_t tocommit(0);
- for (auto bufi = buffer_sequence_begin(bufs), bufend = buffer_sequence_end(bufs);
+ for (auto bufi(boost::asio::buffer_sequence_begin(bufs)), bufend(boost::asio::buffer_sequence_end(bufs));
bufi != bufend; ++bufi)
{
// http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents
std::size_t toread(boost::asio::buffer_size(*bufi));
apr_size_t gotten(toread);
apr_status_t err = apr_file_read(mPipe,
- static_cast<void*>((*bufi).data()),
+ bufi->data(),
&gotten);
// EAGAIN is exactly what we want from a nonblocking pipe.
// Rather than waiting for data, it should return immediately.
@@ -657,10 +657,7 @@ LLProcess::LLProcess(const LLSDOrParams& params):
// case), e.g. by calling operator(), returns a reference to *the same
// instance* of the wrapped type that's stored in our Block subclass.
// That's important! We know 'params' persists throughout this method
- // call; but without that guarantee, we'd have to assume that converting
- // one of its members to std::string might return a different (temp)
- // instance. Capturing the c_str() from a temporary std::string is Bad Bad
- // Bad. But armed with this knowledge, when you see params.cwd().c_str(),
+ // call; but without that guarantee, when you see params.cwd().c_str(),
// grit your teeth and smile and carry on.
if (params.cwd.isProvided())
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index 35335e1213..92f8ae3245 100644
--- a/indra/llcommon/llregistry.h
+++ b/indra/llcommon/llregistry.h
@@ -32,21 +32,11 @@
#include "llsingleton.h"
#include "llstl.h"
-template <typename T>
-struct LLRegistryDefaultComparator
-{
- bool operator()(const T& lhs, const T& rhs) const
- {
- using std::less;
- return less<T>()(lhs, rhs);
- }
-};
-
-template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE>
class LLRegistry
{
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef const VALUE* ptr_const_value_t;
@@ -54,9 +44,9 @@ public:
class Registrar
{
- friend class LLRegistry<KEY, VALUE, COMPARATOR>;
+ friend class LLRegistry<KEY, VALUE>;
public:
- typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
+ typedef std::map<KEY, VALUE> registry_map_t;
bool add(ref_const_key_t key, ref_const_value_t value)
{
@@ -234,9 +224,9 @@ private:
Registrar mDefaultRegistrar;
};
-template <typename KEY, typename VALUE, typename DERIVED_TYPE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> >
+template <typename KEY, typename VALUE, typename DERIVED_TYPE>
class LLRegistrySingleton
- : public LLRegistry<KEY, VALUE, COMPARATOR>,
+ : public LLRegistry<KEY, VALUE>,
public LLSingleton<DERIVED_TYPE>
{
// This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton)
@@ -244,7 +234,7 @@ class LLRegistrySingleton
// LLRegistrySingleton. So each concrete subclass needs
// LLSINGLETON(whatever) -- not this intermediate base class.
public:
- typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t;
+ typedef LLRegistry<KEY, VALUE> registry_t;
typedef const KEY& ref_const_key_t;
typedef const VALUE& ref_const_value_t;
typedef VALUE* ptr_value_t;
@@ -309,7 +299,7 @@ public:
};
// convenience functions
- typedef typename LLRegistry<KEY, VALUE, COMPARATOR>::Registrar& ref_registrar_t;
+ typedef typename LLRegistry<KEY, VALUE>::Registrar& ref_registrar_t;
static ref_registrar_t currentRegistrar()
{
return singleton_t::instance().registry_t::currentRegistrar();
diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp
index 77fe545c3f..ce39bc7af3 100644
--- a/indra/llcommon/llsd.cpp
+++ b/indra/llcommon/llsd.cpp
@@ -39,6 +39,9 @@
#include <limits>
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
+
// Defend against a caller forcibly passing a negative number into an unsigned
// size_t index param
inline
@@ -103,6 +106,9 @@ protected:
U32 mUseCount;
public:
+ static void destruct(Impl*& var);
+ ///< safely decrement or destroy var
+
static void reset(Impl*& var, Impl* impl);
///< safely set var to refer to the new impl (possibly shared)
@@ -166,7 +172,7 @@ public:
virtual const LLSD& ref(size_t) const { return undef(); }
virtual LLSD::map_const_iterator beginMap() const { return endMap(); }
- virtual LLSD::map_const_iterator endMap() const { static const std::map<String, LLSD> empty; return empty.end(); }
+ virtual LLSD::map_const_iterator endMap() const { static const LLSD::llsd_map_t empty; return empty.end(); }
virtual LLSD::array_const_iterator beginArray() const { return endArray(); }
virtual LLSD::array_const_iterator endArray() const { static const std::vector<LLSD> empty; return empty.end(); }
@@ -345,18 +351,7 @@ namespace
LLSD::Real ImplString::asReal() const
{
- F64 v = 0.0;
- std::istringstream i_stream(mValue);
- i_stream >> v;
-
- // we would probably like to ignore all trailing whitespace as
- // well, but for now, simply eat the next character, and make
- // sure we reached the end of the string.
- // *NOTE: gcc 2.95 does not generate an eof() event on the
- // stream operation above, so we manually get here to force it
- // across platforms.
- int c = i_stream.get();
- return ((EOF ==c) ? v : 0.0);
+ return llsd::string_to_real(mValue);
}
@@ -431,7 +426,7 @@ namespace
class ImplMap final : public LLSD::Impl
{
private:
- typedef std::map<LLSD::String, LLSD, std::less<>> DataMap;
+ using DataMap = LLSD::llsd_map_t;
DataMap mData;
@@ -457,7 +452,7 @@ namespace
<< it.second.asXMLRPCValue() << "</member>";
}
os << "</struct>";
- return os.str();
+ return std::move(os).str();
}
virtual bool has(std::string_view) const;
@@ -467,8 +462,13 @@ namespace
using LLSD::Impl::ref; // Unhiding ref(size_t)
virtual LLSD get(std::string_view) const;
virtual LLSD getKeys() const;
+ void insert(std::string&& k, const LLSD& v);
+ void insert(std::string&& k, LLSD&& v);
void insert(std::string_view k, const LLSD& v);
+ void insert(std::string_view k, LLSD&& v);
virtual void erase(const LLSD::String&);
+ LLSD& ref(std::string&&);
+ virtual const LLSD& ref(std::string&&) const;
LLSD& ref(std::string_view);
virtual const LLSD& ref(std::string_view) const;
@@ -525,18 +525,58 @@ namespace
return keys;
}
+ void ImplMap::insert(std::string&& k, const LLSD& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), v);
+ }
+
+ void ImplMap::insert(std::string&& k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(std::move(k), std::move(v));
+ }
+
void ImplMap::insert(std::string_view k, const LLSD& v)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.emplace(k, v);
}
+ void ImplMap::insert(std::string_view k, LLSD&& v)
+ {
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ mData.emplace(k, std::move(v));
+ }
+
void ImplMap::erase(const LLSD::String& k)
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
mData.erase(k);
}
+ LLSD& ImplMap::ref(std::string&& k)
+ {
+ DataMap::iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return mData.emplace_hint(i, std::make_pair(std::move(k), LLSD()))->second;
+ }
+
+ return i->second;
+ }
+
+ const LLSD& ImplMap::ref(std::string&& k) const
+ {
+ DataMap::const_iterator i = mData.lower_bound(k);
+ if (i == mData.end() || mData.key_comp()(k, i->first))
+ {
+ return undef();
+ }
+
+ return i->second;
+ }
+
LLSD& ImplMap::ref(std::string_view k)
{
DataMap::iterator i = mData.lower_bound(k);
@@ -598,7 +638,7 @@ namespace
ImplArray(const DataVector& data) : mData(data) { }
public:
- ImplArray() { }
+ ImplArray() = default;
virtual ImplArray& makeArray(Impl*&);
@@ -615,7 +655,7 @@ namespace
os << it.asXMLRPCValue();
}
os << "</data></array>";
- return os.str();
+ return std::move(os).str();
}
using LLSD::Impl::get; // Unhiding get(LLSD::String)
@@ -625,10 +665,13 @@ namespace
virtual LLSD get(size_t) const;
void set(size_t, const LLSD&);
void insert(size_t, const LLSD&);
+ void insert(size_t, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
virtual void erase(size_t);
LLSD& ref(size_t);
virtual const LLSD& ref(size_t) const;
+ void reserve(size_t size) { mData.reserve(size); }
LLSD::array_iterator beginArray() { return mData.begin(); }
LLSD::array_iterator endArray() { return mData.end(); }
@@ -690,12 +733,31 @@ namespace
mData.insert(mData.begin() + index, v);
}
+ void ImplArray::insert(size_t i, LLSD&& v)
+ {
+ NEGATIVE_EXIT(i);
+ DataVector::size_type index = i;
+
+ if (index >= mData.size()) // tbd - sanity check limit for index ?
+ {
+ mData.resize(index + 1);
+ }
+
+ mData.insert(mData.begin() + index, std::move(v));
+ }
+
LLSD& ImplArray::append(const LLSD& v)
{
mData.push_back(v);
return mData.back();
}
+ LLSD& ImplArray::append(LLSD&& v)
+ {
+ mData.push_back(std::move(v));
+ return mData.back();
+ }
+
void ImplArray::erase(size_t i)
{
NEGATIVE_EXIT(i);
@@ -763,6 +825,14 @@ LLSD::Impl::~Impl()
--sOutstandingCount;
}
+void LLSD::Impl::destruct(Impl*& var)
+{
+ if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0)
+ {
+ delete var;
+ }
+}
+
void LLSD::Impl::reset(Impl*& var, Impl* impl)
{
if (impl && impl->mUseCount != STATIC_USAGE_COUNT)
@@ -961,7 +1031,7 @@ namespace
LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; }
-LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); }
+LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::destruct(impl); }
LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); }
void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); }
@@ -1037,13 +1107,31 @@ LLSD LLSD::emptyMap()
bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); }
LLSD LLSD::get(const std::string_view k) const { return safe(impl).get(k); }
LLSD LLSD::getKeys() const { return safe(impl).getKeys(); }
+void LLSD::insert(std::string&& k, const LLSD& v) { makeMap(impl).insert(std::move(k), v); }
+void LLSD::insert(std::string&& k, LLSD&& v) { makeMap(impl).insert(std::move(k), std::move(v)); }
void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); }
+void LLSD::insert(std::string_view k, LLSD&& v) { makeMap(impl).insert(k, std::move(v)); }
+LLSD& LLSD::with(std::string&& k, const LLSD& v)
+ {
+ makeMap(impl).insert(std::move(k), v);
+ return *this;
+ }
+LLSD& LLSD::with(std::string&& k, LLSD&& v)
+ {
+ makeMap(impl).insert(std::move(k), std::move(v));
+ return *this;
+ }
LLSD& LLSD::with(std::string_view k, const LLSD& v)
{
makeMap(impl).insert(k, v);
return *this;
}
+LLSD& LLSD::with(std::string_view k, LLSD&& v)
+ {
+ makeMap(impl).insert(k, std::move(v));
+ return *this;
+ }
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
LLSD& LLSD::operator[](const std::string_view k)
@@ -1051,6 +1139,13 @@ LLSD& LLSD::operator[](const std::string_view k)
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
return makeMap(impl).ref(k);
}
+
+LLSD& LLSD::operator[](std::string&& k)
+{
+ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
+ return makeMap(impl).ref(std::move(k));
+}
+
const LLSD& LLSD::operator[](const std::string_view k) const
{
LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD;
@@ -1064,18 +1159,33 @@ LLSD LLSD::emptyArray()
return v;
}
+LLSD LLSD::emptyReservedArray(size_t size)
+{
+ LLSD v;
+ makeArray(v.impl).reserve(size);
+ return v;
+}
+
size_t LLSD::size() const { return safe(impl).size(); }
LLSD LLSD::get(Integer i) const { return safe(impl).get(i); }
void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); }
+void LLSD::set(Integer i, LLSD&& v) { makeArray(impl).set(i, std::move(v)); }
void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
+void LLSD::insert(Integer i, LLSD&& v) { makeArray(impl).insert(i, std::move(v)); }
LLSD& LLSD::with(Integer i, const LLSD& v)
{
makeArray(impl).insert(i, v);
return *this;
}
+LLSD& LLSD::with(Integer i, LLSD&& v)
+ {
+ makeArray(impl).insert(i, std::move(v));
+ return *this;
+ }
LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); }
+LLSD& LLSD::append(LLSD&& v) { return makeArray(impl).append(std::move(v)); }
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
LLSD& LLSD::operator[](size_t i)
@@ -1143,6 +1253,22 @@ LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl)
namespace llsd
{
+LLSD::Real string_to_real(std::string_view in_string)
+{
+ LLSD::Real v = 0.0;
+ boost::iostreams::stream<boost::iostreams::array_source> i_stream(in_string.data(), in_string.size());
+ i_stream >> v;
+
+ // we would probably like to ignore all trailing whitespace as
+ // well, but for now, simply eat the next character, and make
+ // sure we reached the end of the string.
+ // *NOTE: gcc 2.95 does not generate an eof() event on the
+ // stream operation above, so we manually get here to force it
+ // across platforms.
+ int c = i_stream.get();
+ return ((EOF == c) ? v : 0.0);
+}
+
U32 allocationCount() { return LLSD::Impl::sAllocationCount; }
U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; }
diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h
index d2b3548831..afe35a65ba 100644
--- a/indra/llcommon/llsd.h
+++ b/indra/llcommon/llsd.h
@@ -34,6 +34,7 @@
#include "stdtypes.h"
#include "lldate.h"
+#include "llstl.h"
#include "lluri.h"
#include "lluuid.h"
@@ -321,11 +322,34 @@ public:
bool has(const std::string_view) const;
LLSD get(const std::string_view) const;
LLSD getKeys() const; // Return an LLSD array with keys as strings
+ void insert(const char* k, const LLSD& v)
+ {
+ return insert(std::string_view(k), v);
+ }
+ void insert(const char* k , LLSD&& v)
+ {
+ return insert(std::string_view(k), std::move(v));
+ }
+ void insert(std::string&&, const LLSD&);
+ void insert(std::string&&, LLSD&&);
void insert(std::string_view, const LLSD&);
+ void insert(std::string_view, LLSD&&);
void erase(const String&);
+ LLSD& with(const char* k, const LLSD& v)
+ {
+ return with(std::string_view(k), v);
+ }
+ LLSD& with(const char* k, LLSD&& v)
+ {
+ return with(std::string_view(k), std::move(v));
+ }
+ LLSD& with(std::string&&, const LLSD&);
+ LLSD& with(std::string&&, LLSD&&);
LLSD& with(std::string_view, const LLSD&);
+ LLSD& with(std::string_view, LLSD&&);
LLSD& operator[](const std::string_view);
+ LLSD& operator[](std::string&&);
LLSD& operator[](const char* c)
{
return c ? (*this)[std::string_view(c)] : *this;
@@ -339,14 +363,22 @@ public:
/** @name Array Values */
//@{
+ // Allocate an empty array
static LLSD emptyArray();
+ // Allocate an array with internal storage reserved but not initialized like a std::vector
+ static LLSD emptyReservedArray(size_t size);
+
LLSD get(Integer) const;
void set(Integer, const LLSD&);
+ void set(Integer, LLSD&&);
void insert(Integer, const LLSD&);
+ void insert(Integer, LLSD&&);
LLSD& append(const LLSD&);
+ LLSD& append(LLSD&&);
void erase(Integer);
LLSD& with(Integer, const LLSD&);
+ LLSD& with(Integer, LLSD&&);
// accept size_t so we can index relative to size()
const LLSD& operator[](size_t) const;
@@ -366,8 +398,9 @@ public:
//@{
size_t size() const;
- typedef std::map<String, LLSD>::iterator map_iterator;
- typedef std::map<String, LLSD>::const_iterator map_const_iterator;
+ using llsd_map_t = std::map<String, LLSD, std::less<>>;
+ typedef llsd_map_t::iterator map_iterator;
+ typedef llsd_map_t::const_iterator map_const_iterator;
map_iterator beginMap();
map_iterator endMap();
@@ -512,6 +545,8 @@ LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd);
namespace llsd
{
+ // Used by LLSD::ImplString to convert string type to real
+ LLSD::Real string_to_real(std::string_view in_string);
#ifdef LLSD_DEBUG_INFO
/** @name Unit Testing Interface */
diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp
index a4b45ed80d..71f35802c5 100644
--- a/indra/llcommon/llsdjson.cpp
+++ b/indra/llcommon/llsdjson.cpp
@@ -70,7 +70,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
const boost::json::array& array = val.as_array();
size_t size = array.size();
// allocate elements 0 .. (size() - 1) to avoid incremental allocation
- if (! array.empty())
+ if (!array.empty())
{
result[size - 1] = LLSD();
}
@@ -84,7 +84,7 @@ LLSD LlsdFromJson(const boost::json::value& val)
result = LLSD::emptyMap();
for (const auto& element : val.as_object())
{
- result[element.key()] = LlsdFromJson(element.value());
+ result[std::string_view(element.key())] = LlsdFromJson(element.value());
}
break;
}
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index 68a7bf0adf..f850238dff 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -775,7 +775,8 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c
// There must be a value for every key, thus
// child_count must be greater than 0.
parse_count += count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child)); // Move as name will be filled on next iteration
+ name.clear();
}
else
{
@@ -822,7 +823,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept
else
{
parse_count += count;
- array.append(child);
+ array.append(std::move(child));
}
c = get(istr);
}
@@ -841,7 +842,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const
auto count = deserialize_string(istr, value, mMaxBytesLeft);
if(PARSE_FAILURE == count) return false;
account(count);
- data = value;
+ data = std::move(value);
return true;
}
@@ -872,10 +873,10 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
if(len)
{
value.resize(len);
- account(fullread(istr, (char *)&value[0], len));
+ account(fullread(istr, (char*)value.data(), len));
}
c = get(istr); // strip off the trailing double-quote
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b64", buf, 3))
{
@@ -885,7 +886,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
std::stringstream coded_stream;
get(istr, *(coded_stream.rdbuf()), '\"');
c = get(istr);
- std::string encoded(coded_stream.str());
+ std::string encoded(std::move(coded_stream).str());
S32 len = apr_base64_decode_len(encoded.c_str());
std::vector<U8> value;
if(len)
@@ -894,7 +895,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
len = apr_base64_decode_binary(&value[0], encoded.c_str());
value.resize(len);
}
- data = value;
+ data = std::move(value);
}
else if(0 == strncmp("b16", buf, 3))
{
@@ -925,7 +926,7 @@ bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const
// copy the data out of the byte buffer
value.insert(value.end(), byte_buffer, write);
}
- data = value;
+ data = std::move(value);
}
else
{
@@ -1077,7 +1078,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
}
else
{
- data = value;
+ data = std::move(value);
account(cnt);
}
if(istr.fail())
@@ -1094,7 +1095,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
std::string value;
if(parseString(istr, value))
{
- data = value;
+ data = std::move(value);
}
else
{
@@ -1159,7 +1160,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con
value.resize(size);
account(fullread(istr, (char*)&value[0], size));
}
- data = value;
+ data = std::move(value);
}
if(istr.fail())
{
@@ -1218,7 +1219,7 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
// There must be a value for every key, thus child_count
// must be greater than 0.
parse_count += child_count;
- map.insert(name, child);
+ map.insert(std::move(name), std::move(child));
}
else
{
@@ -1238,13 +1239,12 @@ S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) con
S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const
{
- array = LLSD::emptyArray();
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
- // *FIX: This would be a good place to reserve some space in the
- // array...
+ // Preallocate array to avoid incremental allocation
+ array = LLSD::emptyReservedArray(size);
S32 parse_count = 0;
S32 count = 0;
@@ -1260,7 +1260,7 @@ S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth)
if(child_count)
{
parse_count += child_count;
- array.append(child);
+ array.append(std::move(child));
}
++count;
c = istr.peek();
@@ -1279,18 +1279,15 @@ bool LLSDBinaryParser::parseString(
std::istream& istr,
std::string& value) const
{
- // *FIX: This is memory inefficient.
U32 value_nbo = 0;
read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/
S32 size = (S32)ntohl(value_nbo);
if(mCheckLimits && (size > mMaxBytesLeft)) return false;
if(size < 0) return false;
- std::vector<char> buf;
if(size)
{
- buf.resize(size);
- account(fullread(istr, &buf[0], size));
- value.assign(buf.begin(), buf.end());
+ value.resize(size);
+ account(fullread(istr, value.data(), size));
}
return true;
}
@@ -1785,7 +1782,7 @@ llssize deserialize_string_delim(
}
}
- value = write_buffer.str();
+ value = std::move(write_buffer).str();
return count;
}
@@ -1806,15 +1803,12 @@ llssize deserialize_string_raw(
{
// We probably have a valid raw string. determine
// the size, and read it.
- // *FIX: This is memory inefficient.
- auto len = strtol(buf + 1, NULL, 0);
+ auto len = strtol(buf + 1, nullptr, 0);
if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE;
- std::vector<char> buf;
if(len)
{
- buf.resize(len);
- count += fullread(istr, (char *)&buf[0], len);
- value.assign(buf.begin(), buf.end());
+ value.resize(len);
+ count += fullread(istr, value.data(), len);
}
c = istr.get();
++count;
@@ -2170,7 +2164,7 @@ std::string zip_llsd(LLSD& data)
return std::string();
}
- std::string source = llsd_strm.str();
+ std::string source = std::move(llsd_strm).str();
U8 out[CHUNK];
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index ce416baa04..afe4fd63a6 100644
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -31,6 +31,8 @@
#include <deque>
#include "apr_base64.h"
+#include <boost/iostreams/device/array.hpp>
+#include <boost/iostreams/stream.hpp>
#include <boost/regex.hpp>
extern "C"
@@ -645,7 +647,7 @@ void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Ch
if (mCurrentKey.empty()) { return startSkipping(); }
LLSD& map = *mStack.back();
- LLSD& newElement = map[mCurrentKey];
+ LLSD& newElement = map[std::move(mCurrentKey)];
mStack.push_back(&newElement);
mCurrentKey.clear();
@@ -709,7 +711,8 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
return;
case ELEMENT_KEY:
- mCurrentKey = mCurrentContent;
+ mCurrentKey = std::move(mCurrentContent); // This is safe to move as we are in the end element handler
+ mCurrentContent.clear(); // Ensure mCurrentContent is empty for subsequent use
return;
default:
@@ -742,14 +745,22 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
}
else
{
- value = LLSD(mCurrentContent).asInteger();
+ // This must treat "1.23" not as an error, but as a number, which is
+ // then truncated down to an integer. Hence, this code doesn't call
+ // std::istringstream::operator>>(int&), which would not consume the
+ // ".23" portion.
+
+ // Utilizes implementation used internally by LLSD::ImplString::asInteger
+ value = (int)llsd::string_to_real(mCurrentContent);
}
}
break;
case ELEMENT_REAL:
{
- value = LLSD(mCurrentContent).asReal();
+ // Utilizes implementation used internally by LLSD::ImplString::asReal
+ value = llsd::string_to_real(mCurrentContent);
+
// removed since this breaks when locale has decimal separator that isn't '.'
// investigated changing local to something compatible each time but deemed higher
// risk that just using LLSD.asReal() each time.
@@ -766,19 +777,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
break;
case ELEMENT_STRING:
- value = mCurrentContent;
+ value = std::move(mCurrentContent); // This is safe to move as we are in the end element handler and this is cleared below
break;
case ELEMENT_UUID:
- value = LLSD(mCurrentContent).asUUID();
+ value = LLUUID(mCurrentContent);
break;
case ELEMENT_DATE:
- value = LLSD(mCurrentContent).asDate();
+ value = LLDate(mCurrentContent);
break;
case ELEMENT_URI:
- value = LLSD(mCurrentContent).asURI();
+ value = LLURI(mCurrentContent);
break;
case ELEMENT_BINARY:
@@ -787,15 +798,14 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
// created by python and other non-linden systems - DEV-39358
// Fortunately we have very little binary passing now,
// so performance impact shold be negligible. + poppy 2009-09-04
- boost::regex r;
- r.assign("\\s");
+ static const boost::regex r("\\s");
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
S32 len = apr_base64_decode_len(stripped.c_str());
std::vector<U8> data;
data.resize(len);
len = apr_base64_decode_binary(&data[0], stripped.c_str());
data.resize(len);
- value = data;
+ value = std::move(data);
break;
}
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 3fba8602ee..e6989211ae 100644
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -25,10 +25,10 @@
#ifndef LLSINGLETON_H
#define LLSINGLETON_H
-#include <boost/unordered_set.hpp>
#include <initializer_list>
#include <list>
#include <typeinfo>
+#include <unordered_set>
#include <vector>
#include "mutex.h"
#include "lockstatic.h"
@@ -61,7 +61,7 @@ private:
static vec_t dep_sort();
// we directly depend on these other LLSingletons
- typedef boost::unordered_set<LLSingletonBase*> set_t;
+ typedef std::unordered_set<LLSingletonBase*> set_t;
set_t mDepends;
protected:
diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h
index 66ba3487c4..edff955ee7 100644
--- a/indra/llcommon/llstaticstringtable.h
+++ b/indra/llcommon/llstaticstringtable.h
@@ -29,9 +29,10 @@
#define LL_STATIC_STRING_TABLE_H
#include "lldefs.h"
-#include <boost/unordered_map.hpp>
#include "llstl.h"
+#include <unordered_map>
+
class LLStaticHashedString
{
public:
@@ -74,7 +75,7 @@ struct LLStaticStringHasher
template< typename MappedObject >
class LL_COMMON_API LLStaticStringTable
- : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
+ : public std::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher >
{
};
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index 7d41c42ba7..7a1c7caf82 100644
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -34,6 +34,7 @@
#include <vector>
#include <list>
#include <set>
+#include <typeindex>
#include <typeinfo>
#ifdef LL_LINUX
@@ -229,12 +230,10 @@ void delete_and_clear_array(T*& ptr)
template <typename T>
inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename T::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
- return NULL;
+ return nullptr;
}
else
{
@@ -243,8 +242,8 @@ inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_ty
};
// helper function which returns true if key is in inmap.
-template <typename K, typename T>
-inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
+template <typename T>
+inline bool is_in_map(const T& inmap, typename T::key_type const& key)
{
if(inmap.find(key) == inmap.end())
{
@@ -260,12 +259,10 @@ inline bool is_in_map(const std::map<K,T>& inmap, const K& key)
// To replace LLSkipMap getIfThere, use:
// get_if_there(map, key, 0)
// WARNING: Make sure default_value (generally 0) is not a valid map entry!
-template <typename K, typename T>
-inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value)
+template <typename T>
+inline typename T::mapped_type get_if_there(const T& inmap, typename T::key_type const& key, typename T::mapped_type default_value)
{
- // Typedef here avoids warnings because of new c++ naming rules.
- typedef typename std::map<K,T>::const_iterator map_iter;
- map_iter iter = inmap.find(key);
+ auto iter = inmap.find(key);
if(iter == inmap.end())
{
return default_value;
@@ -709,5 +706,24 @@ struct ll_template_cast_impl<DEST, SOURCE> \
} \
}
+// Transparent string hashing helper for use with std::unordered_*
+// std::unordered_map<std::string, val, ll::string_hash, std::equal_to<>>
+namespace ll
+{
+ struct string_hash
+ {
+ using is_transparent = void;
+ [[nodiscard]] size_t operator()(char const* rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(std::string_view rhs) const { return std::hash<std::string_view>{}(rhs); }
+ [[nodiscard]] size_t operator()(const std::string& rhs) const { return std::hash<std::string>{}(rhs); }
+ };
+} // namespace ll
+
+// Specialize ostream for std::type_index to allow log output
+inline std::ostream& operator<<(std::ostream& s, std::type_index type)
+{
+ s << type.name();
+ return s;
+}
#endif // LL_LLSTL_H
diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h
index ca1cf03c4d..f91aadccc0 100644
--- a/indra/llcommon/lluuid.h
+++ b/indra/llcommon/lluuid.h
@@ -26,6 +26,7 @@
#ifndef LL_LLUUID_H
#define LL_LLUUID_H
+#include <functional>
#include <iostream>
#include <set>
#include <vector>
@@ -176,15 +177,27 @@ namespace std
{
inline size_t operator()(const LLUUID& id) const noexcept
{
- return (size_t)id.getDigest64();
+ size_t h = 0;
+ // Golden ratio hash with avalanche mixing
+ // Process 8 bytes at a time by manually constructing 64-bit values
+ // Shift by 31: mixes upper half into lower half for better bit distribution
+ // Shift by 47: ensures highest bits influence final hash output
+ for (int i = 0; i < UUID_BYTES; i += 8) {
+ size_t chunk = (size_t)id.mData[i] | ((size_t)id.mData[i+1] << 8) |
+ ((size_t)id.mData[i+2] << 16) | ((size_t)id.mData[i+3] << 24) |
+ ((size_t)id.mData[i+4] << 32) | ((size_t)id.mData[i+5] << 40) |
+ ((size_t)id.mData[i+6] << 48) | ((size_t)id.mData[i+7] << 56);
+ h ^= (chunk * 0x9e3779b97f4a7c15ULL) ^ (h >> 31) ^ (h >> 47);
+ }
+ return h;
}
};
}
-// For use with boost containers.
+// For use with boost::container_hash
inline size_t hash_value(const LLUUID& id) noexcept
{
- return (size_t)id.getDigest64();
+ return std::hash<LLUUID>{}(id);
}
#endif // LL_LLUUID_H
diff --git a/indra/llcommon/llwatchdog.cpp b/indra/llcommon/llwatchdog.cpp
index fa240a9ed7..1bc1283d0b 100644
--- a/indra/llcommon/llwatchdog.cpp
+++ b/indra/llcommon/llwatchdog.cpp
@@ -28,6 +28,7 @@
#include "linden_common.h"
#include "llwatchdog.h"
+#include "llmutex.h"
#include "llthread.h"
constexpr U32 WATCHDOG_SLEEP_TIME_USEC = 1000000U;
diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp
index 0407d6c3e9..67c23358ed 100644
--- a/indra/llcommon/workqueue.cpp
+++ b/indra/llcommon/workqueue.cpp
@@ -281,12 +281,30 @@ bool LL::WorkQueue::done()
bool LL::WorkQueue::post(const Work& callable)
{
- return mQueue.pushIfOpen(callable);
+ try
+ {
+ return mQueue.pushIfOpen(callable);
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLCoros") << "Bad memory allocation in WorkQueue::post" << LL_ENDL;
+ return false;
+ }
}
bool LL::WorkQueue::tryPost(const Work& callable)
{
- return mQueue.tryPush(callable);
+ try
+ {
+ return mQueue.tryPush(callable);
+ }
+ catch (std::bad_alloc&)
+ {
+ LLError::LLUserWarningMsg::showOutOfMemory();
+ LL_ERRS("LLCoros") << "Bad memory allocation in WorkQueue::tryPost" << LL_ENDL;
+ return false;
+ }
}
LL::WorkQueue::Work LL::WorkQueue::pop_()