cellsets.nim 6.3 KB

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