assign.nim 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2012 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. proc genericResetAux(dest: pointer, n: ptr TNimNode) {.benign.}
  10. proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) {.benign.}
  11. proc genericAssignAux(dest, src: pointer, n: ptr TNimNode,
  12. shallow: bool) {.benign.} =
  13. var
  14. d = cast[ByteAddress](dest)
  15. s = cast[ByteAddress](src)
  16. case n.kind
  17. of nkSlot:
  18. genericAssignAux(cast[pointer](d +% n.offset),
  19. cast[pointer](s +% n.offset), n.typ, shallow)
  20. of nkList:
  21. for i in 0..n.len-1:
  22. genericAssignAux(dest, src, n.sons[i], shallow)
  23. of nkCase:
  24. var dd = selectBranch(dest, n)
  25. var m = selectBranch(src, n)
  26. # reset if different branches are in use; note different branches also
  27. # imply that's not self-assignment (``x = x``)!
  28. if m != dd and dd != nil:
  29. genericResetAux(dest, dd)
  30. copyMem(cast[pointer](d +% n.offset), cast[pointer](s +% n.offset),
  31. n.typ.size)
  32. if m != nil:
  33. genericAssignAux(dest, src, m, shallow)
  34. of nkNone: sysAssert(false, "genericAssignAux")
  35. #else:
  36. # echo "ugh memory corruption! ", n.kind
  37. # quit 1
  38. proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
  39. var
  40. d = cast[ByteAddress](dest)
  41. s = cast[ByteAddress](src)
  42. sysAssert(mt != nil, "genericAssignAux 2")
  43. case mt.kind
  44. of tyString:
  45. var x = cast[PPointer](dest)
  46. var s2 = cast[PPointer](s)[]
  47. if s2 == nil or shallow or (
  48. cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
  49. unsureAsgnRef(x, s2)
  50. else:
  51. unsureAsgnRef(x, copyString(cast[NimString](s2)))
  52. of tySequence:
  53. var s2 = cast[PPointer](src)[]
  54. var seq = cast[PGenericSeq](s2)
  55. var x = cast[PPointer](dest)
  56. if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
  57. # this can happen! nil sequences are allowed
  58. unsureAsgnRef(x, s2)
  59. return
  60. sysAssert(dest != nil, "genericAssignAux 3")
  61. if ntfNoRefs in mt.base.flags:
  62. var ss = nimNewSeqOfCap(mt, seq.len)
  63. cast[PGenericSeq](ss).len = seq.len
  64. unsureAsgnRef(x, ss)
  65. var dst = cast[ByteAddress](cast[PPointer](dest)[])
  66. copyMem(cast[pointer](dst +% GenericSeqSize),
  67. cast[pointer](cast[ByteAddress](s2) +% GenericSeqSize),
  68. seq.len * mt.base.size)
  69. else:
  70. unsureAsgnRef(x, newSeq(mt, seq.len))
  71. var dst = cast[ByteAddress](cast[PPointer](dest)[])
  72. for i in 0..seq.len-1:
  73. genericAssignAux(
  74. cast[pointer](dst +% i *% mt.base.size +% GenericSeqSize),
  75. cast[pointer](cast[ByteAddress](s2) +% i *% mt.base.size +%
  76. GenericSeqSize),
  77. mt.base, shallow)
  78. of tyObject:
  79. var it = mt.base
  80. # don't use recursion here on the PNimType because the subtype
  81. # check should only be done at the very end:
  82. while it != nil:
  83. genericAssignAux(dest, src, it.node, shallow)
  84. it = it.base
  85. genericAssignAux(dest, src, mt.node, shallow)
  86. # we need to copy m_type field for tyObject, as it could be empty for
  87. # sequence reallocations:
  88. var pint = cast[ptr PNimType](dest)
  89. # We need to copy the *static* type not the dynamic type:
  90. # if p of TB:
  91. # var tbObj = TB(p)
  92. # tbObj of TC # needs to be false!
  93. #c_fprintf(stdout, "%s %s\n", pint[].name, mt.name)
  94. chckObjAsgn(cast[ptr PNimType](src)[], mt)
  95. pint[] = mt # cast[ptr PNimType](src)[]
  96. of tyTuple:
  97. genericAssignAux(dest, src, mt.node, shallow)
  98. of tyArray, tyArrayConstr:
  99. for i in 0..(mt.size div mt.base.size)-1:
  100. genericAssignAux(cast[pointer](d +% i *% mt.base.size),
  101. cast[pointer](s +% i *% mt.base.size), mt.base, shallow)
  102. of tyRef:
  103. unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
  104. of tyOptAsRef:
  105. let s2 = cast[PPointer](src)[]
  106. let d = cast[PPointer](dest)
  107. if s2 == nil:
  108. unsureAsgnRef(d, s2)
  109. else:
  110. when declared(usrToCell):
  111. let realType = usrToCell(s2).typ
  112. else:
  113. let realType = if mt.base.kind == tyObject: cast[ptr PNimType](s2)[]
  114. else: mt.base
  115. var z = newObj(realType, realType.base.size)
  116. genericAssignAux(d, addr z, mt.base, shallow)
  117. else:
  118. copyMem(dest, src, mt.size) # copy raw bits
  119. proc genericAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
  120. genericAssignAux(dest, src, mt, false)
  121. proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
  122. genericAssignAux(dest, src, mt, true)
  123. when false:
  124. proc debugNimType(t: PNimType) =
  125. if t.isNil:
  126. cprintf("nil!")
  127. return
  128. var k: cstring
  129. case t.kind
  130. of tyBool: k = "bool"
  131. of tyChar: k = "char"
  132. of tyEnum: k = "enum"
  133. of tyArray: k = "array"
  134. of tyObject: k = "object"
  135. of tyTuple: k = "tuple"
  136. of tyRange: k = "range"
  137. of tyPtr: k = "ptr"
  138. of tyRef: k = "ref"
  139. of tyVar: k = "var"
  140. of tyOptAsRef: k = "optref"
  141. of tySequence: k = "seq"
  142. of tyProc: k = "proc"
  143. of tyPointer: k = "range"
  144. of tyOpenArray: k = "openarray"
  145. of tyString: k = "string"
  146. of tyCString: k = "cstring"
  147. of tyInt: k = "int"
  148. of tyInt32: k = "int32"
  149. else: k = "other"
  150. cprintf("%s %ld\n", k, t.size)
  151. debugNimType(t.base)
  152. proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
  153. var src = src # ugly, but I like to stress the parser sometimes :-)
  154. genericAssign(dest, addr(src), mt)
  155. proc genericAssignOpenArray(dest, src: pointer, len: int,
  156. mt: PNimType) {.compilerproc.} =
  157. var
  158. d = cast[ByteAddress](dest)
  159. s = cast[ByteAddress](src)
  160. for i in 0..len-1:
  161. genericAssign(cast[pointer](d +% i *% mt.base.size),
  162. cast[pointer](s +% i *% mt.base.size), mt.base)
  163. proc objectInit(dest: pointer, typ: PNimType) {.compilerProc, benign.}
  164. proc objectInitAux(dest: pointer, n: ptr TNimNode) {.benign.} =
  165. var d = cast[ByteAddress](dest)
  166. case n.kind
  167. of nkNone: sysAssert(false, "objectInitAux")
  168. of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ)
  169. of nkList:
  170. for i in 0..n.len-1:
  171. objectInitAux(dest, n.sons[i])
  172. of nkCase:
  173. var m = selectBranch(dest, n)
  174. if m != nil: objectInitAux(dest, m)
  175. proc objectInit(dest: pointer, typ: PNimType) =
  176. # the generic init proc that takes care of initialization of complex
  177. # objects on the stack or heap
  178. var d = cast[ByteAddress](dest)
  179. case typ.kind
  180. of tyObject:
  181. # iterate over any structural type
  182. # here we have to init the type field:
  183. var pint = cast[ptr PNimType](dest)
  184. pint[] = typ
  185. objectInitAux(dest, typ.node)
  186. of tyTuple:
  187. objectInitAux(dest, typ.node)
  188. of tyArray, tyArrayConstr:
  189. for i in 0..(typ.size div typ.base.size)-1:
  190. objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
  191. else: discard # nothing to do
  192. # ---------------------- assign zero -----------------------------------------
  193. proc genericReset(dest: pointer, mt: PNimType) {.compilerProc, benign.}
  194. proc genericResetAux(dest: pointer, n: ptr TNimNode) =
  195. var d = cast[ByteAddress](dest)
  196. case n.kind
  197. of nkNone: sysAssert(false, "genericResetAux")
  198. of nkSlot: genericReset(cast[pointer](d +% n.offset), n.typ)
  199. of nkList:
  200. for i in 0..n.len-1: genericResetAux(dest, n.sons[i])
  201. of nkCase:
  202. var m = selectBranch(dest, n)
  203. if m != nil: genericResetAux(dest, m)
  204. zeroMem(cast[pointer](d +% n.offset), n.typ.size)
  205. proc genericReset(dest: pointer, mt: PNimType) =
  206. var d = cast[ByteAddress](dest)
  207. sysAssert(mt != nil, "genericReset 2")
  208. case mt.kind
  209. of tyString, tyRef, tyOptAsRef, tySequence:
  210. unsureAsgnRef(cast[PPointer](dest), nil)
  211. of tyTuple:
  212. genericResetAux(dest, mt.node)
  213. of tyObject:
  214. genericResetAux(dest, mt.node)
  215. # also reset the type field for tyObject, for correct branch switching!
  216. var pint = cast[ptr PNimType](dest)
  217. pint[] = nil
  218. of tyArray, tyArrayConstr:
  219. for i in 0..(mt.size div mt.base.size)-1:
  220. genericReset(cast[pointer](d +% i *% mt.base.size), mt.base)
  221. else:
  222. zeroMem(dest, mt.size) # set raw bits to zero
  223. proc selectBranch(discVal, L: int,
  224. a: ptr array[0x7fff, ptr TNimNode]): ptr TNimNode =
  225. result = a[L] # a[L] contains the ``else`` part (but may be nil)
  226. if discVal <% L:
  227. var x = a[discVal]
  228. if x != nil: result = x
  229. proc FieldDiscriminantCheck(oldDiscVal, newDiscVal: int,
  230. a: ptr array[0x7fff, ptr TNimNode],
  231. L: int) {.compilerProc.} =
  232. var oldBranch = selectBranch(oldDiscVal, L, a)
  233. var newBranch = selectBranch(newDiscVal, L, a)
  234. if newBranch != oldBranch and oldDiscVal != 0:
  235. sysFatal(FieldError, "assignment to discriminant changes object branch")