diff options
author | Mathias Fußenegger <mfussenegger@users.noreply.github.com> | 2023-06-08 12:11:24 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-08 12:11:24 +0200 |
commit | 7c661207cc4357553ed2b057b6c8f28400024361 (patch) | |
tree | f84c1082b2bbe5fc967c49a631aae8bc30b8dcd9 /runtime/lua/vim/shared.lua | |
parent | 38b0bb3c93022afcc54c0891d2eced02d2a9fa3a (diff) | |
download | rneovim-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.lua | 94 |
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 |