210 lines
4.8 KiB
Lua
210 lines
4.8 KiB
Lua
--[[
|
|
Doubly-Linked List
|
|
|
|
Function documentation:
|
|
|
|
* rp_mobs.DoublyLinkedList(): Create and return a doubly-linked list (henceforced called "list")
|
|
* list:append(data): Append data to the end of the list. data MUST NOT be nil. Returns entry
|
|
* list:prepend(data): Add data to the beginning of the list. data MUST NOT be nil. Returns entry
|
|
* list:insertBefore(data, previous): Insert data before the entry 'previous'. data MUST NOT be nil. Returns entry
|
|
* list:insertAfter(data, nexxt): Insert data after the entry 'nexxt'. data MUST NOT be nil. Returns entry
|
|
* list:remove(entry): Removes entry from list
|
|
* list:removeAll(): Removes all entries from list
|
|
* list:find(data, reverse): Returns the first entry that is equal to data and returns it.
|
|
Returns nil if it does not exist. If `reverse` is `true`, will traverse the list backwards instead
|
|
* list:iterator(reverse): Returns a function that will return a new element data each time it is called,
|
|
starting with the first, until it reaches the end of the list where it will return nil.
|
|
If `reverse` is true, will traverse the list in reverse order instead
|
|
* list:getFirst(): Returns the first entry or nil if there is none
|
|
* list:getLast(): Returns the last entry or nil if there is none
|
|
* list:isEmpty(): Returns true if the list is empty
|
|
]]
|
|
|
|
|
|
-- Implementation of doubly-linked list
|
|
|
|
--[[
|
|
Internal data structure: list entry:
|
|
entry = {
|
|
nextEntry = , -- reference to next entry or nil
|
|
prevEntry = , -- reference to previous entry or nil
|
|
}
|
|
|
|
Internal data structure: DoublyLinkedList:
|
|
list = {
|
|
first = , -- reference to first entry or nil
|
|
last = , -- reference to last entry or nil
|
|
|
|
append, prepend, ... = , -- references to all the functions
|
|
}
|
|
]]
|
|
|
|
|
|
-- The functions for the doubly-linked list
|
|
|
|
local append = function(self, data)
|
|
local newEntry = {
|
|
data = data,
|
|
}
|
|
local entry = self.last
|
|
if not entry then
|
|
self.first = newEntry
|
|
self.last = newEntry
|
|
else
|
|
self.last.nextEntry = newEntry
|
|
newEntry.prevEntry = self.last
|
|
self.last = newEntry
|
|
end
|
|
return newEntry
|
|
end
|
|
|
|
local prepend = function(self, data)
|
|
local newEntry = {
|
|
data = data,
|
|
}
|
|
local entry = self.first
|
|
if not entry then
|
|
self.first = newEntry
|
|
self.last = newEntry
|
|
else
|
|
self.first.prevEntry = newEntry
|
|
newEntry.nextEntry = self.first
|
|
self.first = newEntry
|
|
end
|
|
return newEntry
|
|
end
|
|
|
|
local insertAfter = function(self, data, previous)
|
|
local newEntry = {
|
|
data = data,
|
|
prevEntry = previous,
|
|
}
|
|
if previous.nextEntry then
|
|
newEntry.nextEntry = previous.nextEntry
|
|
newEntry.nextEntry.prevEntry = newEntry
|
|
previous.nextEntry = newEntry
|
|
else
|
|
previous.nextEntry = newEntry
|
|
self.last = newEntry
|
|
end
|
|
return newEntry
|
|
end
|
|
local insertBefore = function(self, data, nexxt)
|
|
local newEntry = {
|
|
data = data,
|
|
nextEntry = nexxt,
|
|
}
|
|
if nexxt.prevEntry then
|
|
newEntry.prevEntry = nexxt.prevEntry
|
|
newEntry.prevEntry.nextEntry = newEntry
|
|
nexxt.prevEntry = newEntry
|
|
else
|
|
nexxt.prevEntry = newEntry
|
|
self.first = newEntry
|
|
end
|
|
return newEntry
|
|
end
|
|
local remove = function(self, entryToRemove)
|
|
local neighborNext = entryToRemove.nextEntry
|
|
local neighborPrev = entryToRemove.prevEntry
|
|
if neighborNext then
|
|
neighborNext.prevEntry = neighborPrev
|
|
end
|
|
if neighborPrev then
|
|
neighborPrev.nextEntry = neighborNext
|
|
end
|
|
if neighborNext == nil then
|
|
self.last = neighborPrev
|
|
end
|
|
if neighborPrev == nil then
|
|
self.first = neighborNext
|
|
end
|
|
end
|
|
local removeAll = function(self)
|
|
self.first = nil
|
|
self.last = nil
|
|
end
|
|
|
|
local find = function(self, dataToFind, inReverse)
|
|
local entry
|
|
if inReverse then
|
|
entry = self.last
|
|
else
|
|
entry = self.first
|
|
end
|
|
while(entry) do
|
|
if entry.data == dataToFind then
|
|
return entry
|
|
end
|
|
if inReverse then
|
|
entry = entry.prevEntry
|
|
else
|
|
entry = entry.nextEntry
|
|
end
|
|
end
|
|
end
|
|
|
|
local iterator = function(self, reverse)
|
|
local elem
|
|
if reverse then
|
|
elem = self.last
|
|
else
|
|
elem = self.first
|
|
end
|
|
return function()
|
|
if elem == nil then
|
|
return
|
|
end
|
|
local ret = elem.data
|
|
if reverse then
|
|
elem = elem.prevEntry
|
|
else
|
|
elem = elem.nextEntry
|
|
end
|
|
return ret
|
|
end
|
|
end
|
|
|
|
local getFirst = function(self)
|
|
if self.first then
|
|
return self.first
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local getLast = function(self)
|
|
if self.last then
|
|
return self.last
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
|
|
local isEmpty = function(self)
|
|
if not self.first then
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
rp_mobs.DoublyLinkedList = function()
|
|
local dllist = {}
|
|
dllist.append = append
|
|
dllist.prepend = prepend
|
|
dllist.insertAfter = insertAfter
|
|
dllist.insertBefore = insertBefore
|
|
dllist.remove = remove
|
|
dllist.removeAll = removeAll
|
|
dllist.find = find
|
|
dllist.iterator = iterator
|
|
dllist.getFirst = getFirst
|
|
dllist.getLast = getLast
|
|
dllist.isEmpty = isEmpty
|
|
dllist.first = nil -- reference to first entry
|
|
dllist.last = nil -- reference to last entry
|
|
return dllist
|
|
end
|
|
|