1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206
|
#
#
# Nim's Runtime Library
# (c) Copyright 2015 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
const
TableSize = when sizeof(int) <= 2: 0xff else: 0xff_ffff
type
PtrTable = ptr object
counter, max: int
data: array[TableSize, (pointer, pointer)]
template hashPtr(key: pointer): int = cast[int](key) shr 8
template allocPtrTable: untyped =
cast[PtrTable](alloc0(sizeof(int)*2 + sizeof(pointer)*2*cap))
proc rehash(t: PtrTable): PtrTable =
let cap = (t.max+1) * 2
result = allocPtrTable()
result.counter = t.counter
result.max = cap-1
for i in 0..t.max:
let k = t.data[i][0]
if k != nil:
var h = hashPtr(k)
while result.data[h and result.max][0] != nil: inc h
result.data[h and result.max] = t.data[i]
dealloc t
proc initPtrTable(): PtrTable =
const cap = 32
result = allocPtrTable()
result.counter = 0
result.max = cap-1
template deinit(t: PtrTable) = dealloc(t)
proc get(t: PtrTable; key: pointer): pointer =
var h = hashPtr(key)
while true:
let k = t.data[h and t.max][0]
if k == nil: break
if k == key:
return t.data[h and t.max][1]
inc h
proc put(t: var PtrTable; key, val: pointer) =
if (t.max+1) * 2 < t.counter * 3: t = rehash(t)
var h = hashPtr(key)
while t.data[h and t.max][0] != nil: inc h
t.data[h and t.max] = (key, val)
inc t.counter
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType;
tab: var PtrTable) {.benign.}
proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode;
tab: var PtrTable) {.benign.} =
var
d = cast[int](dest)
s = cast[int](src)
case n.kind
of nkSlot:
genericDeepCopyAux(cast[pointer](d +% n.offset),
cast[pointer](s +% n.offset), n.typ, tab)
of nkList:
for i in 0..n.len-1:
genericDeepCopyAux(dest, src, n.sons[i], tab)
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, tab)
of nkNone: sysAssert(false, "genericDeepCopyAux")
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
var
d = cast[int](dest)
s = cast[int](src)
sysAssert(mt != nil, "genericDeepCopyAux 2")
case mt.kind
of tyString:
when defined(nimSeqsV2):
var x = cast[ptr NimStringV2](dest)
var s2 = cast[ptr NimStringV2](s)[]
nimAsgnStrV2(x[], s2)
else:
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:
when defined(nimSeqsV2):
deepSeqAssignImpl(genericDeepCopyAux, tab)
else:
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[int](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericDeepCopyAux(
cast[pointer](dst +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
cast[pointer](cast[int](s2) +% align(GenericSeqSize, mt.base.align) +% i *% mt.base.size),
mt.base, tab)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
if mt.base != nil:
genericDeepCopyAux(dest, src, mt.base, tab)
else:
var pint = cast[ptr PNimType](dest)
pint[] = cast[ptr PNimType](src)[]
genericDeepCopyAux(dest, src, mt.node, tab)
of tyTuple:
genericDeepCopyAux(dest, src, mt.node, tab)
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, tab)
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)
when defined(nimSeqsV2):
cast[PPointer](dest)[] = z
else:
unsureAsgnRef(cast[PPointer](dest), z)
else:
let z = tab.get(s2)
if z == nil:
when declared(usrToCell):
let x = usrToCell(s2)
let realType = x.typ
let z = newObj(realType, realType.base.size)
unsureAsgnRef(cast[PPointer](dest), z)
tab.put(s2, z)
genericDeepCopyAux(z, s2, realType.base, tab)
else:
when false:
# addition check disabled
let x = usrToCell(s2)
let realType = x.typ
sysAssert realType == mt, " types do differ"
when defined(nimSeqsV2):
let typ = if mt.base.kind == tyObject: cast[PNimType](cast[ptr PNimTypeV2](s2)[].typeInfoV1)
else: mt.base
let z = nimNewObj(typ.size, typ.align)
cast[PPointer](dest)[] = z
else:
# this version should work for any other GC:
let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base
let z = newObj(mt, typ.size)
unsureAsgnRef(cast[PPointer](dest), z)
tab.put(s2, z)
genericDeepCopyAux(z, s2, typ, tab)
else:
unsureAsgnRef(cast[PPointer](dest), z)
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.} =
when not defined(nimSeqsV2): GC_disable()
var tab = initPtrTable()
genericDeepCopyAux(dest, src, mt, tab)
deinit tab
when not defined(nimSeqsV2): GC_enable()
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[int](dest)
s = cast[int](src)
for i in 0..len-1:
genericDeepCopy(cast[pointer](d +% i *% mt.base.size),
cast[pointer](s +% i *% mt.base.size), mt.base)
|