--[[ 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