Open
Description
Summary
Hello,
I propose a deepcopy implementation using a fieldPairs iterators. It seems to work for all types and is 3 times quicker than the actual one. It has not been tested on cyclic data structures.
Here is the code below :
proc deepCopyImpl[T](dest: var T; src: T) =
when typeof(src) is ref or typeof(src) is ptr:
if src != nil:
dest = T()
dest[] = src[]
deepCopyImpl(dest[], src[])
elif typeof(src) is object:
for _, v1, v2 in fieldPairs(dest, src):
deepCopyImpl(v1, v2)
proc deepCopy*[T](dest: var T; src: T) =
## This procedure copies values and create new object for references
## Also copies pointers, so unmanaged memory is unsafe if pointer is not wrapped into an object with a destructor
# Should behave exactly like system.deepCopy
dest = src
deepCopyImpl(dest, src)
Here is also the code for a deepEqual checking implementation :
func deepEqual*[T](a, b: T): bool =
## Check values recursively
## Ignore References/adresse inequality
result = true
when typeof(a) is ref or typeof(a) is ptr:
if a != nil and b != nil:
result = deepEqual(a[], b[])
else:
result = a == b
if result == false:
return
elif typeof(a) is object:
for name, v1, v2 in fieldPairs(a, b):
result = deepEqual(v1, v2)
if result == false:
return
else:
result = a == b
Here are some unittests :
import mylib/Testing
testing():
import strtabs, std/with
type
MyProc = ref object
pid: int
alive: bool
data: string
MyTerminal = object
size: int
data: string
process: MyProc
ShellOptions = enum
QuoteArgs, MergeStderr
Shell = ref object
cmd: string
args: seq[string]
options: set[ShellOptions]
env: StringTableRef
process: MyProc
terminal: MyTerminal
nilval1: pointer
nilval2: MyProc
var s1 = Shell()
with s1:
cmd = "ls"
args = @["-l", "-a"]
options = {MergeStderr}
env = newStringTable()
process = MyProc()
with process:
pid = 10
alive = true
data = "This is running"
with terminal:
size = 1000
data = "youpi"
process = MyProc()
with process:
pid = 9
alive = true
data = "Have a terminal"
s1.env["SHELL"] = "/bin/bash"
proc assertions()
var s2: Shell
## System.deepCopy is commented
#[
runTest("system.deepCopy"):
s2 = Shell()
system.deepCopy(s2, s1)
assertions()
runBench("system.deepCopy", 1):
s2 = Shell()
system.deepCopy(s2, s1)
]#
runTest("proposal.deepCopy"):
s2 = Shell()
deepCopy(s2, s1)
assertions()
runBench("proposal.deepCopy", 1):
s2 = Shell()
deepCopy(s2, s1)
proc assertions() =
doAssert deepEqual(s2, s1), "Expected s1 deeply equal s2"
doAssert deepEqual(s1, s2), "Expected s2 deeply equal s1"
doAssert s2.cmd == s1.cmd, "Field must be same"
doAssert s2.args == s1.args, "Field must be same"
doAssert s2.options == s1.options, "Field must be same"
doAssert $(s2.env) == $(s1.env), "Field must be same"
doAssert s2.process.pid == s1.process.pid, "Field must be same"
doAssert s2.terminal.process.pid == s1.terminal.process.pid, "Field must be same"
doAssert s2.nilval1 == s1.nilval1, "Undefined ref must be nil"
doAssert s2.nilval2 == s1.nilval2, "Undefined ref must be nil"
# Inequality checks
doAssert s2 != s1, "Refs must be different"
doAssert s2.terminal != s1.terminal, "Must be different because one field is ref"
doAssert s2.terminal.process != s1.terminal.process, "Refs must be different"
s2.terminal.process.pid = 10
doAssert not deepEqual(s2, s1), "Expected s1 no longer equal s2"
s2.cmd = "changed"
doAssert s2.cmd != s1.cmd, "Field must not be same"
s2.args.add("myfile")
doAssert s2.args != s1.args, "Field must not be same"
s2.options.incl(QuoteArgs)
doAssert s2.options != s1.options, "Field must not be same"
s2.env["field"] = "changed"
doAssert $(s2.env) != $(s1.env), "Field must not be same"
s2.process.pid = 53
doAssert s2.process.pid != s1.process.pid, "Field not must be same"
s2.terminal.size = 30
doAssert s2.terminal != s1.terminal, "Field must not be same"
s2.terminal.process.pid = 87
doAssert s2.terminal.process.pid != s1.terminal.process.pid, "Field must not be same"
Description
The actual deepcopy implementation is slow and require a supplementary compile flag.
Alternatives
No response
Examples
No response
Backwards Compatibility
No response
Links
No response