Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
--n-tuple implementation based on an index tree.
--Cosmin Apreutesei. Public domain.
if not ... then require'tuple_test'; return end
local weakvals_meta = {__mode = 'v'}
--make a table with weak values.
local function weakvals(t)
return setmetatable(t or {}, weakvals_meta)
end
--make a table with strong values, i.e. make a table.
local function strongvals(t)
return t or {}
end
--convert nils and NaNs to be used as table keys.
local NIL = {}
local NAN = {}
local function tokey(v)
if v == nil then
return NIL
elseif v ~= v then
return NAN
else
return v
end
end
--make a new tuple space, with weak or strong references.
--using strong references is faster but dead tuples won't get collected
--until the space is released.
local function space(weak, index, tuples)
local weakvals = weak and weakvals or strongvals
index = weakvals(index) --{k1 = index1}; index1 = {k2 = index2}
tuples = weakvals(tuples) --{index1 = tuple(k1), index2 = tuple(k1, k2)}
--find a matching tuple by going through the index tree.
local function find(n, ...)
local index = index
for i = 1, n do
local k = tokey(select(i, ...))
index = index[k]
if not index then
return
end
end
return tuples[index]
end
--add a new tuple to the index tree.
local function add(n, tuple)
tuple.n = n
local index = index
for i = 1, n do
local k = tokey(tuple[i])
local t = index[k]
if not t then
t = weakvals()
index[k] = t
end
if weak and i < n then
tuple[t] = true --anchor index table in the tuple.
end
index = t
end
tuples[index] = tuple
return tuple
end
--get a matching tuple, or make a new one and add it to the index.
local function tuple_vararg(...)
local n = select('#', ...)
return find(n, ...) or add(n, {...})
end
--same as above, but for a fixed number of elements.
local function tuple_narg(n, ...)
local tuple = find(n, ...)
if not tuple then
tuple = {}
for i = 1, n do
tuple[i] = select(i, ...)
end
tuple = add(n, tuple)
end
return tuple
end
--same as above, but using a table as input.
local function tuple_array(tuple)
local n = tuple.n or #tuple
return find(n, unpack(tuple, 1, n)) or add(n, tuple)
end
local function iterate()
return coroutine.wrap(function()
for _,v in pairs(tuples) do
coroutine.yield(v)
end
end)
end
--remove an existing tuple, found by previously by creating it or from iteration.
local function remove_from(index, t, i)
local k = tokey(t[i])
local index1 = index[k]
if index1 then
return remove_from(index1, t, i+1) --tail call
else
tuples[index] = nil
index[k] = nil
end
end
local function remove(t)
return remove_from(index, t, 1)
end
return tuple_vararg, tuple_narg, tuple_array, iterate, remove
end
--tuple class
local tuple = {}
local tuple_meta = {__index = tuple, __newindex = false}
local function wrap(t)
return setmetatable(t, tuple_meta)
end
function tuple:unpack(i, j)
return unpack(self, i, self.n)
end
tuple_meta.__call = tuple.unpack
function tuple_meta:__tostring()
local t = {}
for i=1,self.n do
t[i] = tostring(self[i])
end
return string.format('(%s)', table.concat(t, ', '))
end
--integration with the pp module.
function tuple_meta:__pwrite(write, write_value)
write'tuple('; write_value(self[1])
for i=2,self.n do
write','; write_value(self[i])
end
write')'
end
--tuple space module
local space_module
function space_module(weak, ...)
local tuple_vararg, tuple_narg, tuple_array, iterate, remove = space(weak, ...)
return setmetatable({
space = space_module,
narg = function(n, ...)
return wrap(tuple_narg(n, ...))
end,
from_array = function(t)
return wrap(tuple_array(t))
end,
tuples = iterate,
remove = remove,
}, {
__call = function(_, ...)
return wrap(tuple_vararg(...))
end
})
end
--default weak tuple space module
return space_module(true)