summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-09-02 16:41:09 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-09-02 16:41:09 -0400
commit1101ed699a0c3c23c0bb11267d390febfdc02409 (patch)
tree52b369b2f8a14413ca69eea04768cbbf7aa79da8 /indra/newview
parent8c18cfd22583e981f93734ec0aa6ee0ead3f26c5 (diff)
Introduce result_view.lua, and use it in LLInventory.lua.
result_view(key_length, fetch) returns a virtual view of a potentially-large C++ result set. Given the result-set key, its total length and a function fetch(key, start) => (slice, adjusted start), the read-only table returned by result_view() manages indexed access and table iteration over the entire result set, fetching a slice at a time as required. Change LLInventory to use result_view() instead of only ever fetching the first slice of a result set. TODO: This depends on the viewer's "LLInventory" listener returning the total result set length as well as the result set key. It does not yet return the length.
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/scripts/lua/require/LLInventory.lua38
-rw-r--r--indra/newview/scripts/lua/require/result_view.lua62
2 files changed, 82 insertions, 18 deletions
diff --git a/indra/newview/scripts/lua/require/LLInventory.lua b/indra/newview/scripts/lua/require/LLInventory.lua
index 0ff6b9fb37..ce501e75f3 100644
--- a/indra/newview/scripts/lua/require/LLInventory.lua
+++ b/indra/newview/scripts/lua/require/LLInventory.lua
@@ -1,12 +1,14 @@
local leap = require 'leap'
local mapargs = require 'mapargs'
+local result_view = require 'result_view'
local function result(keys)
return LL.setdtor(
'LLInventory result',
setmetatable(
-- the basic table wrapped by setmetatable just captures the int
- -- result-set keys from 'keys', but with underscore prefixes
+ -- result-set {key, length} pairs from 'keys', but with underscore
+ -- prefixes
{
_categories=keys.categories,
_items=keys.items,
@@ -15,7 +17,7 @@ local function result(keys)
close = function(self)
leap.send('LLInventory',
{op='closeResult',
- result={self._categories, self._items}})
+ result={self._categories[1], self._items[1]}})
end
},
-- The caller of one of our methods that returns a result set
@@ -24,25 +26,25 @@ local function result(keys)
-- either 'categories' or 'items', the __index() metamethod
-- populates that field.
{
- __index = function(t, key)
+ __index = function(t, field)
-- we really don't care about references to any other field
- if not table.find({'categories', 'items'}, key) then
+ if not table.find({'categories', 'items'}, field) then
return nil
end
- -- We cleverly saved the int result set key in a field
- -- with the same name but an underscore prefix.
- local resultkey = t['_' .. key]
- -- TODO: This only ever fetches the FIRST slice. What we
- -- really want is to return a table with metamethods that
- -- manage indexed access and table iteration.
- -- Remember our C++ entry point uses 0-relative indexing.
- local slice = leap.request(
- 'LLInventory',
- {op='getSlice', result=resultkey, index=0}).slice
- print(`getSlice({resultkey}, 0) => {slice} ({#slice} entries)`)
- -- cache this slice for future reference
- t[key] = slice
- return slice
+ local view = result_view(
+ -- We cleverly saved the result set {key, length} pair in
+ -- a field with the same name but an underscore prefix.
+ t['_' .. field],
+ function(key, start)
+ local fetched = leap.request(
+ 'LLInventory',
+ {op='getSlice', result=key, index=start})
+ return fetched.slice, fetched.start
+ end
+ )
+ -- cache that view for future reference
+ t[field] = view
+ return view
end
}
),
diff --git a/indra/newview/scripts/lua/require/result_view.lua b/indra/newview/scripts/lua/require/result_view.lua
new file mode 100644
index 0000000000..4a58636f2f
--- /dev/null
+++ b/indra/newview/scripts/lua/require/result_view.lua
@@ -0,0 +1,62 @@
+-- result_view(key_length, fetch) returns a table which stores only a slice
+-- of a result set plus some control values, yet presents read-only virtual
+-- access to the entire result set.
+-- key_length: {result set key, total result set length}
+-- fetch: function(key, start) that returns (slice, adjusted start)
+local function result_view(key_length, fetch)
+ return setmetatable(
+ {
+ key=key_length[1],
+ length=key_length[2],
+ -- C++ result sets use 0-based indexing, so internally we do too
+ start=0,
+ -- start with a dummy array with length 0
+ slice={}
+ },
+ {
+ __len = function(this)
+ return this.length
+ end,
+ __index = function(this, i)
+ -- right away, convert to 0-relative indexing
+ i -= 1
+ -- can we find this index within the current slice?
+ local reli = i - this.start
+ if 0 <= reli and reli < #this.slice then
+ return this.slice[reli]
+ end
+ -- is this index outside the overall result set?
+ if not (0 <= i and i < this.length) then
+ return nil
+ end
+ -- fetch a new slice starting at i, using provided fetch()
+ local start
+ this.slice, start = fetch(key, i)
+ -- It's possible that caller-provided fetch() function forgot
+ -- to return the adjusted start index of the new slice. In
+ -- Lua, 0 tests as true, so if fetch() returned (slice, 0),
+ -- we'll duly reset this.start to 0.
+ if start then
+ this.start = start
+ end
+ -- hopefully this slice contains the desired i
+ return this.slice[i - this.start]
+ end,
+ -- We purposely avoid putting any array entries (int keys) into
+ -- our table so that access to any int key will always call our
+ -- __index() metamethod. Moreover, we want any table iteration to
+ -- call __index(table, i) however many times; we do NOT want it to
+ -- retrieve key, length, start, slice.
+ -- So turn 'for k, v in result' into 'for k, v in ipairs(result)'.
+ __iter = ipairs,
+ -- This result set provides read-only access.
+ -- We do not support pushing updates to individual items back to
+ -- C++; for the intended use cases, that makes no sense.
+ __newindex = function(this, i, value)
+ error("result_view is a read-only data structure", 2)
+ end
+ }
+ )
+end
+
+return result_view