cellsets.nim 7.0 KB

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