File

util/multitable.lua @ 7567:495de404a8ae

ejabberdsql2prosody: rename variable 'host' to prevent shadowing upvalue [luacheck] Functions roster(), roster_pending(), roster_group(), private_storage() and offline_msg() have argument named "host", which used to shadow upvalue of this variable before this change. Instead of renaming this argument, let's rename the variable to match what the script says in usage: Usage: ejabberdsql2prosody.lua filename.txt hostname
author Anton Shestakov <av6@dwimlabs.net>
date Fri, 12 Aug 2016 13:44:47 +0800
parent 7185:5687788a2e4d
child 8382:e5d00bf4a4d5
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 or unpack; --luacheck: ignore 113

local _ENV = nil;

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)
		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;
};