Skip to content
Snippets Groups Projects
Commit 0afe1f78 authored by Serge Petrenko's avatar Serge Petrenko Committed by Kirill Yukhin
Browse files

lua: introduce table.equals method

Introduce table.equals for comparing tables.
The method respects __eq metamethod, if provided.

Needed-for #5894

@TarantoolBot document
Title: lua: new method table.equals

Document the new lua method table.equals
It compares two tables deeply. For example:
```
tarantool> t1 = {a=3}
---
...

tarantool> t2 = {a=3}
---
...

tarantool> t1 == t2
---
- false
...

tarantool> table.equals(t1, t2)
---
- true
...
```
The method respects the __eq metamethod. When both tables being compared
have the same __eq metamethod, it's used for comparison (just like this
is done in Lua 5.1)
parent fc3e6986
No related branches found
No related tags found
No related merge requests found
## feature/lua
* Introduce method `table.equals`. It compares 2 tables by value and respects
`__eq` metamethod.
......@@ -57,6 +57,34 @@ local function table_shallowcopy(orig)
return copy
end
--- Compare two lua tables
-- Supports __eq metamethod for comparing custom tables with metatables
-- @function equals
-- @return true when the two tables are equal (false otherwise).
local function table_equals(a, b)
if type(a) ~= 'table' or type(b) ~= 'table' then
return type(a) == type(b) and a == b
end
local mta = getmetatable(a)
local mtb = getmetatable(b)
-- Let Lua decide what should happen when at least one of the tables has a
-- metatable.
if mta and mta.__eq or mtb and mtb.__eq then
return a == b
end
for k, v in pairs(a) do
if not table_equals(v, b[k]) then
return false
end
end
for k, _ in pairs(b) do
if not a[k] then
return false
end
end
return true
end
-- table library extension
local table = require('table')
-- require modifies global "table" module and adds "clear" function to it.
......@@ -65,3 +93,4 @@ require('table.clear')
table.copy = table_shallowcopy
table.deepcopy = table_deepcopy
table.equals = table_equals
......@@ -8,7 +8,7 @@ yaml.cfg{
encode_invalid_as_nil = true,
}
local test = require('tap').test('table')
test:plan(31)
test:plan(44)
do -- check basic table.copy (deepcopy)
local example_table = {
......@@ -223,4 +223,51 @@ do -- check usage of not __copy metamethod on second level + shallow
)
end
do -- check table.equals
test:ok(table.equals({}, {}), "table.equals for empty tables")
test:is(table.equals({}, {1}), false, "table.equals with one empty table")
test:is(table.equals({1}, {}), false, "table.equals with one empty table")
test:is(table.equals({key = box.NULL}, {key = nil}), false,
"table.equals for box.NULL and nil")
test:is(table.equals({key = nil}, {key = box.NULL}), false,
"table.equals for box.NULL and nil")
local tbl_a = {
first = {
1,
2,
{},
},
second = {
a = {
{'something'},
},
b = 'something else',
},
[3] = 'some value',
}
local tbl_b = table.deepcopy(tbl_a)
local tbl_c = table.copy(tbl_a)
test:ok(table.equals(tbl_a, tbl_b), "table.equals for complex tables")
test:ok(table.equals(tbl_a, tbl_c),
"table.equals for shallow copied tables")
tbl_c.second.a = 'other thing'
test:ok(table.equals(tbl_a, tbl_c),
"table.equals for shallow copied tables after modification")
test:is(table.equals(tbl_a, tbl_b), false, "table.equals does a deep check")
local mt = {
__eq = function(a, b) -- luacheck: no unused args
return true
end}
local tbl_d = setmetatable({a = 15}, mt)
local tbl_e = setmetatable({b = 2, c = 3}, mt)
test:ok(table.equals(tbl_d, tbl_e), "table.equals respects __eq")
test:is(table.equals(tbl_d, {a = 15}), false,
"table.equals when metatables don't match")
test:is(table.equals({a = 15}, tbl_d), false,
"table.equals when metatables don't match")
local tbl_f = setmetatable({a = 15}, {__eq = function() return true end})
test:is(table.equals(tbl_d, tbl_f), false,
"table.equals when metatables don't match")
end
os.exit(test:check() == true and 0 or 1)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment