cellsets.nim 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. #
  2. #
  3. # Nim's Runtime Library
  4. # (c) Copyright 2013 Andreas Rumpf
  5. #
  6. # See the file "copying.txt", included in this
  7. # distribution, for details about the copyright.
  8. #
  9. # Efficient set of pointers for the GC (and repr)
  10. type
  11. RefCount = int
  12. Cell {.pure.} = object
  13. refcount: RefCount # the refcount and some flags
  14. typ: PNimType
  15. when trackAllocationSource:
  16. filename: cstring
  17. line: int
  18. when useCellIds:
  19. id: int
  20. PCell = ptr Cell
  21. PPageDesc = ptr PageDesc
  22. BitIndex = range[0..UnitsPerPage-1]
  23. PageDesc {.final, pure.} = object
  24. next: PPageDesc # all nodes are connected with this pointer
  25. key: ByteAddress # start address at bit 0
  26. bits: array[BitIndex, int] # a bit vector
  27. PPageDescArray = ptr UncheckedArray[PPageDesc]
  28. CellSet {.final, pure.} = object
  29. counter, max: int
  30. head: PPageDesc
  31. data: PPageDescArray
  32. PCellArray = ptr UncheckedArray[PCell]
  33. CellSeq {.final, pure.} = object
  34. len, cap: int
  35. d: PCellArray
  36. {.deprecated: [TCell: Cell, TBitIndex: BitIndex, TPageDesc: PageDesc,
  37. TRefCount: RefCount, TCellSet: CellSet, TCellSeq: CellSeq].}
  38. # ------------------- cell seq handling ---------------------------------------
  39. proc contains(s: CellSeq, c: PCell): bool {.inline.} =
  40. for i in 0 .. s.len-1:
  41. if s.d[i] == c: return true
  42. return false
  43. proc add(s: var CellSeq, c: PCell) {.inline.} =
  44. if s.len >= s.cap:
  45. s.cap = s.cap * 3 div 2
  46. var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
  47. copyMem(d, s.d, s.len * sizeof(PCell))
  48. dealloc(s.d)
  49. s.d = d
  50. # XXX: realloc?
  51. s.d[s.len] = c
  52. inc(s.len)
  53. proc init(s: var CellSeq, cap: int = 1024) =
  54. s.len = 0
  55. s.cap = cap
  56. s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
  57. proc deinit(s: var CellSeq) =
  58. dealloc(s.d)
  59. s.d = nil
  60. s.len = 0
  61. s.cap = 0
  62. # ------------------- cell set handling ---------------------------------------
  63. const
  64. InitCellSetSize = 1024 # must be a power of two!
  65. proc init(s: var CellSet) =
  66. s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
  67. s.max = InitCellSetSize-1
  68. s.counter = 0
  69. s.head = nil
  70. proc deinit(s: var CellSet) =
  71. var it = s.head
  72. while it != nil:
  73. var n = it.next
  74. dealloc(it)
  75. it = n
  76. s.head = nil # play it safe here
  77. dealloc(s.data)
  78. s.data = nil
  79. s.counter = 0
  80. proc nextTry(h, maxHash: int): int {.inline.} =
  81. result = ((5*h) + 1) and maxHash
  82. # For any initial h in range(maxHash), repeating that maxHash times
  83. # generates each int in range(maxHash) exactly once (see any text on
  84. # random-number generation for proof).
  85. proc cellSetGet(t: CellSet, key: ByteAddress): PPageDesc =
  86. var h = cast[int](key) and t.max
  87. while t.data[h] != nil:
  88. if t.data[h].key == key: return t.data[h]
  89. h = nextTry(h, t.max)
  90. return nil
  91. proc cellSetRawInsert(t: CellSet, data: PPageDescArray, desc: PPageDesc) =
  92. var h = cast[int](desc.key) and t.max
  93. while data[h] != nil:
  94. sysAssert(data[h] != desc, "CellSetRawInsert 1")
  95. h = nextTry(h, t.max)
  96. sysAssert(data[h] == nil, "CellSetRawInsert 2")
  97. data[h] = desc
  98. proc cellSetEnlarge(t: var CellSet) =
  99. var oldMax = t.max
  100. t.max = ((t.max+1)*2)-1
  101. var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
  102. for i in 0 .. oldMax:
  103. if t.data[i] != nil:
  104. cellSetRawInsert(t, n, t.data[i])
  105. dealloc(t.data)
  106. t.data = n
  107. proc cellSetPut(t: var CellSet, key: ByteAddress): PPageDesc =
  108. var h = cast[int](key) and t.max
  109. while true:
  110. var x = t.data[h]
  111. if x == nil: break
  112. if x.key == key: return x
  113. h = nextTry(h, t.max)
  114. if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
  115. cellSetEnlarge(t)
  116. inc(t.counter)
  117. h = cast[int](key) and t.max
  118. while t.data[h] != nil: h = nextTry(h, t.max)
  119. sysAssert(t.data[h] == nil, "CellSetPut")
  120. # the new page descriptor goes into result
  121. result = cast[PPageDesc](alloc0(sizeof(PageDesc)))
  122. result.next = t.head
  123. result.key = key
  124. t.head = result
  125. t.data[h] = result
  126. # ---------- slightly higher level procs --------------------------------------
  127. proc contains(s: CellSet, cell: PCell): bool =
  128. var u = cast[ByteAddress](cell)
  129. var t = cellSetGet(s, u shr PageShift)
  130. if t != nil:
  131. u = (u %% PageSize) /% MemAlign
  132. result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
  133. else:
  134. result = false
  135. proc incl(s: var CellSet, cell: PCell) {.noinline.} =
  136. var u = cast[ByteAddress](cell)
  137. var t = cellSetPut(s, u shr PageShift)
  138. u = (u %% PageSize) /% MemAlign
  139. t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
  140. proc excl(s: var CellSet, cell: PCell) =
  141. var u = cast[ByteAddress](cell)
  142. var t = cellSetGet(s, u shr PageShift)
  143. if t != nil:
  144. u = (u %% PageSize) /% MemAlign
  145. t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
  146. not (1 shl (u and IntMask)))
  147. proc containsOrIncl(s: var CellSet, cell: PCell): bool =
  148. var u = cast[ByteAddress](cell)
  149. var t = cellSetGet(s, u shr PageShift)
  150. if t != nil:
  151. u = (u %% PageSize) /% MemAlign
  152. result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
  153. if not result:
  154. t.bits[u shr IntShift] = t.bits[u shr IntShift] or
  155. (1 shl (u and IntMask))
  156. else:
  157. incl(s, cell)
  158. result = false
  159. iterator elements(t: CellSet): PCell {.inline.} =
  160. # while traversing it is forbidden to add pointers to the tree!
  161. var r = t.head
  162. while r != nil:
  163. var i = 0
  164. while i <= high(r.bits):
  165. var w = r.bits[i] # taking a copy of r.bits[i] here is correct, because
  166. # modifying operations are not allowed during traversation
  167. var j = 0
  168. while w != 0: # test all remaining bits for zero
  169. if (w and 1) != 0: # the bit is set!
  170. yield cast[PCell]((r.key shl PageShift) or
  171. (i shl IntShift +% j) *% MemAlign)
  172. inc(j)
  173. w = w shr 1
  174. inc(i)
  175. r = r.next
  176. when false:
  177. type
  178. CellSetIter = object
  179. p: PPageDesc
  180. i, w, j: int
  181. proc next(it: var CellSetIter): PCell =
  182. while true:
  183. while it.w != 0: # test all remaining bits for zero
  184. if (it.w and 1) != 0: # the bit is set!
  185. result = cast[PCell]((it.p.key shl PageShift) or
  186. (it.i shl IntShift +% it.j) *% MemAlign)
  187. inc(it.j)
  188. it.w = it.w shr 1
  189. return
  190. else:
  191. inc(it.j)
  192. it.w = it.w shr 1
  193. # load next w:
  194. if it.i >= high(it.p.bits):
  195. it.i = 0
  196. it.j = 0
  197. it.p = it.p.next
  198. if it.p == nil: return nil
  199. else:
  200. inc it.i
  201. it.w = it.p.bits[i]
  202. proc init(it: var CellSetIter; t: CellSet): PCell =
  203. it.p = t.head
  204. it.i = -1
  205. it.w = 0
  206. result = it.next
  207. iterator elementsExcept(t, s: CellSet): PCell {.inline.} =
  208. var r = t.head
  209. while r != nil:
  210. let ss = cellSetGet(s, r.key)
  211. var i = 0
  212. while i <= high(r.bits):
  213. var w = r.bits[i]
  214. if ss != nil:
  215. w = w and not ss.bits[i]
  216. var j = 0
  217. while w != 0:
  218. if (w and 1) != 0:
  219. yield cast[PCell]((r.key shl PageShift) or
  220. (i shl IntShift +% j) *% MemAlign)
  221. inc(j)
  222. w = w shr 1
  223. inc(i)
  224. r = r.next