diff --git a/lib/utils/deque.lua b/lib/utils/deque.lua new file mode 100644 index 0000000..cc31ccd --- /dev/null +++ b/lib/utils/deque.lua @@ -0,0 +1,121 @@ +---@class Deque +---@field private first integer +---@field private last integer +---@field private _data table +local Deque = {} +Deque.__index = Deque + +---Создать пустую очередь +---@return Deque +local function new() + ---@type Deque + local self = setmetatable({ + first = 1, + last = 0, + _data = {}, + }, Deque) + return self +end + +---Количество элементов +---@return integer +function Deque:size() + return self.last - self.first + 1 +end + +---Пуста ли очередь +---@return boolean +function Deque:is_empty() + return self.first > self.last +end + +---Добавить в начало +---@param value any +---@return Deque self +function Deque:push_front(value) + self.first = self.first - 1 + self._data[self.first] = value + return self +end + +---Добавить в конец +---@param value any +---@return Deque self +function Deque:push_back(value) + self.last = self.last + 1 + self._data[self.last] = value + return self +end + +---Забрать из начала +---@return any +function Deque:pop_front() + if self.first > self.last then return nil end + local value = self._data[self.first] + self._data[self.first] = nil + self.first = self.first + 1 + return value +end + +---Забрать из конца +---@return any +function Deque:pop_back() + if self.first > self.last then return nil end + local value = self._data[self.last] + self._data[self.last] = nil + self.last = self.last - 1 + return value +end + +---Подсмотреть начало +---@return any +function Deque:peek_front() + if self.first > self.last then return nil end + return self._data[self.first] +end + +---Подсмотреть конец +---@generic T +---@return T|nil +function Deque:peek_back() + if self.first > self.last then return nil end + return self._data[self.last] +end + +---Очистить очередь +function Deque:clear() + -- Полная очистка таблицы для GC + for i = self.first, self.last do + self._data[i] = nil + end + self.first, self.last = 1, 0 +end + +---Итератор по значениям слева направо +---@return fun():any +function Deque:values() + local i = self.first + return function() + if i <= self.last then + local v = self._data[i] + i = i + 1 + return v + end + end +end + +---Преобразовать в массив +---@return any[] +function Deque:to_array() + local n = self:size() + local arr = {} + if n <= 0 then return arr end + local j = 1 + for i = self.first, self.last do + arr[j] = self._data[i] + j = j + 1 + end + return arr +end + +return { new = new }