local record Ringbuffer {T} push: function(self: Ringbuffer, el: T): boolean pop: function(self: Ringbuffer): T | nil is_empty: function(self: Ringbuffer): boolean head: integer n: integer size: integer end local impl: table = {} impl.push = function(self: Ringbuffer, el: T): boolean if self.n == self.size then return false end -- items are at head + 0, head + 1, ..., head + (n-1) local tail = (self.head + self.n) % self.size self[1 + tail] = el self.n = self.n + 1 return true end impl.pop = function(self: Ringbuffer): T | nil if self.n == 0 then return nil end local res = self[1 + self.head] self.head = (self.head + 1) % self.size self.n = self.n - 1 return res end impl.is_empty = function(self: Ringbuffer): boolean return self.n == 0 end local function new(size: integer): Ringbuffer return setmetatable({ head = 0, n = 0, size = size }, { __index = impl }) end return { new = new, Ringbuffer = Ringbuffer }