Deepcopy of table

I have a table with params.Params can be vector3/vector4/url/hashes. I need to make a deepcopy of that table. How can i do that? The problem that i don’t know what type of userdata i coping. I tried check fields with pcall but it is not helped.
I can make a map with keys and types. But maybe there are others ways.
Table

return {
	go_fun = "create_go_sprite_main",
	z = 0.2,
	scale = SCALE,
	sprite = hash("asteroid1"),
	speed = 1000,
	rect_size = vmath.vector3(300, 300, 0),
	removable = true,
	mask = MASK.ENEMY_MASK,
	group = MASK.ENEMY,
	cg = {
		{type = "rect", x = 0, y = 0, w = 250, h = 250},
		{type = "circle", x = 0, y = 0, r = 125}
	}
}
local function deepcopy(orig)
	local orig_type = type(orig)
	local copy
	if orig_type == 'table' then
		copy = {}
		for k, v in pairs(orig) do
			copy[k] = deepcopy(v)
		end
	elseif orig_type == "userdata" then
		print("here1")
		if pcall(orig.w) then
			copy = vmath.vector4()
		elseif pcall(orig.x) then
			copy = vmath.vector3(orig)
		else
			assert(nil, "unknown user data")
			print(orig)
		end
		print("here2")
	else -- number, string, boolean, etc
		copy = orig
	end
	return copy
end

Does this help, or any of the other answers?

1 Like

No. This will not copy vector. It will copy link to vector. I need a copy.

Well, the type() function will return “userdata” for matrix, vector3, vector4 and quaternion types so that’s no help. I guess you could perhaps do some checks to figure things out:

if type(foobar) == "userdata" and not foobar.w then
    print("This could be a vector3")
end

pcall() will not work like that. pcall() expects a function (you passed another value type) to invoke and it returns if the function invocation was successful or not, as well as any return values from the function call.

I had an idea for a project to encode/decode complex data structures, based on some kind of data model descriptions. It could be extended to also deep-copy data structures. I’ve never announced it before, but I’m leaving it here for inspiration: https://github.com/britzl/desert

2 Likes

i get error when try to get vector.w for vector3. So i try to check in pcall.

Yes my mistake.=)

I know keys and types so I make a map key->fun to make a copy.

local KEY_TYPE_MAP = {
	spine = same,
	sprite = same,
	sprite = msg.url,
	spine = msg.url,
	pos2d = vmath.vector3,
	vel = vmath.vector3,
	loop_start_pos = vmath.vector3,
	loop_end_pos = vmath.vector3,
	move_point = vmath.vector3,
	rect_size = vmath.vector3,
}
2 Likes

I was working on pretty much exactly this problem. As of 1.2.188 the functions sys.serialize() and sys.deserialize() provide a very convenient solution.

See below where I duplicate the “original” table and modify both a subtable and a vector3. As you can see when pprinting both tables, table “duplicate” contains copies, not refs. Thanks @JCash for the suggestion.

	local original = {a = "string", b = {1,2,3}, c = vmath.vector3(4,5,6), d = hash("hash")}

	local duplicate = sys.serialize(original)
	duplicate = sys.deserialize(duplicate)

	duplicate.b[2] = 7

	duplicate.c.y = 8

	pprint(duplicate)
	pprint(original)
8 Likes