view util/multitable.lua @ 13461:c673ff1075bd

mod_posix: Move everything to util.startup This allows greater control over the order of events. Notably, the internal ordering between daemonization, initialization of libunbound and setup of signal handling is sensitive. libunbound starts a separate thread for processing DNS requests. If this thread is started before signal handling has been set up, it will not inherit the signal handlers and instead behave as it would have before signal handlers were set up, i.e. cause the whole process to immediately exit. libunbound is usually initialized on the first DNS request, usually triggered by an outgoing s2s connection attempt. If daemonization happens before signals have been set up, signals may not be processed at all.
author Kim Alvefur <zash@zash.se>
date Sat, 23 Mar 2024 20:48:19 +0100
parents 39ae08180c81
children c9c4a13732e4
line wrap: on
line source

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--

local select = select;
local t_insert = table.insert;
local pairs, next, type = pairs, next, type;
local unpack = table.unpack;

local _ENV = nil;
-- luacheck: std none

local function get(self, ...)
	local t = self.data;
	for n = 1,select('#', ...) do
		t = t[select(n, ...)];
		if not t then break; end
	end
	return t;
end

local function add(self, ...)
	local t = self.data;
	local count = select('#', ...);
	for n = 1,count-1 do
		local key = select(n, ...);
		local tab = t[key];
		if not tab then tab = {}; t[key] = tab; end
		t = tab;
	end
	t_insert(t, (select(count, ...)));
end

local function set(self, ...)
	local t = self.data;
	local count = select('#', ...);
	for n = 1,count-2 do
		local key = select(n, ...);
		local tab = t[key];
		if not tab then tab = {}; t[key] = tab; end
		t = tab;
	end
	t[(select(count-1, ...))] = (select(count, ...));
end

local function r(t, n, _end, ...)
	if t == nil then return; end
	local k = select(n, ...);
	if n == _end then
		t[k] = nil;
		return;
	end
	if k then
		local v = t[k];
		if v then
			r(v, n+1, _end, ...);
			if not next(v) then
				t[k] = nil;
			end
		end
	else
		for _,b in pairs(t) do
			r(b, n+1, _end, ...);
			if not next(b) then
				t[_] = nil;
			end
		end
	end
end

local function remove(self, ...)
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	r(self.data, 1, _end, ...);
end


local function s(t, n, results, _end, ...)
	if t == nil then return; end
	local k = select(n, ...);
	if n == _end then
		if k == nil then
			for _, v in pairs(t) do
				t_insert(results, v);
			end
		else
			t_insert(results, t[k]);
		end
		return;
	end
	if k then
		local v = t[k];
		if v then
			s(v, n+1, results, _end, ...);
		end
	else
		for _,b in pairs(t) do
			s(b, n+1, results, _end, ...);
		end
	end
end

-- Search for keys, nil == wildcard
local function search(self, ...)
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	local results = {};
	s(self.data, 1, results, _end, ...);
	return results;
end

-- Append results to an existing list
local function search_add(self, results, ...)
	if not results then results = {}; end
	local _end = select('#', ...);
	for n = _end,1 do
		if select(n, ...) then _end = n; break; end
	end
	s(self.data, 1, results, _end, ...);
	return results;
end

local function iter(self, ...)
	local query = { ... };
	local maxdepth = select("#", ...);
	local stack = { self.data };
	local keys = { };
	local function it(self) -- luacheck: ignore 432/self
		local depth = #stack;
		local key = next(stack[depth], keys[depth]);
		if key == nil then -- Go up the stack
			stack[depth], keys[depth] = nil, nil;
			if depth > 1 then
				return it(self);
			end
			return; -- The end
		else
			keys[depth] = key;
		end
		local value = stack[depth][key];
		if query[depth] == nil or key == query[depth] then
			if depth == maxdepth then -- Result
				local result = {}; -- Collect keys forming path to result
				for i = 1, depth do
					result[i] = keys[i];
				end
				result[depth+1] = value;
				return unpack(result, 1, depth+1);
			elseif type(value) == "table" then
				t_insert(stack, value); -- Descend
			end
		end
		return it(self);
	end;
	return it, self;
end

local function new()
	return {
		data = {};
		get = get;
		add = add;
		set = set;
		remove = remove;
		search = search;
		search_add = search_add;
		iter = iter;
	};
end

return {
	iter = iter;
	new = new;
};