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.
256 lines
9.2 KiB
256 lines
9.2 KiB
--===========================================================================--
|
|
-- --
|
|
-- System.Collections.Queue --
|
|
-- --
|
|
--===========================================================================--
|
|
|
|
--===========================================================================--
|
|
-- Author : kurapica125@outlook.com --
|
|
-- URL : http://github.com/kurapica/PLoop --
|
|
-- Create Date : 2019/12/08 --
|
|
-- Update Date : 2019/12/08 --
|
|
-- Version : 1.0.0 --
|
|
--===========================================================================--
|
|
|
|
PLoop(function(_ENV)
|
|
namespace "System.Collections"
|
|
|
|
import "System.Serialization"
|
|
|
|
--- Represents a first-in, first-out collection of objects.
|
|
__Sealed__() __Serializable__() __Arguments__{ AnyType }( Any )
|
|
__NoNilValue__(false):AsInheritable() __NoRawSet__(false):AsInheritable()
|
|
class "Queue" (function(_ENV, lsttype)
|
|
extend "ICountable" "ISerializable"
|
|
|
|
export { type = type, ipairs = ipairs, yield = coroutine.yield, select = select, unpack = _G.unpack or table.unpack, min = math.min }
|
|
|
|
lsttype = lsttype ~= Any and lsttype or nil
|
|
|
|
if lsttype then
|
|
export {
|
|
valid = getmetatable(lsttype).ValidateValue,
|
|
GetErrorMessage = Struct.GetErrorMessage,
|
|
parseindex = Toolset.parseindex,
|
|
}
|
|
end
|
|
|
|
local FIELD_FRONT = -1
|
|
local FIELD_REAR = -2
|
|
local FIELD_CLEAR = -3
|
|
|
|
-----------------------------------------------------------
|
|
-- 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 = { [FIELD_FRONT] = 0 }
|
|
while v ~= nil do
|
|
self[i] = v
|
|
i = i + 1
|
|
v = info:GetValue(i, lsttype)
|
|
end
|
|
|
|
self[FIELD_REAR] = i - 1
|
|
|
|
return self, true
|
|
end
|
|
|
|
-----------------------------------------------------------
|
|
-- property --
|
|
-----------------------------------------------------------
|
|
--- Get the count of items in the object
|
|
property "Count" { set = false, get = function (self) return self[FIELD_REAR] - self[FIELD_FRONT] end }
|
|
|
|
-----------------------------------------------------------
|
|
-- method --
|
|
-----------------------------------------------------------
|
|
--- Returns an iterator that iterates through the Queue
|
|
__Iterator__()
|
|
function GetIterator(self)
|
|
local start = self[FIELD_FRONT]
|
|
local stop = self[FIELD_REAR]
|
|
|
|
for i = 1, stop - start do
|
|
yield(i, self[i + start])
|
|
end
|
|
end
|
|
|
|
--- Whether an item existed in the Queue
|
|
function Contains(self, item)
|
|
for i = self[FIELD_FRONT] + 1, self[FIELD_REAR] do
|
|
if self[i] == item then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
--- Adds an object to the end of the Queue
|
|
if lsttype then __Arguments__{ lsttype * 1 } end
|
|
function Enqueue(self, ...)
|
|
if self[FIELD_CLEAR] then
|
|
for i = self[FIELD_CLEAR], self[FIELD_FRONT] do
|
|
self[i] = nil
|
|
end
|
|
|
|
self[FIELD_CLEAR] = nil
|
|
end
|
|
|
|
local count = select("#", ...)
|
|
local start = self[FIELD_REAR]
|
|
|
|
for i = 1, count do
|
|
self[start + i] = select(i, ...)
|
|
end
|
|
|
|
self[FIELD_REAR] = start + count
|
|
|
|
return self
|
|
end
|
|
|
|
--- Removes and returns the object at the beginning of the Queue
|
|
function Dequeue(self, count)
|
|
count = min(count and type(count) == "number" and count or 1, self[FIELD_REAR] - self[FIELD_FRONT])
|
|
if count < 1 then return end
|
|
|
|
local start = self[FIELD_FRONT] + 1
|
|
self[FIELD_CLEAR] = self[FIELD_CLEAR] or start
|
|
self[FIELD_FRONT] = start + count - 1
|
|
|
|
return unpack(self, start, self[FIELD_FRONT])
|
|
end
|
|
|
|
--- Clear the queue
|
|
function Clear(self)
|
|
for i = self[FIELD_CLEAR] or (self[FIELD_FRONT] + 1), self[FIELD_REAR] do
|
|
self[i] = nil
|
|
end
|
|
self[FIELD_FRONT] = 0
|
|
self[FIELD_REAR] = 0
|
|
self[FIELD_CLEAR] = nil
|
|
end
|
|
|
|
--- Returns the object at the beginning of the Queue without removing it
|
|
__Arguments__{ NaturalNumber/nil }
|
|
function Peek(self, count)
|
|
count = min(count and type(count) == "number" and count or 1, self[FIELD_REAR] - self[FIELD_FRONT])
|
|
if count < 1 then return end
|
|
|
|
local start = self[FIELD_FRONT]
|
|
return unpack(self, start + 1, start + count)
|
|
end
|
|
|
|
__Arguments__{ NaturalNumber, NaturalNumber }
|
|
function Peek(self, start, count)
|
|
start = self[FIELD_FRONT] + start - 1
|
|
count = min(count, self[FIELD_REAR] - start)
|
|
return unpack(self, start + 1, start + count)
|
|
end
|
|
|
|
-----------------------------------------------------------
|
|
-- constructor --
|
|
-----------------------------------------------------------
|
|
__Arguments__{ RawTable }
|
|
function __new(_, lst)
|
|
lst[FIELD_FRONT] = 0
|
|
lst[FIELD_REAR] = #lst
|
|
return lst, true
|
|
end
|
|
|
|
__Arguments__{ IList }
|
|
function __new(_, lst)
|
|
local i = 0
|
|
local obj = { [FIELD_FRONT] = 0 }
|
|
for idx, item in lst:GetIterator() do
|
|
i = i + 1
|
|
obj[i] = item
|
|
end
|
|
obj[FIELD_REAR] = i
|
|
return obj, true
|
|
end
|
|
|
|
__Arguments__{ Callable, System.Any/nil, System.Any/nil }
|
|
function __new(_, iter, obj, idx)
|
|
local i = 0
|
|
local lst = { [FIELD_FRONT] = 0 }
|
|
for key, item in iter, obj, idx do
|
|
i = i + 1
|
|
if item ~= nil then
|
|
lst[i] = item
|
|
else
|
|
lst[i] = key
|
|
end
|
|
end
|
|
obj[FIELD_REAR] = i
|
|
return lst, true
|
|
end
|
|
|
|
__Arguments__{ NaturalNumber, Callable }
|
|
function __new(_, count, initValue)
|
|
local obj = { [FIELD_FRONT] = 0 }
|
|
for i = 1, count do
|
|
obj[i] = initValue(i)
|
|
end
|
|
obj[FIELD_REAR] = count
|
|
return obj, true
|
|
end
|
|
|
|
__Arguments__{ NaturalNumber, System.Any/nil }
|
|
function __new(_, count, initValue)
|
|
local obj = { [FIELD_FRONT] = 0 }
|
|
if initValue ~= nil then
|
|
for i = 1, count do
|
|
obj[i] = initValue
|
|
end
|
|
else
|
|
for i = 1, count do
|
|
obj[i] = i
|
|
end
|
|
end
|
|
obj[FIELD_REAR] = count
|
|
return obj, true
|
|
end
|
|
|
|
__Arguments__{ Any * 0 }
|
|
function __new(_, ...)
|
|
local obj = { ... }
|
|
obj[FIELD_FRONT] = 0
|
|
obj[FIELD_REAR] = #obj
|
|
return obj, 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 --
|
|
-----------------------------------------------------------
|
|
if lsttype then __Arguments__{ lsttype * 0 } end
|
|
function __call(self, item, ...)
|
|
if item ~= nil then
|
|
return self:Enqueue(item, ...)
|
|
else
|
|
return self:Dequeue()
|
|
end
|
|
end
|
|
|
|
function __len(self)
|
|
return self[FIELD_REAR] - self[FIELD_FRONT]
|
|
end
|
|
end)
|
|
end)
|
|
|