mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Add table.copy_with_metatables (#15754)
				
					
				
			This commit is contained in:
		@@ -22,7 +22,7 @@ read_globals = {
 | 
			
		||||
	"PerlinNoise", "PerlinNoiseMap",
 | 
			
		||||
 | 
			
		||||
	string = {fields = {"split", "trim"}},
 | 
			
		||||
	table  = {fields = {"copy", "getn", "indexof", "keyof", "insert_all"}},
 | 
			
		||||
	table  = {fields = {"copy", "copy_with_metatables", "getn", "indexof", "keyof", "insert_all"}},
 | 
			
		||||
	math   = {fields = {"hypot", "round"}},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -457,18 +457,37 @@ do
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
--------------------------------------------------------------------------------
 | 
			
		||||
function table.copy(t, seen)
 | 
			
		||||
	local n = {}
 | 
			
		||||
	seen = seen or {}
 | 
			
		||||
	seen[t] = n
 | 
			
		||||
	for k, v in pairs(t) do
 | 
			
		||||
		n[(type(k) == "table" and (seen[k] or table.copy(k, seen))) or k] =
 | 
			
		||||
			(type(v) == "table" and (seen[v] or table.copy(v, seen))) or v
 | 
			
		||||
 | 
			
		||||
local function table_copy(value, preserve_metatables)
 | 
			
		||||
	local seen = {}
 | 
			
		||||
	local function copy(val)
 | 
			
		||||
		if type(val) ~= "table" then
 | 
			
		||||
			return val
 | 
			
		||||
		end
 | 
			
		||||
		local t = val
 | 
			
		||||
		if seen[t] then
 | 
			
		||||
			return seen[t]
 | 
			
		||||
		end
 | 
			
		||||
		local res = {}
 | 
			
		||||
		seen[t] = res
 | 
			
		||||
		for k, v in pairs(t) do
 | 
			
		||||
			res[copy(k)] = copy(v)
 | 
			
		||||
		end
 | 
			
		||||
		if preserve_metatables then
 | 
			
		||||
			setmetatable(res, getmetatable(t))
 | 
			
		||||
		end
 | 
			
		||||
		return res
 | 
			
		||||
	end
 | 
			
		||||
	return n
 | 
			
		||||
	return copy(value)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function table.copy(value)
 | 
			
		||||
	return table_copy(value, false)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function table.copy_with_metatables(value)
 | 
			
		||||
	return table_copy(value, true)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
function table.insert_all(t, other)
 | 
			
		||||
	if table.move then -- LuaJIT
 | 
			
		||||
 
 | 
			
		||||
@@ -178,6 +178,35 @@ describe("table", function()
 | 
			
		||||
		assert.equal(2, table.keyof({[2] = "foo", [3] = "bar"}, "foo"))
 | 
			
		||||
		assert.equal(3, table.keyof({[1] = "foo", [3] = "bar"}, "bar"))
 | 
			
		||||
	end)
 | 
			
		||||
 | 
			
		||||
	describe("copy()", function()
 | 
			
		||||
		it("strips metatables", function()
 | 
			
		||||
			local v = vector.new(1, 2, 3)
 | 
			
		||||
			local w = table.copy(v)
 | 
			
		||||
			assert.are_not.equal(v, w)
 | 
			
		||||
			assert.same(v, w)
 | 
			
		||||
			assert.equal(nil, getmetatable(w))
 | 
			
		||||
		end)
 | 
			
		||||
		it("preserves referential structure", function()
 | 
			
		||||
			local t = {{}, {}}
 | 
			
		||||
			t[1][1] = t[2]
 | 
			
		||||
			t[2][1] = t[1]
 | 
			
		||||
			local copy = table.copy(t)
 | 
			
		||||
			assert.same(t, copy)
 | 
			
		||||
			assert.equal(copy[1][1], copy[2])
 | 
			
		||||
			assert.equal(copy[2][1], copy[1])
 | 
			
		||||
		end)
 | 
			
		||||
	end)
 | 
			
		||||
 | 
			
		||||
	describe("copy_with_metatables()", function()
 | 
			
		||||
		it("preserves metatables", function()
 | 
			
		||||
			local v = vector.new(1, 2, 3)
 | 
			
		||||
			local w = table.copy_with_metatables(v)
 | 
			
		||||
			assert.equal(getmetatable(v), getmetatable(w))
 | 
			
		||||
			assert(vector.check(w))
 | 
			
		||||
			assert.equal(v, w) -- vector overrides ==
 | 
			
		||||
		end)
 | 
			
		||||
	end)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
describe("formspec_escape", function()
 | 
			
		||||
 
 | 
			
		||||
@@ -4142,6 +4142,11 @@ Helper functions
 | 
			
		||||
    * returns time with microsecond precision. May not return wall time.
 | 
			
		||||
* `table.copy(table)`: returns a table
 | 
			
		||||
    * returns a deep copy of `table`
 | 
			
		||||
    * strips metatables, but this may change in the future
 | 
			
		||||
* `table.copy_with_metatables(table)`
 | 
			
		||||
    * since 5.12
 | 
			
		||||
    * `table` can also be non-table value, which will be returned as-is
 | 
			
		||||
    * preserves metatables as they are
 | 
			
		||||
* `table.indexof(list, val)`: returns the smallest numerical index containing
 | 
			
		||||
      the value `val` in the table `list`. Non-numerical indices are ignored.
 | 
			
		||||
      If `val` could not be found, `-1` is returned. `list` must not have
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user