summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/CMakeLists.txt2
-rw-r--r--indra/llcommon/resultset.cpp93
-rw-r--r--indra/llcommon/resultset.h61
-rw-r--r--indra/newview/llinventorylistener.cpp111
4 files changed, 175 insertions, 92 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 8577d94be1..8c346ea6ce 100644
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -112,6 +112,7 @@ set(llcommon_SOURCE_FILES
lockstatic.cpp
lua_function.cpp
lualistener.cpp
+ resultset.cpp
threadpool.cpp
throttle.cpp
u64.cpp
@@ -261,6 +262,7 @@ set(llcommon_HEADER_FILES
lockstatic.h
lua_function.h
lualistener.h
+ resultset.h
stdtypes.h
stringize.h
tempset.h
diff --git a/indra/llcommon/resultset.cpp b/indra/llcommon/resultset.cpp
new file mode 100644
index 0000000000..ee8cc68c6c
--- /dev/null
+++ b/indra/llcommon/resultset.cpp
@@ -0,0 +1,93 @@
+/**
+ * @file resultset.cpp
+ * @author Nat Goodspeed
+ * @date 2024-09-03
+ * @brief Implementation for resultset.
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Copyright (c) 2024, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+// Precompiled header
+#include "linden_common.h"
+// associated header
+#include "resultset.h"
+// STL headers
+// std headers
+// external library headers
+// other Linden headers
+#include "llerror.h"
+#include "llsdutil.h"
+
+namespace LL
+{
+
+LLSD ResultSet::getKeyLength() const
+{
+ return llsd::array(getKey(), getLength());
+}
+
+std::pair<LLSD, int> ResultSet::getSliceStart(int index, int count) const
+{
+ // only call getLength() once
+ auto length = getLength();
+ // Adjust bounds [start, end) to overlap the actual result set from
+ // [0, getLength()). Permit negative index; e.g. with a result set
+ // containing 5 entries, getSlice(-2, 5) will adjust start to 0 and
+ // end to 3.
+ int start = llclamp(index, 0, length);
+ int end = llclamp(index + count, 0, length);
+ LLSD result{ LLSD::emptyArray() };
+ // beware of count <= 0, or an [index, count) range that doesn't even
+ // overlap [0, length) at all
+ if (end > start)
+ {
+ // right away expand the result array to the size we'll need
+ result[end - 1] = LLSD();
+ for (int i = start; i < end; ++i)
+ {
+ result[i] = getSingle(i);
+ }
+ }
+ return { result, start };
+}
+
+LLSD ResultSet::getSlice(int index, int count) const
+{
+ return getSliceStart(index, count).first;
+}
+
+/*==========================================================================*|
+LLSD ResultSet::getSingle(int index) const
+{
+ if (0 <= index && index < getLength())
+ {
+ return getSingle_(index);
+ }
+ else
+ {
+ return {};
+ }
+}
+|*==========================================================================*/
+
+ResultSet::ResultSet(const std::string& name):
+ mName(name)
+{
+ LL_DEBUGS("Lua") << *this << LL_ENDL;
+}
+
+ResultSet::~ResultSet()
+{
+ // We want to be able to observe that the consuming script eventually
+ // destroys each of these ResultSets.
+ LL_DEBUGS("Lua") << "~" << *this << LL_ENDL;
+}
+
+} // namespace LL
+
+std::ostream& operator<<(std::ostream& out, const LL::ResultSet& self)
+{
+ return out << "ResultSet(" << self.mName << ", " << self.getKey() << ")";
+}
diff --git a/indra/llcommon/resultset.h b/indra/llcommon/resultset.h
new file mode 100644
index 0000000000..9b9ecbb21e
--- /dev/null
+++ b/indra/llcommon/resultset.h
@@ -0,0 +1,61 @@
+/**
+ * @file resultset.h
+ * @author Nat Goodspeed
+ * @date 2024-09-03
+ * @brief ResultSet is an abstract base class to allow scripted access to
+ * potentially large collections representable as LLSD arrays.
+ *
+ * $LicenseInfo:firstyear=2024&license=viewerlgpl$
+ * Copyright (c) 2024, Linden Research, Inc.
+ * $/LicenseInfo$
+ */
+
+#if ! defined(LL_RESULTSET_H)
+#define LL_RESULTSET_H
+
+#include "llinttracker.h"
+#include "llsd.h"
+#include <iosfwd> // std::ostream
+#include <utility> // std::pair
+
+namespace LL
+{
+
+// This abstract base class defines an interface by which a large collection
+// of items representable as an LLSD array can be retrieved in slices. It isa
+// LLIntTracker so we can pass its unique int key to a consuming script via
+// LLSD.
+struct ResultSet: public LLIntTracker<ResultSet>
+{
+ // Get the length of the result set. Indexes are 0-relative.
+ virtual int getLength() const = 0;
+ // Get conventional LLSD { key, length } pair.
+ LLSD getKeyLength() const;
+ // Retrieve LLSD corresponding to a single entry from the result set,
+ // once we're sure the index is valid.
+ virtual LLSD getSingle(int index) const = 0;
+ // Retrieve LLSD corresponding to a "slice" of the result set: a
+ // contiguous sub-array starting at index. The returned LLSD array might
+ // be shorter than count entries if count > MAX_ITEM_LIMIT, or if the
+ // specified slice contains the end of the result set.
+ LLSD getSlice(int index, int count) const;
+ // Like getSlice(), but also return adjusted start position.
+ std::pair<LLSD, int> getSliceStart(int index, int count) const;
+/*==========================================================================*|
+ // Retrieve LLSD corresponding to a single entry from the result set,
+ // with index validation.
+ LLSD getSingle(int index) const;
+|*==========================================================================*/
+
+ /*---------------- the rest is solely for debug logging ----------------*/
+ std::string mName;
+
+ ResultSet(const std::string& name);
+ virtual ~ResultSet();
+};
+
+} // namespace LL
+
+std::ostream& operator<<(std::ostream& out, const LL::ResultSet& self);
+
+#endif /* ! defined(LL_RESULTSET_H) */
diff --git a/indra/newview/llinventorylistener.cpp b/indra/newview/llinventorylistener.cpp
index c330ef42a0..6a8182c539 100644
--- a/indra/newview/llinventorylistener.cpp
+++ b/indra/newview/llinventorylistener.cpp
@@ -28,13 +28,14 @@
#include "llinventorylistener.h"
#include "llappearancemgr.h"
-#include "llinttracker.h"
#include "llinventoryfunctions.h"
#include "lltransutil.h"
#include "llwearableitemslist.h"
+#include "resultset.h"
#include "stringize.h"
+#include <algorithm> // std::min()
-constexpr U32 MAX_ITEM_LIMIT = 100;
+constexpr S32 MAX_ITEM_LIMIT = 100;
LLInventoryListener::LLInventoryListener()
: LLEventAPI("LLInventory",
@@ -104,87 +105,11 @@ LLInventoryListener::LLInventoryListener()
llsd::map("result", LLSD()));
}
-// This abstract base class defines the interface for CatResultSet and
-// ItemResultSet. It isa LLIntTracker so we can pass its unique int key to a
-// consuming script via LLSD.
-struct InvResultSet: public LLIntTracker<InvResultSet>
-{
- // Get the length of the result set. Indexes are 0-relative.
- virtual int getLength() const = 0;
-/*==========================================================================*|
- // Retrieve LLSD corresponding to a single entry from the result set,
- // with index validation.
- LLSD getSingle(int index) const
- {
- if (0 <= index && index < getLength())
- {
- return getSingle_(index);
- }
- else
- {
- return {};
- }
- }
-|*==========================================================================*/
- // Retrieve LLSD corresponding to a single entry from the result set,
- // once we're sure the index is valid.
- virtual LLSD getSingle(int index) const = 0;
- // Retrieve LLSD corresponding to a "slice" of the result set: a
- // contiguous sub-array starting at index. The returned LLSD array might
- // be shorter than count entries if count > MAX_ITEM_LIMIT, or if the
- // specified slice contains the end of the result set.
- LLSD getSlice(int index, int count) const
- {
- // only call getLength() once
- auto length = getLength();
- // Adjust bounds [start, end) to overlap the actual result set from
- // [0, getLength()). Permit negative index; e.g. with a result set
- // containing 5 entries, getSlice(-2, 5) will adjust start to 0 and
- // end to 3.
- int start = llclamp(index, 0, length);
- // Constrain count to MAX_ITEM_LIMIT even before clamping end.
- int end = llclamp(index + llclamp(count, 0, MAX_ITEM_LIMIT), 0, length);
- LLSD result{ LLSD::emptyArray() };
- // beware of count == 0, or an [index, count) range that doesn't even
- // overlap [0, length) at all
- if (end > start)
- {
- // right away expand the result array to the size we'll need
- result[end - 1] = LLSD();
- for (int i = start; i < end; ++i)
- {
- result[i] = getSingle(i);
- }
- }
- return result;
- }
-
- /*---------------- the rest is solely for debug logging ----------------*/
- std::string mName;
-
- friend std::ostream& operator<<(std::ostream& out, const InvResultSet& self)
- {
- return out << "InvResultSet(" << self.mName << ", " << self.getKey() << ")";
- }
-
- InvResultSet(const std::string& name):
- mName(name)
- {
- LL_DEBUGS("Lua") << *this << LL_ENDL;
- }
- virtual ~InvResultSet()
- {
- // We want to be able to observe that the consuming script uses
- // LL.setdtor() to eventually destroy each of these InvResultSets.
- LL_DEBUGS("Lua") << "~" << *this << LL_ENDL;
- }
-};
-
// This struct captures (possibly large) category results from
// getDirectDescendants() and collectDescendantsIf().
-struct CatResultSet: public InvResultSet
+struct CatResultSet: public LL::ResultSet
{
- CatResultSet(): InvResultSet("categories") {}
+ CatResultSet(): LL::ResultSet("categories") {}
LLInventoryModel::cat_array_t mCategories;
int getLength() const override { return narrow(mCategories.size()); }
@@ -199,9 +124,9 @@ struct CatResultSet: public InvResultSet
// This struct captures (possibly large) item results from
// getDirectDescendants() and collectDescendantsIf().
-struct ItemResultSet: public InvResultSet
+struct ItemResultSet: public LL::ResultSet
{
- ItemResultSet(): InvResultSet("items") {}
+ ItemResultSet(): LL::ResultSet("items") {}
LLInventoryModel::item_array_t mItems;
int getLength() const override { return narrow(mItems.size()); }
@@ -244,8 +169,9 @@ void LLInventoryListener::getItemsInfo(LLSD const &data)
}
}
}
- response["categories"] = catresult->getKey();
- response["items"] = itemresult->getKey();
+ // Each of categories and items is a { result set key, total length } pair.
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
}
void LLInventoryListener::getFolderTypeNames(LLSD const &data)
@@ -277,8 +203,8 @@ void LLInventoryListener::getDirectDescendants(LLSD const &data)
catresult->mCategories = *cats;
itemresult->mItems = *items;
- response["categories"] = catresult->getKey();
- response["items"] = itemresult->getKey();
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
}
struct LLFilteredCollector : public LLInventoryCollectFunctor
@@ -337,25 +263,26 @@ void LLInventoryListener::collectDescendantsIf(LLSD const &data)
LLInventoryModel::EXCLUDE_TRASH,
collector);
- response["categories"] = catresult->getKey();
- response["items"] = itemresult->getKey();
+ response["categories"] = catresult->getKeyLength();
+ response["items"] = itemresult->getKeyLength();
}
/*==========================================================================*|
void LLInventoryListener::getSingle(LLSD const& data)
{
- auto result = InvResultSet::getInstance(data["result"]);
+ auto result = LL::ResultSet::getInstance(data["result"]);
sendReply(llsd::map("single", result->getSingle(data["index"])), data);
}
|*==========================================================================*/
void LLInventoryListener::getSlice(LLSD const& data)
{
- auto result = InvResultSet::getInstance(data["result"]);
+ auto result = LL::ResultSet::getInstance(data["result"]);
int count = data.has("count")? data["count"].asInteger() : MAX_ITEM_LIMIT;
LL_DEBUGS("Lua") << *result << ".getSlice(" << data["index"].asInteger()
<< ", " << count << ')' << LL_ENDL;
- sendReply(llsd::map("slice", result->getSlice(data["index"], count)), data);
+ auto pair{ result->getSliceStart(data["index"], std::min(count, MAX_ITEM_LIMIT)) };
+ sendReply(llsd::map("slice", pair.first, "start", pair.second), data);
}
void LLInventoryListener::closeResult(LLSD const& data)
@@ -367,7 +294,7 @@ void LLInventoryListener::closeResult(LLSD const& data)
}
for (const auto& result : llsd::inArray(results))
{
- auto ptr = InvResultSet::getInstance(result);
+ auto ptr = LL::ResultSet::getInstance(result);
if (ptr)
{
delete ptr.get();