1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-01-23 17:30:04 +08:00
SpaceVim/bundle/telescope.nvim-0.1.2/lua/telescope/algos/linked_list.lua

256 lines
5.0 KiB
Lua

local LinkedList = {}
LinkedList.__index = LinkedList
function LinkedList:new(opts)
opts = opts or {}
local track_at = opts.track_at
return setmetatable({
size = 0,
head = false,
tail = false,
-- track_at: Track at can track a particular node
-- Use to keep a node tracked at a particular index
-- This greatly decreases looping for checking values at this location.
track_at = track_at,
_tracked_node = nil,
tracked = nil,
}, self)
end
function LinkedList:_increment()
self.size = self.size + 1
return self.size
end
local create_node = function(item)
return {
item = item,
}
end
function LinkedList:append(item)
local final_size = self:_increment()
local node = create_node(item)
if not self.head then
self.head = node
end
if self.tail then
self.tail.next = node
node.prev = self.tail
end
self.tail = node
if self.track_at then
if final_size == self.track_at then
self.tracked = item
self._tracked_node = node
end
end
end
function LinkedList:prepend(item)
local final_size = self:_increment()
local node = create_node(item)
if not self.tail then
self.tail = node
end
if self.head then
self.head.prev = node
node.next = self.head
end
self.head = node
if self.track_at then
if final_size == self.track_at then
self._tracked_node = self.tail
elseif final_size > self.track_at then
self._tracked_node = self._tracked_node.prev
else
return
end
self.tracked = self._tracked_node.item
end
end
-- [a, b, c]
-- b.prev = a
-- b.next = c
--
-- a.next = b
-- c.prev = c
--
-- insert d after b
-- [a, b, d, c]
--
-- b.next = d
-- b.prev = a
--
-- Place "item" after "node" (which is at index `index`)
function LinkedList:place_after(index, node, item)
local new_node = create_node(item)
assert(node.prev ~= node)
assert(node.next ~= node)
local final_size = self:_increment()
-- Update tail to be the next node.
if self.tail == node then
self.tail = new_node
end
new_node.prev = node
new_node.next = node.next
node.next = new_node
if new_node.prev then
new_node.prev.next = new_node
end
if new_node.next then
new_node.next.prev = new_node
end
if self.track_at then
if index == self.track_at then
self._tracked_node = new_node
elseif index < self.track_at then
if final_size == self.track_at then
self._tracked_node = self.tail
elseif final_size > self.track_at then
self._tracked_node = self._tracked_node.prev
else
return
end
end
self.tracked = self._tracked_node.item
end
end
function LinkedList:place_before(index, node, item)
local new_node = create_node(item)
assert(node.prev ~= node)
assert(node.next ~= node)
local final_size = self:_increment()
-- Update head to be the node we are inserting.
if self.head == node then
self.head = new_node
end
new_node.prev = node.prev
new_node.next = node
node.prev = new_node
-- node.next = node.next
if new_node.prev then
new_node.prev.next = new_node
end
if new_node.next then
new_node.next.prev = new_node
end
if self.track_at then
if index == self.track_at - 1 then
self._tracked_node = node
elseif index < self.track_at then
if final_size == self.track_at then
self._tracked_node = self.tail
elseif final_size > self.track_at then
self._tracked_node = self._tracked_node.prev
else
return
end
end
self.tracked = self._tracked_node.item
end
end
-- Do you even do this in linked lists...?
-- function LinkedList:remove(item)
-- end
function LinkedList:iter()
local current_node = self.head
return function()
local node = current_node
if not node then
return nil
end
current_node = current_node.next
return node.item
end
end
function LinkedList:ipairs()
local index = 0
local current_node = self.head
return function()
local node = current_node
if not node then
return nil
end
current_node = current_node.next
index = index + 1
return index, node.item, node
end
end
function LinkedList:truncate(max_results)
if max_results >= self.size then
return
end
local current_node
if max_results < self.size - max_results then
local index = 1
current_node = self.head
while index < max_results do
local node = current_node
if not node.next then
break
end
current_node = current_node.next
index = index + 1
end
self.size = max_results
else
current_node = self.tail
while self.size > max_results do
if current_node.prev == nil then
break
end
current_node = current_node.prev
self.size = self.size - 1
end
end
self.tail = current_node
self.tail.next = nil
if max_results < self.track_at then
self.track_at = max_results
self.tracked = current_node.item
self._tracked_node = current_node
end
end
return LinkedList