Last active
December 22, 2018 01:11
-
-
Save pablomayobre/adc1ed058a9ae350df559e2b100949dc to your computer and use it in GitHub Desktop.
Perform many removal, inserting operations on a table, fast!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
RULE: Batch should never create tables by itself, not even when parameters are not supplied.