You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
924 lines
34 KiB
924 lines
34 KiB
|
5 years ago
|
--===========================================================================--
|
||
|
|
-- --
|
||
|
|
-- System.Collections.List --
|
||
|
|
-- --
|
||
|
|
--===========================================================================--
|
||
|
|
|
||
|
|
--===========================================================================--
|
||
|
|
-- Author : kurapica125@outlook.com --
|
||
|
|
-- URL : http://github.com/kurapica/PLoop --
|
||
|
|
-- Create Date : 2016/02/28 --
|
||
|
|
-- Update Date : 2020/07/06 --
|
||
|
|
-- Version : 1.2.4 --
|
||
|
|
--===========================================================================--
|
||
|
|
|
||
|
|
PLoop(function(_ENV)
|
||
|
|
namespace "System.Collections"
|
||
|
|
|
||
|
|
import "System.Serialization"
|
||
|
|
|
||
|
|
-- Helpers
|
||
|
|
export { yield = coroutine.yield }
|
||
|
|
|
||
|
|
__Iterator__() iterforstep = function (start, stop, step) local yield = yield for i = start, stop, step do yield(i, i) end end
|
||
|
|
__Iterator__() iterforlist = function (iter, tar, idx) local yield = yield for k, v in iter, tar, idx do yield(k, v == nil and k or v) end end
|
||
|
|
|
||
|
|
--- Represents the list collections that only elements has meanings
|
||
|
|
interface "IList" { Iterable }
|
||
|
|
|
||
|
|
--- Represents countable list collections
|
||
|
|
__Sealed__()
|
||
|
|
interface "ICountable" { IList,
|
||
|
|
--- Get the count of items in the object
|
||
|
|
__Abstract__(),
|
||
|
|
Count = { set = false, get = function (self) return #self end },
|
||
|
|
}
|
||
|
|
|
||
|
|
--- Represents the indexed list collections that can use obj[idx] to access the its elements
|
||
|
|
__Sealed__()
|
||
|
|
interface "IIndexedList" { ICountable }
|
||
|
|
|
||
|
|
--- The default indexed list
|
||
|
|
__Sealed__() __Serializable__() __Arguments__{ AnyType }( Any )
|
||
|
|
__NoNilValue__(false):AsInheritable() __NoRawSet__(false):AsInheritable()
|
||
|
|
class "List" (function (_ENV, lsttype)
|
||
|
|
extend "IIndexedList" "ISerializable"
|
||
|
|
|
||
|
|
export { type = type, ipairs = ipairs }
|
||
|
|
|
||
|
|
lsttype = lsttype ~= Any and lsttype or nil
|
||
|
|
|
||
|
|
if lsttype then
|
||
|
|
export {
|
||
|
|
valid = getmetatable(lsttype).ValidateValue,
|
||
|
|
GetErrorMessage = Struct.GetErrorMessage,
|
||
|
|
parseindex = Toolset.parseindex,
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- serialization --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
function Serialize(self, info)
|
||
|
|
for i, v in self:GetIterator() do
|
||
|
|
info:SetValue(i, v, lsttype)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ SerializationInfo }
|
||
|
|
function __new(_, info)
|
||
|
|
local i = 1
|
||
|
|
local v = info:GetValue(i, lsttype)
|
||
|
|
local self = {}
|
||
|
|
while v ~= nil do
|
||
|
|
self[i] = v
|
||
|
|
i = i + 1
|
||
|
|
v = info:GetValue(i, lsttype)
|
||
|
|
end
|
||
|
|
return self, true
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
GetIterator = ipairs
|
||
|
|
|
||
|
|
--- Insert an item to the list
|
||
|
|
if lsttype then
|
||
|
|
__Arguments__{ Integer, lsttype }
|
||
|
|
Insert = table.insert
|
||
|
|
|
||
|
|
__Arguments__{ lsttype }
|
||
|
|
Insert = table.insert
|
||
|
|
else
|
||
|
|
Insert = table.insert
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Whether an item existed in the list
|
||
|
|
function Contains(self, item) for i, chk in self:GetIterator() do if chk == item then return true end end return false end
|
||
|
|
|
||
|
|
--- Get the index of the item if it existed in the list
|
||
|
|
function IndexOf(self, item) for i, chk in self:GetIterator() do if chk == item then return i end end end
|
||
|
|
|
||
|
|
--- Remove an item
|
||
|
|
function Remove(self, item) local i = self:IndexOf(item) if i then return self:RemoveByIndex(i) end end
|
||
|
|
|
||
|
|
--- Remove an item from the tail or the given index
|
||
|
|
RemoveByIndex = table.remove
|
||
|
|
|
||
|
|
--- Clear the list
|
||
|
|
function Clear(self)
|
||
|
|
for i = self.Count, 1, -1 do self[i] = nil end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Extend the list
|
||
|
|
if lsttype then
|
||
|
|
__Arguments__{ RawTable }
|
||
|
|
function Extend(self, lst)
|
||
|
|
local ins = self.Insert
|
||
|
|
for _, item in ipairs(lst) do
|
||
|
|
local ret, msg = valid(lsttype, item, true)
|
||
|
|
if not msg then ins(self, item) end
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function Extend(self, lst)
|
||
|
|
local ins = self.Insert
|
||
|
|
for _, item in lst:GetIterator() do
|
||
|
|
local ret, msg = valid(lsttype, item, true)
|
||
|
|
if not msg then ins(self, item) end
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function Extend(self, iter, obj, idx)
|
||
|
|
local ins = self.Insert
|
||
|
|
for key, item in iter, obj, idx do
|
||
|
|
if item == nil then item = key end
|
||
|
|
local ret, msg = valid(lsttype, item, true)
|
||
|
|
if not msg then ins(self, item) end
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
else
|
||
|
|
__Arguments__{ RawTable }
|
||
|
|
function Extend(self, lst)
|
||
|
|
local ins = self.Insert
|
||
|
|
for _, item in ipairs(lst) do ins(self, item) end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function Extend(self, lst)
|
||
|
|
local ins = self.Insert
|
||
|
|
for _, item in lst:GetIterator() do ins(self, item) end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function Extend(self, iter, obj, idx)
|
||
|
|
local ins = self.Insert
|
||
|
|
for key, item in iter, obj, idx do
|
||
|
|
if item == nil then item = key end
|
||
|
|
ins(self, item)
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- constructor --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
__Arguments__{ RawTable }
|
||
|
|
function __new(_, lst) return lst, true end
|
||
|
|
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function __new(_, lst)
|
||
|
|
local i = 1
|
||
|
|
local obj = {}
|
||
|
|
for idx, item in lst:GetIterator() do
|
||
|
|
obj[i] = item
|
||
|
|
i = i + 1
|
||
|
|
end
|
||
|
|
return obj, true
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function __new(_, iter, obj, idx)
|
||
|
|
local i = 1
|
||
|
|
local lst = {}
|
||
|
|
for key, item in iter, obj, idx do
|
||
|
|
if item ~= nil then
|
||
|
|
lst[i] = item
|
||
|
|
i = i + 1
|
||
|
|
else
|
||
|
|
lst[i] = key
|
||
|
|
i = i + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return lst, true
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ NaturalNumber, Callable }
|
||
|
|
function __new(_, count, initValue)
|
||
|
|
local obj = {}
|
||
|
|
for i = 1, count do
|
||
|
|
obj[i] = initValue(i)
|
||
|
|
end
|
||
|
|
return obj, true
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ NaturalNumber, System.Any/nil }
|
||
|
|
function __new(_, count, initValue)
|
||
|
|
local obj = {}
|
||
|
|
if initValue ~= nil then
|
||
|
|
for i = 1, count do
|
||
|
|
obj[i] = initValue
|
||
|
|
end
|
||
|
|
else
|
||
|
|
for i = 1, count do
|
||
|
|
obj[i] = i
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return obj, true
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__.Rest()
|
||
|
|
function __new(_, ...)
|
||
|
|
return { ... }, true
|
||
|
|
end
|
||
|
|
|
||
|
|
if lsttype then
|
||
|
|
function __ctor(self)
|
||
|
|
local msg
|
||
|
|
for k, v in self:GetIterator() do
|
||
|
|
v, msg = valid(lsttype, v)
|
||
|
|
if msg then throw(GetErrorMessage(msg, parseindex(k))) end
|
||
|
|
self[k]= v
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- meta-method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
function __index(self, idx)
|
||
|
|
if type(idx) ~= "number" or idx >= 0 then return end
|
||
|
|
local cnt = self.Count
|
||
|
|
|
||
|
|
idx = cnt + idx + 1
|
||
|
|
if idx >= 1 and idx <= cnt then
|
||
|
|
return self[idx]
|
||
|
|
else
|
||
|
|
return nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
--- The dynamic list
|
||
|
|
__Sealed__() __NoRawSet__(true)
|
||
|
|
class "XList" (function(_ENV)
|
||
|
|
extend "IList"
|
||
|
|
export { ipairs = ipairs, type = type, iterforstep = iterforstep, iterforlist = iterforlist }
|
||
|
|
|
||
|
|
XLIST_TYPE_STEP = 1
|
||
|
|
XLIST_TYPE_ITER = 2
|
||
|
|
XLIST_TYPE_LIST = 3
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
function GetIterator(self)
|
||
|
|
local type = self[1]
|
||
|
|
|
||
|
|
if type == XLIST_TYPE_STEP then
|
||
|
|
return iterforstep(self[2], self[3], self[4])
|
||
|
|
elseif type == XLIST_TYPE_ITER then
|
||
|
|
return iterforlist(self[2], self[3], self[4])
|
||
|
|
else
|
||
|
|
return self[2]:GetIterator()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- constructor --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
__Arguments__{
|
||
|
|
Variable("start", NaturalNumber),
|
||
|
|
Variable("stop", NaturalNumber),
|
||
|
|
Variable("step", Integer, true, 1)
|
||
|
|
}
|
||
|
|
function __new(_, ...) return { XLIST_TYPE_STEP, ... }, true end
|
||
|
|
|
||
|
|
__Arguments__{
|
||
|
|
Variable("stop", NaturalNumber),
|
||
|
|
}
|
||
|
|
function __new(_, stop) return { XLIST_TYPE_STEP, 1, stop, 1 }, true end
|
||
|
|
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function __new(_, lst) return { XLIST_TYPE_LIST, lst }, true end
|
||
|
|
|
||
|
|
__Arguments__{ RawTable }
|
||
|
|
function __new(_, lst) return { XLIST_TYPE_ITER, ipairs(lst) }, true end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function __new(_, iter, obj, idx) return { XLIST_TYPE_ITER, iter, obj, idx }, true end
|
||
|
|
end)
|
||
|
|
|
||
|
|
--- the list stream worker, used to provide stream filter, map and etc
|
||
|
|
-- operations on a list without creating any temp caches
|
||
|
|
__Final__() __Sealed__() __SuperObject__(false)
|
||
|
|
__NoRawSet__(false) __NoNilValue__(false)
|
||
|
|
class "ListStreamWorker" (function (_ENV)
|
||
|
|
extend "IList"
|
||
|
|
|
||
|
|
export {
|
||
|
|
type = type,
|
||
|
|
yield = coroutine.yield,
|
||
|
|
MATH_HUGE = math.huge,
|
||
|
|
tinsert = table.insert,
|
||
|
|
tremove = table.remove,
|
||
|
|
getobjectclass = Class.GetObjectClass,
|
||
|
|
issubtype = Class.IsSubType,
|
||
|
|
|
||
|
|
ListStreamWorker, IIndexedList, ICountable
|
||
|
|
}
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- helpers --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
local getIdleworkers
|
||
|
|
local rycIdleworkers
|
||
|
|
|
||
|
|
if Platform.MULTI_OS_THREAD then
|
||
|
|
getIdleworkers = Toolset.fakefunc
|
||
|
|
rycIdleworkers = Toolset.fakefunc
|
||
|
|
else
|
||
|
|
-- Keep idle workers for re-usage
|
||
|
|
local idleworkers = {}
|
||
|
|
getIdleworkers = function() return tremove(idleworkers) end
|
||
|
|
rycIdleworkers = function(worker) tinsert(idleworkers, worker) end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- constant --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
export {
|
||
|
|
FLD_TARGETLIST = 0,
|
||
|
|
FLD_TARGETITER = 1,
|
||
|
|
FLD_ITEROBJECT = 2,
|
||
|
|
FLD_ITERINDEX = 3,
|
||
|
|
|
||
|
|
FLD_MAPACTITON = 4,
|
||
|
|
FLD_FILTERACTN = 5,
|
||
|
|
FLD_RANGESTART = 6,
|
||
|
|
FLD_RANGESTOP = 7,
|
||
|
|
FLD_RANGESTEP = 8,
|
||
|
|
}
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
__Iterator__()
|
||
|
|
function GetIterator(self)
|
||
|
|
local targetList = self[FLD_TARGETLIST]
|
||
|
|
local targetIter = self[FLD_TARGETITER]
|
||
|
|
local targetObj = self[FLD_ITEROBJECT]
|
||
|
|
local targetIdx = self[FLD_ITERINDEX]
|
||
|
|
|
||
|
|
local map = self[FLD_MAPACTITON]
|
||
|
|
local filter = self[FLD_FILTERACTN]
|
||
|
|
local rangeStart = self[FLD_RANGESTART]
|
||
|
|
local rangeStop = self[FLD_RANGESTOP]
|
||
|
|
local rangeStep = self[FLD_RANGESTEP]
|
||
|
|
|
||
|
|
-- Clear self and put self into idleworkers
|
||
|
|
self[FLD_TARGETLIST] = nil
|
||
|
|
self[FLD_TARGETITER] = nil
|
||
|
|
self[FLD_ITEROBJECT] = nil
|
||
|
|
self[FLD_ITERINDEX] = nil
|
||
|
|
|
||
|
|
self[FLD_MAPACTITON] = nil
|
||
|
|
self[FLD_FILTERACTN] = nil
|
||
|
|
self[FLD_RANGESTART] = nil
|
||
|
|
self[FLD_RANGESTOP] = nil
|
||
|
|
self[FLD_RANGESTEP] = nil
|
||
|
|
|
||
|
|
rycIdleworkers(self)
|
||
|
|
|
||
|
|
-- So we should run an iterator over the targetList to fetch datas, like link list
|
||
|
|
if targetList then
|
||
|
|
targetIter, targetObj, targetIdx = targetList:GetIterator()
|
||
|
|
end
|
||
|
|
|
||
|
|
local _, stop
|
||
|
|
|
||
|
|
-- Process the iterator
|
||
|
|
if not rangeStart then
|
||
|
|
rangeStart = 1
|
||
|
|
rangeStop = MATH_HUGE
|
||
|
|
rangeStep = 1
|
||
|
|
else
|
||
|
|
local lstCount
|
||
|
|
local targetCls = getobjectclass(targetList)
|
||
|
|
|
||
|
|
-- If the targetCls is ICountable, we can deal with negative position
|
||
|
|
if targetCls and issubtype(targetCls, ICountable) then lstCount = targetList.Count end
|
||
|
|
|
||
|
|
if lstCount then
|
||
|
|
if rangeStart < 0 then rangeStart = lstCount + rangeStart + 1 end
|
||
|
|
if rangeStop < 0 then rangeStop = lstCount + rangeStop + 1 end
|
||
|
|
else
|
||
|
|
if rangeStop == -1 then rangeStop = MATH_HUGE end
|
||
|
|
if rangeStart < 0 or rangeStop < 0 then return end
|
||
|
|
end
|
||
|
|
|
||
|
|
if targetCls and issubtype(targetCls, IIndexedList) then
|
||
|
|
-- The targetList should be used like targetList[index]
|
||
|
|
if rangeStep == 0 or
|
||
|
|
(rangeStart > rangeStop and rangeStep > 0) or
|
||
|
|
(rangeStart < rangeStop and rangeStep < 0) then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
if map then
|
||
|
|
if filter then
|
||
|
|
for i = rangeStart, rangeStop, rangeStep do
|
||
|
|
local item = targetList[i]
|
||
|
|
if item == nil then return end
|
||
|
|
if filter(item) then
|
||
|
|
local mitem = map(item)
|
||
|
|
if mitem ~= nil then
|
||
|
|
_, _, stop = yield(i, mitem, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
for i = rangeStart, rangeStop, rangeStep do
|
||
|
|
local item = targetList[i]
|
||
|
|
if item == nil then return end
|
||
|
|
local mitem = map(item)
|
||
|
|
if mitem ~= nil then
|
||
|
|
_, _, stop = yield(i, mitem, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
if filter then
|
||
|
|
for i = rangeStart, rangeStop, rangeStep do
|
||
|
|
local item = targetList[i]
|
||
|
|
if item == nil then return end
|
||
|
|
if filter(item) then
|
||
|
|
_, _, stop = yield(i, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
for i = rangeStart, rangeStop, rangeStep do
|
||
|
|
local item = targetList[i]
|
||
|
|
if item == nil then return end
|
||
|
|
_, _, stop = yield(i, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return
|
||
|
|
else
|
||
|
|
if lstCount then
|
||
|
|
if rangeStart > rangeStop then rangeStart, rangeStop, rangeStep = rangeStop, rangeStart, - rangeStep end
|
||
|
|
if rangeStart < 1 then rangeStart = 1 end
|
||
|
|
if rangeStart > lstCount then rangeStep = -1 end -- no items would be scaned
|
||
|
|
else
|
||
|
|
if rangeStart > rangeStop then rangeStart, rangeStop, rangeStep = rangeStop, rangeStart, - rangeStep end
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if rangeStep < 1 then return end
|
||
|
|
|
||
|
|
local idx = 1
|
||
|
|
local stepCnt = rangeStep
|
||
|
|
local item
|
||
|
|
|
||
|
|
while idx < rangeStart do
|
||
|
|
targetIdx, item = targetIter(targetObj, targetIdx)
|
||
|
|
if targetIdx == nil then return end
|
||
|
|
idx = idx + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
if map then
|
||
|
|
if filter then
|
||
|
|
while idx <= rangeStop do
|
||
|
|
targetIdx, item = targetIter(targetObj, targetIdx)
|
||
|
|
if targetIdx == nil then return end
|
||
|
|
|
||
|
|
if stepCnt == rangeStep then
|
||
|
|
stepCnt = 0
|
||
|
|
if item ~= nil and filter(item) then
|
||
|
|
local mitem = map(item)
|
||
|
|
if mitem ~= nil then
|
||
|
|
_, _, stop = yield(targetIdx, mitem, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
stepCnt = stepCnt + 1
|
||
|
|
idx = idx + 1
|
||
|
|
end
|
||
|
|
else
|
||
|
|
while idx <= rangeStop do
|
||
|
|
targetIdx, item = targetIter(targetObj, targetIdx)
|
||
|
|
if targetIdx == nil then return end
|
||
|
|
|
||
|
|
if stepCnt == rangeStep then
|
||
|
|
stepCnt = 0
|
||
|
|
if item ~= nil then
|
||
|
|
local mitem = map(item)
|
||
|
|
if mitem ~= nil then
|
||
|
|
_, _, stop = yield(targetIdx, mitem, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
stepCnt = stepCnt + 1
|
||
|
|
idx = idx + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
if filter then
|
||
|
|
while idx <= rangeStop do
|
||
|
|
targetIdx, item = targetIter(targetObj, targetIdx)
|
||
|
|
if targetIdx == nil then return end
|
||
|
|
|
||
|
|
if stepCnt == rangeStep then
|
||
|
|
stepCnt = 0
|
||
|
|
if item ~= nil and filter(item) then
|
||
|
|
_, _, stop = yield(targetIdx, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
stepCnt = stepCnt + 1
|
||
|
|
idx = idx + 1
|
||
|
|
end
|
||
|
|
else
|
||
|
|
while idx <= rangeStop do
|
||
|
|
targetIdx, item = targetIter(targetObj, targetIdx)
|
||
|
|
if targetIdx == nil then return end
|
||
|
|
|
||
|
|
if stepCnt == rangeStep then
|
||
|
|
stepCnt = 0
|
||
|
|
if item ~= nil then
|
||
|
|
_, _, stop = yield(targetIdx, item)
|
||
|
|
if stop then return end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
stepCnt = stepCnt + 1
|
||
|
|
idx = idx + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- Queue method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
--- Map the items to other datas
|
||
|
|
__Arguments__{ Callable }
|
||
|
|
function Map(self, func)
|
||
|
|
if self[FLD_MAPACTITON] then return ListStreamWorker(self):Map(func) end
|
||
|
|
self[FLD_MAPACTITON] = func
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ String }
|
||
|
|
function Map(self, feature)
|
||
|
|
if self[FLD_MAPACTITON] then return ListStreamWorker(self):Map(feature) end
|
||
|
|
self[FLD_MAPACTITON] = function(item)
|
||
|
|
if type(item) == "table" then
|
||
|
|
return item[feature]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Table }
|
||
|
|
function Map(self, map)
|
||
|
|
if self[FLD_MAPACTITON] then return ListStreamWorker(self):Map(feature) end
|
||
|
|
self[FLD_MAPACTITON] = function(item) if map[item] ~= nil then return map[item] else return item end end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable }
|
||
|
|
function Filter(self, func)
|
||
|
|
if self[FLD_FILTERACTN] or self[FLD_MAPACTITON] then return ListStreamWorker(self):Filter(func) end
|
||
|
|
self[FLD_FILTERACTN] = func
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Table }
|
||
|
|
function Filter(self, filter)
|
||
|
|
if self[FLD_FILTERACTN] or self[FLD_MAPACTITON] then return ListStreamWorker(self):Filter(func) end
|
||
|
|
self[FLD_FILTERACTN] = function(item) return filter[item] end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Used to filter the items with a check function
|
||
|
|
__Arguments__{ String, System.Any/nil }
|
||
|
|
function Filter(self, feature, value)
|
||
|
|
if self[FLD_FILTERACTN] or self[FLD_MAPACTITON] then return ListStreamWorker(self):Filter(feature, value) end
|
||
|
|
self[FLD_FILTERACTN] = value ~= nil and function(item)
|
||
|
|
if type(item) == "table" then
|
||
|
|
return item[feature] == value
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end or function(item)
|
||
|
|
if type(item) == "table" then
|
||
|
|
return item[feature] and true or false
|
||
|
|
else
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Used to select items with ranged index
|
||
|
|
__Arguments__{ Integer/1, Integer/-1, Integer/1 }
|
||
|
|
function Range(self, start, stop, step)
|
||
|
|
if self[FLD_RANGESTART] or self[FLD_FILTERACTN] then return ListStreamWorker(self):Range(start, stop, step) end
|
||
|
|
self[FLD_RANGESTART], self[FLD_RANGESTOP], self[FLD_RANGESTEP] = start, stop, step
|
||
|
|
return self
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- Constructor --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function __ctor(self, list)
|
||
|
|
self[FLD_TARGETLIST] = list
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function __ctor(self, iter, obj, idx)
|
||
|
|
self[FLD_TARGETITER] = iter
|
||
|
|
self[FLD_ITEROBJECT] = obj
|
||
|
|
self[FLD_ITERINDEX] = idx
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- meta method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
__Arguments__{ IList }
|
||
|
|
function __exist(_, list)
|
||
|
|
local worker = getIdleworkers()
|
||
|
|
if worker then worker[FLD_TARGETLIST] = list end
|
||
|
|
return worker
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
||
|
|
function __exist(_, iter, obj, idx)
|
||
|
|
local worker = getIdleworkers()
|
||
|
|
if worker then
|
||
|
|
worker[FLD_TARGETITER] = iter
|
||
|
|
worker[FLD_ITEROBJECT] = obj
|
||
|
|
worker[FLD_ITERINDEX] = idx
|
||
|
|
end
|
||
|
|
return worker
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
__Sealed__()
|
||
|
|
interface "IList" (function (_ENV)
|
||
|
|
|
||
|
|
export {
|
||
|
|
type = type,
|
||
|
|
rawget = rawget,
|
||
|
|
getobjectclass = Class.GetObjectClass,
|
||
|
|
isObjectType = Class.IsObjectType,
|
||
|
|
tblconcat = table.concat,
|
||
|
|
tonumber = tonumber,
|
||
|
|
}
|
||
|
|
|
||
|
|
export { ListStreamWorker, IIndexedList, XList }
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- Queue method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
--- Map the items to other type datas
|
||
|
|
__Arguments__{ Callable }
|
||
|
|
function Map(self, func) return ListStreamWorker(self):Map(func) end
|
||
|
|
|
||
|
|
__Arguments__{ Table }
|
||
|
|
function Map(self, map) return ListStreamWorker(self):Map(map) end
|
||
|
|
|
||
|
|
__Arguments__{ String }
|
||
|
|
function Map(self, feature) return ListStreamWorker(self):Map(feature) end
|
||
|
|
|
||
|
|
--- Used to filter the items with a check function
|
||
|
|
__Arguments__{ Callable }
|
||
|
|
function Filter(self, func) return ListStreamWorker(self):Filter(func) end
|
||
|
|
|
||
|
|
__Arguments__{ Table }
|
||
|
|
function Filter(self, filter) return ListStreamWorker(self):Filter(filter) end
|
||
|
|
|
||
|
|
__Arguments__{ String, System.Any/nil }
|
||
|
|
function Filter(self, feature, value) return ListStreamWorker(self):Filter(feature, value) end
|
||
|
|
|
||
|
|
--- Used to select items with ranged index
|
||
|
|
__Arguments__{ Integer/1, Integer/-1, Integer/1 }
|
||
|
|
function Range(self, start, stop, step) return ListStreamWorker(self):Range(start, stop, step) end
|
||
|
|
|
||
|
|
-----------------------------------------------------------
|
||
|
|
-- Final method --
|
||
|
|
-----------------------------------------------------------
|
||
|
|
--- Convert the selected items to a raw hash table
|
||
|
|
function ToTable(self)
|
||
|
|
local result = {}
|
||
|
|
local index = 1
|
||
|
|
for _, value in self:GetIterator() do
|
||
|
|
result[index] = value
|
||
|
|
index = index + 1
|
||
|
|
end
|
||
|
|
return result
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Convert the selected items to a list
|
||
|
|
__Arguments__{ -IList/List }
|
||
|
|
function ToList(self, cls) return cls(self) end
|
||
|
|
|
||
|
|
--- Save the link operations into a xlist so we can use it as a new start for link operations
|
||
|
|
function ToXList(self) return XList(self) end
|
||
|
|
|
||
|
|
--- Combine the items to get a result
|
||
|
|
__Arguments__{ Callable, System.Any/nil }
|
||
|
|
function Reduce(self, func, init)
|
||
|
|
for _, obj in self:GetIterator() do
|
||
|
|
if init == nil then
|
||
|
|
init = obj
|
||
|
|
else
|
||
|
|
init = func(obj, init)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return init
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Call the function for each element or set property's value for each element
|
||
|
|
__Arguments__{ Callable, System.Any * 0 }
|
||
|
|
function Each(self, func, ...)
|
||
|
|
for _, obj in self:GetIterator() do
|
||
|
|
func(obj, ...)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{ String, System.Any * 0 }
|
||
|
|
function Each(self, feature, ...)
|
||
|
|
local cls, cmethod
|
||
|
|
|
||
|
|
for _, obj in self:GetIterator() do
|
||
|
|
if type(obj) == "table" then
|
||
|
|
if getobjectclass(obj) ~= cls then
|
||
|
|
cls = getobjectclass(obj)
|
||
|
|
cmethod = nil
|
||
|
|
if cls then
|
||
|
|
local ret = cls[feature]
|
||
|
|
if type(ret) == "function" then cmethod = ret end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local method = rawget(obj, feature) or cmethod
|
||
|
|
|
||
|
|
if type(method) == "function" then
|
||
|
|
method(obj, ...)
|
||
|
|
else
|
||
|
|
obj[feature] = ...
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Check if any element meet the requirement of the target function
|
||
|
|
__Arguments__{ Callable, System.Any * 0 }
|
||
|
|
function Any(self, chk, ...)
|
||
|
|
local iter, obj, idx, val = self:GetIterator()
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
while idx do
|
||
|
|
if chk(val, ...) then
|
||
|
|
-- Pass true to end iter if it support
|
||
|
|
iter(obj, idx, true)
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
end
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Check if all elements meet the requirement of the target function
|
||
|
|
__Arguments__{ Callable, System.Any * 0 }
|
||
|
|
function All(self, chk, ...)
|
||
|
|
local iter, obj, idx, val = self:GetIterator()
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
while idx do
|
||
|
|
if not chk(val, ...) then
|
||
|
|
-- Pass true to end iter if it support
|
||
|
|
iter(obj, idx, true)
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
end
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Get the first element of the list
|
||
|
|
__Arguments__{ Callable, System.Any * 0 }
|
||
|
|
function First(self, chk, ...)
|
||
|
|
local iter, obj, idx, val = self:GetIterator()
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
while idx do
|
||
|
|
if chk(val, ...) then
|
||
|
|
-- Pass true to end iter if it support
|
||
|
|
iter(obj, idx, true)
|
||
|
|
return val
|
||
|
|
end
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__ {}
|
||
|
|
function First(self)
|
||
|
|
local iter, obj, idx, val = self:GetIterator()
|
||
|
|
idx, val = iter(obj, idx)
|
||
|
|
while idx do
|
||
|
|
iter(obj, idx, true)
|
||
|
|
return val
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Get the last element of the list
|
||
|
|
__Arguments__{ Callable, System.Any * 0 }
|
||
|
|
function Last(self, chk, ...)
|
||
|
|
local last
|
||
|
|
|
||
|
|
for _, val in self:GetIterator() do
|
||
|
|
if chk(val, ...) then
|
||
|
|
last = val
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return last
|
||
|
|
end
|
||
|
|
|
||
|
|
__Arguments__{}
|
||
|
|
function Last(self)
|
||
|
|
if isObjectType(self, IIndexedList) then return self[self.Count] end
|
||
|
|
|
||
|
|
local last
|
||
|
|
|
||
|
|
for _, val in self:GetIterator() do
|
||
|
|
last = val
|
||
|
|
end
|
||
|
|
|
||
|
|
return last
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Get the concatenation of the List
|
||
|
|
__Arguments__{ String/nil }
|
||
|
|
function Join(self, sep)
|
||
|
|
return tblconcat(isObjectType(self, IIndexedList) and self or self:ToList(), sep)
|
||
|
|
end
|
||
|
|
|
||
|
|
--- Get the sum of the list
|
||
|
|
function Sum(self)
|
||
|
|
local sum = 0
|
||
|
|
for _, val in self:GetIterator() do sum = sum + (tonumber(val) or 0) end
|
||
|
|
return sum
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------
|
||
|
|
-- Serialization Extend --
|
||
|
|
-----------------------------------------------------------------------
|
||
|
|
export {
|
||
|
|
isListType = Class.IsSubType,
|
||
|
|
isstruct = Struct.Validate,
|
||
|
|
getstructcategory = Struct.GetStructCategory,
|
||
|
|
pairs = pairs,
|
||
|
|
type = type,
|
||
|
|
floor = math.floor,
|
||
|
|
|
||
|
|
Serialization
|
||
|
|
}
|
||
|
|
|
||
|
|
--- Whether the data is a list object
|
||
|
|
__Static__() function Serialization.IsArrayData(data)
|
||
|
|
-- Check the data type
|
||
|
|
local objField = data[Serialization.ObjectTypeField]
|
||
|
|
if objField then return isListType(objField, IIndexedList) or isstruct(objField) and getstructcategory(objField) == "ARRAY" or false end
|
||
|
|
|
||
|
|
-- Check the data
|
||
|
|
local count = #data
|
||
|
|
|
||
|
|
for k in pairs(data) do
|
||
|
|
if type(k) ~= "number" or (floor(k) ~= k or k < 0 or k > count) then
|
||
|
|
return false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
for i = 1, count do
|
||
|
|
if data[i] == nil then return false end
|
||
|
|
end
|
||
|
|
|
||
|
|
return true
|
||
|
|
end
|
||
|
|
end)
|