Rather more robust nr_elements_in_seq
.
This commit is contained in:
parent
a13c6351c1
commit
ef0a4c82ed
|
@ -39,10 +39,10 @@ local LEAF_VALUE_TYPES = {
|
||||||
['boolean'] = true,
|
['boolean'] = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
local SHORT_STRING_MAX_LEN = 7
|
local SHORT_STRING_MAX_LEN = 7 -- Range: [0, ∞[
|
||||||
local MINIMUM_NUMBER_OF_SET_ELEMENTS = 2
|
local MINIMUM_NUMBER_OF_SET_ELEMENTS = 2 -- Range: [1, ∞[
|
||||||
|
local ALLOWED_HOLE_SIZE_IN_SEQUENCE = 1 -- Range: [0, ∞[. Set to 0, to completely disallow holes in sequences.
|
||||||
local RECURSIVE_TOSTRING_TIMEOUT = 10
|
local RECURSIVE_TOSTRING_TIMEOUT = 10 -- Range: [1, ∞[. High values may result in crashes on specially-crafted input.
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -98,6 +98,8 @@ local function largest_number_index (t)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function nr_elements_in_table (t)
|
local function nr_elements_in_table (t)
|
||||||
|
-- Determines the total number of elements in the table.
|
||||||
|
|
||||||
assert(type(t) == 'table')
|
assert(type(t) == 'table')
|
||||||
--
|
--
|
||||||
local k, count = nil, -1
|
local k, count = nil, -1
|
||||||
|
@ -108,16 +110,30 @@ local function nr_elements_in_table (t)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function nr_elements_in_seq (t)
|
local function nr_elements_in_seq (t)
|
||||||
|
-- Determines the number of elements in the sequence part of the table.
|
||||||
|
-- Allows holes of size `ALLOWED_HOLE_SIZE_IN_SEQUENCE`, before stopping.
|
||||||
|
-- This function works even when the given table's metamethods throws errors.
|
||||||
|
--
|
||||||
|
-- Returns:
|
||||||
|
-- * Number: number of elements
|
||||||
|
-- * Boolean: whether the table has holes.
|
||||||
|
|
||||||
assert(type(t) == 'table')
|
assert(type(t) == 'table')
|
||||||
|
|
||||||
if getmetatable(t) and getmetatable(t).__index then
|
-- We don't want to crash if the __index metamethod throws an error, so we
|
||||||
return 0, false -- FIXME: Temporary stopgap for when __index throws an
|
-- copy the pairs with number keys into a fresh table, which we then operate
|
||||||
-- error. I think we need to clone the numbers part of the table, to
|
-- on lower down.
|
||||||
-- fix this.
|
if debug.getmetatable(t) and debug.getmetatable(t).__index then
|
||||||
|
local t_prime = {}
|
||||||
|
for k, v in pairs(t) do
|
||||||
|
if type(k) == 'number' then t_prime[k] = v end
|
||||||
|
end
|
||||||
|
t = t_prime
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Now we run though the table, from 1 and up.
|
||||||
local i, last_elem_i, nr_elems, has_holes = 0, 0, 0, false
|
local i, last_elem_i, nr_elems, has_holes = 0, 0, 0, false
|
||||||
while i <= last_elem_i + 2 do
|
while i <= last_elem_i + 1 + ALLOWED_HOLE_SIZE_IN_SEQUENCE do
|
||||||
i = i + 1
|
i = i + 1
|
||||||
if t[i] ~= nil then
|
if t[i] ~= nil then
|
||||||
last_elem_i, nr_elems = i, nr_elems + 1
|
last_elem_i, nr_elems = i, nr_elems + 1
|
||||||
|
|
|
@ -229,6 +229,13 @@ SUITE:addTest('Can count elements, even though metatable.__index throws errors',
|
||||||
assert_equal(2, info[input].seq_elems)
|
assert_equal(2, info[input].seq_elems)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
SUITE:addTest('Can count elements, even though metatable.__index throws errors and __metatable returns bogus', function ()
|
||||||
|
local input = setmetatable({ 'hi', 'hello' }, {__index = function (_, k) error('Undefined access on key: '..k) end, __metatable = {}})
|
||||||
|
local info = analyze_structure(input, math.huge)
|
||||||
|
|
||||||
|
assert_equal(2, info[input].seq_elems)
|
||||||
|
end)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
-- Uniform structure
|
-- Uniform structure
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user