deepcopy.nim 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2015 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. type
  10. PtrTable = ptr object
  11. counter, max: int
  12. data: array[0xff_ffff, (pointer, pointer)]
  13. template hashPtr(key: pointer): int = cast[int](key) shr 8
  14. template allocPtrTable: untyped =
  15. cast[PtrTable](alloc0(sizeof(int)*2 + sizeof(pointer)*2*cap))
  16. proc rehash(t: PtrTable): PtrTable =
  17. let cap = (t.max+1) * 2
  18. result = allocPtrTable()
  19. result.counter = t.counter
  20. result.max = cap-1
  21. for i in 0..t.max:
  22. let k = t.data[i][0]
  23. if k != nil:
  24. var h = hashPtr(k)
  25. while result.data[h and result.max][0] != nil: inc h
  26. result.data[h and result.max] = t.data[i]
  27. dealloc t
  28. proc initPtrTable(): PtrTable =
  29. const cap = 32
  30. result = allocPtrTable()
  31. result.counter = 0
  32. result.max = cap-1
  33. template deinit(t: PtrTable) = dealloc(t)
  34. proc get(t: PtrTable; key: pointer): pointer =
  35. var h = hashPtr(key)
  36. while true:
  37. let k = t.data[h and t.max][0]
  38. if k == nil: break
  39. if k == key:
  40. return t.data[h and t.max][1]
  41. inc h
  42. proc put(t: var PtrTable; key, val: pointer) =
  43. if (t.max+1) * 2 < t.counter * 3: t = rehash(t)
  44. var h = hashPtr(key)
  45. while t.data[h and t.max][0] != nil: inc h
  46. t.data[h and t.max] = (key, val)
  47. inc t.counter
  48. proc genericDeepCopyAux(dest, src: pointer, mt: PNimType;
  49. tab: var PtrTable) {.benign.}
  50. proc genericDeepCopyAux(dest, src: pointer, n: ptr TNimNode;
  51. tab: var PtrTable) {.benign.} =
  52. var
  53. d = cast[ByteAddress](dest)
  54. s = cast[ByteAddress](src)
  55. case n.kind
  56. of nkSlot:
  57. genericDeepCopyAux(cast[pointer](d +% n.offset),
  58. cast[pointer](s +% n.offset), n.typ, tab)
  59. of nkList:
  60. for i in 0..n.len-1:
  61. genericDeepCopyAux(dest, src, n.sons[i], tab)
  62. of nkCase:
  63. var dd = selectBranch(dest, n)
  64. var m = selectBranch(src, n)
  65. # reset if different branches are in use; note different branches also
  66. # imply that's not self-assignment (``x = x``)!
  67. if m != dd and dd != nil:
  68. genericResetAux(dest, dd)
  69. copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
  70. n.typ.size)
  71. if m != nil:
  72. genericDeepCopyAux(dest, src, m, tab)
  73. of nkNone: sysAssert(false, "genericDeepCopyAux")
  74. proc genericDeepCopyAux(dest, src: pointer, mt: PNimType; tab: var PtrTable) =
  75. var
  76. d = cast[ByteAddress](dest)
  77. s = cast[ByteAddress](src)
  78. sysAssert(mt != nil, "genericDeepCopyAux 2")
  79. case mt.kind
  80. of tyString:
  81. var x = cast[PPointer](dest)
  82. var s2 = cast[PPointer](s)[]
  83. if s2 == nil:
  84. unsureAsgnRef(x, s2)
  85. else:
  86. unsureAsgnRef(x, copyDeepString(cast[NimString](s2)))
  87. of tySequence:
  88. var s2 = cast[PPointer](src)[]
  89. var seq = cast[PGenericSeq](s2)
  90. var x = cast[PPointer](dest)
  91. if s2 == nil:
  92. unsureAsgnRef(x, s2)
  93. return
  94. sysAssert(dest != nil, "genericDeepCopyAux 3")
  95. unsureAsgnRef(x, newSeq(mt, seq.len))
  96. var dst = cast[ByteAddress](cast[PPointer](dest)[])
  97. for i in 0..seq.len-1:
  98. genericDeepCopyAux(
  99. cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
  100. cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
  101. GenericSeqSize),
  102. mt.base, tab)
  103. of tyObject:
  104. # we need to copy m_type field for tyObject, as it could be empty for
  105. # sequence reallocations:
  106. if mt.base != nil:
  107. genericDeepCopyAux(dest, src, mt.base, tab)
  108. else:
  109. var pint = cast[ptr PNimType](dest)
  110. pint[] = cast[ptr PNimType](src)[]
  111. genericDeepCopyAux(dest, src, mt.node, tab)
  112. of tyTuple:
  113. genericDeepCopyAux(dest, src, mt.node, tab)
  114. of tyArray, tyArrayConstr:
  115. for i in 0..(mt.size div mt.base.size)-1:
  116. genericDeepCopyAux(cast[pointer](d +% i *% mt.base.size),
  117. cast[pointer](s +% i *% mt.base.size), mt.base, tab)
  118. of tyRef, tyOptAsRef:
  119. let s2 = cast[PPointer](src)[]
  120. if s2 == nil:
  121. unsureAsgnRef(cast[PPointer](dest), s2)
  122. elif mt.base.deepcopy != nil:
  123. let z = mt.base.deepcopy(s2)
  124. unsureAsgnRef(cast[PPointer](dest), z)
  125. else:
  126. let z = tab.get(s2)
  127. if z == nil:
  128. when declared(usrToCell):
  129. let x = usrToCell(s2)
  130. let realType = x.typ
  131. let z = newObj(realType, realType.base.size)
  132. unsureAsgnRef(cast[PPointer](dest), z)
  133. tab.put(s2, z)
  134. genericDeepCopyAux(z, s2, realType.base, tab)
  135. else:
  136. when false:
  137. # addition check disabled
  138. let x = usrToCell(s2)
  139. let realType = x.typ
  140. sysAssert realType == mt, " types do differ"
  141. # this version should work for any possible GC:
  142. let typ = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[] else: mt.base
  143. let z = newObj(mt, typ.size)
  144. unsureAsgnRef(cast[PPointer](dest), z)
  145. tab.put(s2, z)
  146. genericDeepCopyAux(z, s2, typ, tab)
  147. else:
  148. unsureAsgnRef(cast[PPointer](dest), z)
  149. of tyPtr:
  150. # no cycle check here, but also not really required
  151. let s2 = cast[PPointer](src)[]
  152. if s2 != nil and mt.base.deepcopy != nil:
  153. cast[PPointer](dest)[] = mt.base.deepcopy(s2)
  154. else:
  155. cast[PPointer](dest)[] = s2
  156. else:
  157. copyMem(dest, src, mt.size)
  158. proc genericDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
  159. GC_disable()
  160. var tab = initPtrTable()
  161. genericDeepCopyAux(dest, src, mt, tab)
  162. deinit tab
  163. GC_enable()
  164. proc genericSeqDeepCopy(dest, src: pointer, mt: PNimType) {.compilerProc.} =
  165. # also invoked for 'string'
  166. var src = src
  167. genericDeepCopy(dest, addr(src), mt)
  168. proc genericDeepCopyOpenArray(dest, src: pointer, len: int,
  169. mt: PNimType) {.compilerproc.} =
  170. var
  171. d = cast[ByteAddress](dest)
  172. s = cast[ByteAddress](src)
  173. for i in 0..len-1:
  174. genericDeepCopy(cast[pointer](d +% i *% mt.base.size),
  175. cast[pointer](s +% i *% mt.base.size), mt.base)