You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
3.0 KiB
Lua
151 lines
3.0 KiB
Lua
--[=[
|
|
@c Cache x Iterable
|
|
@mt mem
|
|
@d Iterable class that holds references to Discordia Class objects in no particular order.
|
|
]=]
|
|
|
|
local json = require('json')
|
|
local Iterable = require('iterables/Iterable')
|
|
|
|
local null = json.null
|
|
|
|
local Cache = require('class')('Cache', Iterable)
|
|
|
|
local meta = {__mode = 'v'}
|
|
|
|
function Cache:__init(array, constructor, parent)
|
|
local objects = {}
|
|
for _, data in ipairs(array) do
|
|
local obj = constructor(data, parent)
|
|
objects[obj:__hash()] = obj
|
|
end
|
|
self._count = #array
|
|
self._objects = objects
|
|
self._constructor = constructor
|
|
self._parent = parent
|
|
self._deleted = setmetatable({}, meta)
|
|
end
|
|
|
|
function Cache:__pairs()
|
|
return next, self._objects
|
|
end
|
|
|
|
function Cache:__len()
|
|
return self._count
|
|
end
|
|
|
|
local function insert(self, k, obj)
|
|
self._objects[k] = obj
|
|
self._count = self._count + 1
|
|
return obj
|
|
end
|
|
|
|
local function remove(self, k, obj)
|
|
self._objects[k] = nil
|
|
self._deleted[k] = obj
|
|
self._count = self._count - 1
|
|
return obj
|
|
end
|
|
|
|
local function hash(data)
|
|
-- local meta = getmetatable(data) -- debug
|
|
-- assert(meta and meta.__jsontype == 'object') -- debug
|
|
if data.id then -- snowflakes
|
|
return data.id
|
|
elseif data.user then -- members
|
|
return data.user.id
|
|
elseif data.emoji then -- reactions
|
|
return data.emoji.id ~= null and data.emoji.id or data.emoji.name
|
|
elseif data.code then -- invites
|
|
return data.code
|
|
else
|
|
return nil, 'json data could not be hashed'
|
|
end
|
|
end
|
|
|
|
function Cache:_insert(data)
|
|
local k = assert(hash(data))
|
|
local old = self._objects[k]
|
|
if old then
|
|
old:_load(data)
|
|
return old
|
|
elseif self._deleted[k] then
|
|
return insert(self, k, self._deleted[k])
|
|
else
|
|
local obj = self._constructor(data, self._parent)
|
|
return insert(self, k, obj)
|
|
end
|
|
end
|
|
|
|
function Cache:_remove(data)
|
|
local k = assert(hash(data))
|
|
local old = self._objects[k]
|
|
if old then
|
|
old:_load(data)
|
|
return remove(self, k, old)
|
|
elseif self._deleted[k] then
|
|
return self._deleted[k]
|
|
else
|
|
return self._constructor(data, self._parent)
|
|
end
|
|
end
|
|
|
|
function Cache:_delete(k)
|
|
local old = self._objects[k]
|
|
if old then
|
|
return remove(self, k, old)
|
|
elseif self._deleted[k] then
|
|
return self._deleted[k]
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
function Cache:_load(array, update)
|
|
if update then
|
|
local updated = {}
|
|
for _, data in ipairs(array) do
|
|
local obj = self:_insert(data)
|
|
updated[obj:__hash()] = true
|
|
end
|
|
for obj in self:iter() do
|
|
local k = obj:__hash()
|
|
if not updated[k] then
|
|
self:_delete(k)
|
|
end
|
|
end
|
|
else
|
|
for _, data in ipairs(array) do
|
|
self:_insert(data)
|
|
end
|
|
end
|
|
end
|
|
|
|
--[=[
|
|
@m get
|
|
@p k *
|
|
@r *
|
|
@d Returns an individual object by key, where the key should match the result of
|
|
calling `__hash` on the contained objects. Unlike Iterable:get, this
|
|
method operates with O(1) complexity.
|
|
]=]
|
|
function Cache:get(k)
|
|
return self._objects[k]
|
|
end
|
|
|
|
--[=[
|
|
@m iter
|
|
@r function
|
|
@d Returns an iterator that returns all contained objects. The order of the objects
|
|
is not guaranteed.
|
|
]=]
|
|
function Cache:iter()
|
|
local objects, k, obj = self._objects
|
|
return function()
|
|
k, obj = next(objects, k)
|
|
return obj
|
|
end
|
|
end
|
|
|
|
return Cache
|