Software /
code /
prosody
File
util/queue.lua @ 10973:39991e40d1dc
util.dbuffer: dynamic string buffer
Similar to util.ringbuffer (and shares almost identical API). Differences:
- size limit is optional and dynamic
- does not allocate a fixed buffer of max_size bytes
- focus on simply storing references to existing string objects where possible,
avoiding unnecessary allocations
- references are still stored in a ring buffer to enable use as a fast FIFO
Optional second parameter to new() provides the number of ring buffer segments. On
Lua 5.2 on my laptop, a segment is ~19 bytes. If the ring buffer fills up, the next
write will compact all strings into a single item.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Fri, 26 Jun 2020 16:41:31 +0100 |
parent | 9926:1bfd28e774db |
child | 11114:6a608ecb3471 |
line wrap: on
line source
-- Prosody IM -- Copyright (C) 2008-2015 Matthew Wild -- Copyright (C) 2008-2015 Waqas Hussain -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- -- Small ringbuffer library (i.e. an efficient FIFO queue with a size limit) -- (because unbounded dynamically-growing queues are a bad thing...) local have_utable, utable = pcall(require, "util.table"); -- For pre-allocation of table local function new(size, allow_wrapping) -- Head is next insert, tail is next read local head, tail = 1, 1; local items = 0; -- Number of stored items local t = have_utable and utable.create(size, 0) or {}; -- Table to hold items --luacheck: ignore 212/self return { _items = t; size = size; count = function (self) return items; end; push = function (self, item) if items >= size then if allow_wrapping then tail = (tail%size)+1; -- Advance to next oldest item items = items - 1; else return nil, "queue full"; end end t[head] = item; items = items + 1; head = (head%size)+1; return true; end; pop = function (self) if items == 0 then return nil; end local item; item, t[tail] = t[tail], 0; tail = (tail%size)+1; items = items - 1; return item; end; peek = function (self) if items == 0 then return nil; end return t[tail]; end; replace = function (self, data) if items == 0 then return self:push(data); end t[tail] = data; return true; end; items = function (self) return function (_, pos) if pos >= items then return nil; end local read_pos = tail + pos; if read_pos > self.size then read_pos = (read_pos%size); end return pos+1, t[read_pos]; end, self, 0; end; consume = function (self) return self.pop, self; end; }; end return { new = new; };