aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/shared.lua
diff options
context:
space:
mode:
authorMathias Fußenegger <mfussenegger@users.noreply.github.com>2023-06-08 12:11:24 +0200
committerGitHub <noreply@github.com>2023-06-08 12:11:24 +0200
commit7c661207cc4357553ed2b057b6c8f28400024361 (patch)
treef84c1082b2bbe5fc967c49a631aae8bc30b8dcd9 /runtime/lua/vim/shared.lua
parent38b0bb3c93022afcc54c0891d2eced02d2a9fa3a (diff)
downloadrneovim-7c661207cc4357553ed2b057b6c8f28400024361.tar.gz
rneovim-7c661207cc4357553ed2b057b6c8f28400024361.tar.bz2
rneovim-7c661207cc4357553ed2b057b6c8f28400024361.zip
feat(lua): add ringbuffer (#22894)
https://en.wikipedia.org/wiki/Circular_buffer
Diffstat (limited to 'runtime/lua/vim/shared.lua')
-rw-r--r--runtime/lua/vim/shared.lua94
1 files changed, 94 insertions, 0 deletions
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<T>
+ ---@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.
+ ---
+ --- <pre>
+ --- 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
+ --- </pre>
+ ---
+ --- 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