Skip to content

Instantly share code, notes, and snippets.

@ochaton
Last active March 28, 2020 21:48
Show Gist options
  • Save ochaton/4b1a31043bf1632f4314f10a5bb0636e to your computer and use it in GitHub Desktop.
Save ochaton/4b1a31043bf1632f4314f10a5bb0636e to your computer and use it in GitHub Desktop.
Attempt to understand how #t works in Lua
-- Execute with tarantool or luajit
assert(jit, "jit required")
local table_new = require 'table.new'
local function tablen(t, len)
local j = len
if j > 1 and t[j] == nil then
-- Use i = 0 here because in Lua tables are 1-indexed:
local i = 0
-- Implements right binsearch.
-- Finds first right non-nil value:
while (j - i) > 1 do
local m = math.floor((i+j)/2)
if t[m] == nil then
j = m
else
i = m
end
end
return i
end
return j
end
local function testit(t, n)
local len = tablen(t, n)
assert(#t == len, "Failed: " .. len .. " != " .. #t)
local m = {}
for i = 1, n do
if t[i] ~= nil then
table.insert(m, ("[%d] = %s"):format(i, t[i]))
end
end
print("Len=".. len, "{" .. table.concat(m, ", ") .. "}")
end
-- Returns table with less than 2*log(len) items with desired length
local function adopt_table(len)
if len == 0 then
return {}
end
local maxn = 2^math.floor(1+math.log(len, 2))
local t = table_new(maxn, 0)
local i = 0
local j = maxn
while (j - i) > 1 do
local m = math.floor((i+j)/2)
if m <= len then
t[m] = i
i = m
else
j = m
end
end
return t, maxn
end
local t1 = {1, 2, nil, 4}
testit(t1, 4) --> 4
local t2 = {1, 2, nil, nil}
testit(t2, 4) --> 2
local t3 = {1, 2, 3, nil, 5, nil}
testit(t3, 6) --> 3
local t4 = {1, nil, 3, 4, 5, nil}
testit(t4, 6) --> 5
local t5 = table_new(129, 0)
testit(t5, 129) --> 0
local t6 = table_new(129, 0)
t6[64] = 64
testit(t6, 129) --> 64
t6[95] = 95
testit(t6, 129) --> 64
t6[80] = 80
testit(t6, 129) --> 80
t6[96] = 96
testit(t6, 129) --> 96
testit(adopt_table(100500)) --> 100500
for len = 1, 10000 do
local t = adopt_table(len)
assert(#t == len, len)
local c = 0
for _ in pairs(t) do c = c + 1 end
if len > 16 then assert(c <= 2*math.log(len), len) end
end
--[[
Len=4 {[1] = 1, [2] = 2, [4] = 4}
Len=2 {[1] = 1, [2] = 2}
Len=3 {[1] = 1, [2] = 2, [3] = 3, [5] = 5}
Len=5 {[1] = 1, [3] = 3, [4] = 4, [5] = 5}
Len=0 {}
Len=64 {[64] = 64}
Len=64 {[64] = 64, [95] = 95}
Len=80 {[64] = 64, [80] = 80, [95] = 95}
Len=96 {[64] = 64, [80] = 80, [95] = 95, [96] = 96}
]]
@ochaton
Copy link
Author

ochaton commented Mar 28, 2020

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