#
#
# Nim's Runtime Library
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) {.benign.}
proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode) {.benign.} =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
case n.kind
of nkSlot:
genericDeepCopyAux(cast[pointer](d +% n.offset),
cast[pointer](s +% n.offset), n.typ)
of nkList:
for i in 0..n.len-1:
genericDeepCopyAux(dest, src, n.sons[i])
of nkCase:
var dd = selectBranch(dest, n)
var m = selectBranch(src, n)
# reset if different branches are in use; note different branches also
# imply that's not self-assignment (``x = x``)!
if m != dd and dd != nil:
genericResetAux(dest, dd)
copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
n.typ.size)
if m != nil:
genericDeepCopyAux(dest, src, m)
of nkNone: sysAssert(false, "genericDeepCopyAux")
proc copyDeepString(src: NimString): NimString {.inline.} =
if src != nil:
result = rawNewStringNoInit(src.len)
result.len = src.len
c_memcpy(result.data, src.data, src.len + 1)
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind
of tyString:
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil:
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
of tySequence:
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[PPointer](dest)
if s2 == nil:
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericDeepCopyAux 3")
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[ByteAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
mt.base)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[]
if mt.base != nil:
genericDeepCopyAux(dest, src, mt.base)
genericDeepCopyAux(dest, src, mt.node)
of tyTuple:
genericDeepCopyAux(dest, src, mt.node)
of tyArray, tyArrayConstr:
for i in 0..(mt.size div mt.base.size)-1:
genericDeepCopyAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base)
of tyRef:
let s2 = cast[PPointer](src)[]
if s2 == nil:
unsureAsgnRef(cast[PPointer](dest), s2)
elif mt.base.deepcopy != nil:
let z = mt.base.deepcopy(s2)
unsureAsgnRef(cast[PPointer](dest), z)
else:
# we modify the header of the cell temporarily; instead of the type
# field we store a forwarding pointer. XXX This is bad when the cloning
# fails due to OOM etc.
when declared(usrToCell):
# unfortunately we only have cycle detection for our native GCs.
let x = usrToCell(s2)
let forw = cast[int](x.typ)
if (forw and 1) == 1:
# we stored a forwarding pointer, so let's use that:
let z = cast[pointer](forw and not 1)
unsureAsgnRef(cast[PPointer](dest), z)
else:
let realType = x.typ
let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z)
x.typ = cast[PNimType](cast[int](z) or 1)
genericDeepCopyAux(z, s2, realType.base)
x.typ = realType
else:
let realType = mt
let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z)
genericDeepCopyAux(z, s2, realType.base)
of tyPtr:
# no cycle check here, but also not really required
let s2 = cast[PPointer](src)[]
if s2 != nil and mt.base.deepcopy != nil:
cast[PPointer](dest)[] = mt.base.deepcopy(s2)
else:
cast[PPointer](dest)[] = s2
else:
copyMem(dest, src, mt.size)
proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
genericDeepCopyAux(dest, src, mt)
proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
# also invoked for 'string'
var src = src
genericDeepCopy(dest, addr(src), mt)
proc genericDeepCopyOpenArray(dest, src: pointer, len: int,
mt: PNimType) {.compilerproc.} =
var
d = cast[ByteAddress](dest)
s = cast[ByteAddress](src)
for i in 0..len-1:
genericDeepCopy(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base)