From 7c661207cc4357553ed2b057b6c8f28400024361 Mon Sep 17 00:00:00 2001 From: Mathias Fußenegger Date: Thu, 8 Jun 2023 12:11:24 +0200 Subject: feat(lua): add ringbuffer (#22894) https://en.wikipedia.org/wiki/Circular_buffer --- runtime/lua/vim/shared.lua | 94 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'runtime/lua') diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua index 4f230c4412..f899157ab7 100644 --- a/runtime/lua/vim/shared.lua +++ b/runtime/lua/vim/shared.lua @@ -881,4 +881,98 @@ function vim.defaulttable(create) }) end +do + ---@class vim.Ringbuf + ---@field private _items table[] + ---@field private _idx_read integer + ---@field private _idx_write integer + ---@field private _size integer + local Ringbuf = {} + + --- Clear all items + function Ringbuf.clear(self) + self._items = {} + self._idx_read = 0 + self._idx_write = 0 + end + + --- Adds an item, overriding the oldest item if the buffer is full. + ---@generic T + ---@param item T + function Ringbuf.push(self, item) + self._items[self._idx_write] = item + self._idx_write = (self._idx_write + 1) % self._size + if self._idx_write == self._idx_read then + self._idx_read = (self._idx_read + 1) % self._size + end + end + + --- Removes and returns the first unread item + ---@generic T + ---@return T? + function Ringbuf.pop(self) + local idx_read = self._idx_read + if idx_read == self._idx_write then + return nil + end + local item = self._items[idx_read] + self._items[idx_read] = nil + self._idx_read = (idx_read + 1) % self._size + return item + end + + --- Returns the first unread item without removing it + ---@generic T + ---@return T? + function Ringbuf.peek(self) + if self._idx_read == self._idx_write then + return nil + end + return self._items[self._idx_read] + end + + --- Create a ring buffer limited to a maximal number of items. + --- Once the buffer is full, adding a new entry overrides the oldest entry. + --- + ---
+  ---   local ringbuf = vim.ringbuf(4)
+  ---   ringbuf:push("a")
+  ---   ringbuf:push("b")
+  ---   ringbuf:push("c")
+  ---   ringbuf:push("d")
+  ---   ringbuf:push("e")    -- overrides "a"
+  ---   print(ringbuf:pop()) -- returns "b"
+  ---   print(ringbuf:pop()) -- returns "c"
+  ---
+  ---   -- Can be used as iterator. Pops remaining items:
+  ---   for val in ringbuf do
+  ---     print(val)
+  ---   end
+  --- 
+ --- + --- Returns a Ringbuf instance with the following methods: + --- + --- - |Ringbuf:push()| + --- - |Ringbuf:pop()| + --- - |Ringbuf:peek()| + --- - |Ringbuf:clear()| + --- + ---@param size integer + ---@return vim.Ringbuf ringbuf (table) + function vim.ringbuf(size) + local ringbuf = { + _items = {}, + _size = size + 1, + _idx_read = 0, + _idx_write = 0, + } + return setmetatable(ringbuf, { + __index = Ringbuf, + __call = function(self) + return self:pop() + end, + }) + end +end + return vim -- cgit