diff --git a/hashlist.lua b/hashlist.lua new file mode 100644 index 0000000..5e84623 --- /dev/null +++ b/hashlist.lua @@ -0,0 +1,90 @@ +-- Localize globals +local setmetatable = setmetatable + +-- Table based list, can handle at most 2^52 pushes +local list = {} +-- TODO use __len for Lua version > 5.1 +local metatable = {__index = list} +list.metatable = metatable + +-- Takes a list +function list:new() + self.head = 0 + self.length = #self + return setmetatable(self, metatable) +end + +function list:in_bounds(index) + return index >= 1 and index <= self.length +end + +function list:get(index) + return self[self.head + index] +end + +function list:set(index, value) + assert(value ~= nil) + self[self.head + index] = value +end + +function list:len() + return self.length +end + +function list:ipairs() + local index = 1 + return function() + if index > self.length then + return + end + return index, self[self.head + index] + end +end + +function list:rpairs() + local index = self.length + return function() + if index < 1 then + return + end + return index, self[self.head + index] + end +end + +function list:push_tail(value) + assert(value ~= nil) + self.length = self.length + 1 + self[self.head + self.length] = value +end + +function list:get_tail() + return self[self.head + self.length] +end + +function list:pop_tail() + if self.length == 0 then return end + local value = self:get_tail() + self[self.head + self.length] = nil + self.length = self.length - 1 + return value +end + +function list:push_head(value) + self[self.head] = value + self.head = self.head - 1 + self.length = self.length + 1 +end + +function list:get_head() + return self[self.head + 1] +end + +function list:pop_head() + if self.length == 0 then return end + local value = self:get_head() + self.head = self.head + 1 + self[self.head] = nil + return value +end + +return list \ No newline at end of file diff --git a/test.lua b/test.lua index 2ddabf2..34d776f 100644 --- a/test.lua +++ b/test.lua @@ -99,6 +99,19 @@ do end end +-- hashlist +do + local n = 100 + local list = hashlist.new{} + for i = 1, n do + list:push_tail(i) + end + for i = 1, n do + local head = list:get_head() + assert(head == list:pop_head(i) and head == i) + end +end + -- ranked set do local n = 100