Skip to content

Instantly share code, notes, and snippets.

@pablomayobre
Last active December 22, 2018 01:11
Show Gist options
  • Save pablomayobre/adc1ed058a9ae350df559e2b100949dc to your computer and use it in GitHub Desktop.
Save pablomayobre/adc1ed058a9ae350df559e2b100949dc to your computer and use it in GitHub Desktop.
Perform many removal, inserting operations on a table, fast!
local batch = {}
local holes_err = "bad argument #%s to function '%s' (this list doesn't support holes)"
local refill = function (t, ...)
local newn = select('#', ...)
local length = math.max(newn, (t.n or #t))
for i = 1, length do
t[i] = select(i, ...)
if (not t.n) and (t[i] == nil) and (i < newn) then
error(holes_err:format(i + 1, 'batch.refill'), 3)
end
end
if t.n then
t.n = newn
end
end
local push = function (t, ...)
local length = t.n or #t
local pushed = select('#', ...)
for i=1, pushed do
local value = select(i, ...)
if not t.n and value == nil then
return i
end
t[length + i] = value
end
if t.n then
t.n = length + pushed
end
end
local splice = function (t, position, removed, ...)
local inserted = select('#', ...)
local length = (t.n or #t)
removed = math.min(removed, length - position + 1)
-- Hack: Inverting the order of the loop fixes issues with weird removing/inserting
local a, b, c = position, length + inserted, 1
if inserted > removed then
a, b, c = b, a, -c
end
for i = a, b, c do
local j = i - inserted
if j < position then
local value = select(i + 1 - position, ...)
if not t.n and value == nil then
return i + 1 - position
end
t[i] = value
else
local k = j + removed
if k > length then
t[i] = nil
else
t[i] = t[k]
end
end
end
if t.n then
t.n = length
end
end
-- a = {1, 2, 3, 4, 5}
-- b = {}
-- >>> batch.filter(a, b, function(i, t) return i%2 == 0 end)
-- b = {1, 3, 5}
-- Any other argument passed to batch.filter gets passed to the function after i, t
batch.filter = function (a, b, callback, ...)
local alength = a.n or #a
local blength = b.n or #b
local left = alength
local j = 1
for i = 1, alength do
if not callback(i, a, ...) then
left = left - 1
else
b[j] = a[i]
j = j + 1
end
end
for i = left + 1, blength do
b[i] = nil
end
if b.n then
b.n = left
end
return b
end
-- t = {1, 2, 3, 4, 5}
-- >>> batch.refill(t, 6, 7, 8, 9, 10, 11)
-- t = {6, 7, 8, 9, 10, 11}
batch.refill = function (...)
return refill(...)
end
-- t = {1, 2, 3, 4, 5}
-- >>> batch.clear(t)
-- t = {}
batch.clear = function (t)
return refill(t)
end
-- t = {1, 2, 3, 4, 5, 6, 7}
-- >>> batch.splice(t, 3, 2, 8, 9, 10)
-- t = {1, 2, 8, 9, 10, 5, 6, 7}
batch.splice = function (t, ...)
local index = splice(t, ...)
if index then
error(holes_err:format(index + 3, 'batch.splice'), 2)
end
return t
end
-- t = {1, 2, 3, 4, 5}
-- >>> batch.insert(t, 3, 6, 7, 8)
-- t = {1, 2, 6, 7, 8, 3, 4, 5}
batch.insert = function (t, position, ...)
local index
if not position or position > (t.n or #t) then
index = push(t, ...)
else
index = splice(t, position, 0, ...)
end
if index then
error(holes_err:format(index + 2, 'batch.insert'), 2)
end
return t
end
-- t = {1, 2, 3, 4, 5}
-- >>> batch.push(t, 6, 7, 8)
-- t = {1, 2, 3, 4, 5, 6, 7, 8}
batch.push = function (t, ...)
local index = push(t, ...)
if index then
error(holes_err:format(index + 1, 'batch.push'), 2)
end
return t
end
-- t = {1, 2, 3, 4, 5, 6, 7}
-- >>> batch.remove(t, 3, 2)
-- t = {1, 2, 5, 6, 7}
batch.remove = function (t, position, n)
splice(t, position, n)
return t
end
-- t = {1, 2, nil, 4, 5}
-- >>> batch.maxn(t) == 5
batch.maxn = function (t)
local n = math.max(t.n, #t)
for k, _ in next, t do
if type(k) == 'number' and k > n then
n = k
end
end
return n
end
-- a = {1, 2, 3, 4, 5}
-- b = {}
-- >>> batch.copy(a, b)
-- b = {1, 2, 3, 4, 5}
batch.copy = function (a, b)
local alength = a.n or #a
local blength = b.n or #b
for i=1, math.max(alength, blength) do
if i <= alength then
b[i] = a[i]
else
b[i] = nil
end
end
return b
end
return batch
@pablomayobre
Copy link
Author

RULE: Batch should never create tables by itself, not even when parameters are not supplied.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment