deepcopy.nim 6.0 KB

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