tradix.nim 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. discard """
  2. output: '''
  3. start tradix.nim
  4. false
  5. false
  6. false
  7. false
  8. false
  9. false
  10. false
  11. false
  12. false
  13. false
  14. 128
  15. 1
  16. 2
  17. 3
  18. 4
  19. 255
  20. 17
  21. 45
  22. 19000
  23. 4294967288
  24. '''
  25. """
  26. # implements and tests an efficient radix tree
  27. ## another method to store an efficient array of pointers:
  28. ## We use a radix tree with node compression.
  29. ## There are two node kinds:
  30. echo "start tradix.nim"
  31. const BitsPerUnit = 8*sizeof(int)
  32. type
  33. TRadixNodeKind = enum rnLinear, rnFull, rnLeafBits, rnLeafLinear
  34. PRadixNode = ptr TRadixNode
  35. TRadixNode {.pure, inheritable.} = object
  36. kind: TRadixNodeKind
  37. TRadixNodeLinear = object of TRadixNode
  38. len: uint8
  39. keys: array[0..31, uint8]
  40. vals: array[0..31, PRadixNode]
  41. TRadixNodeFull = object of TRadixNode
  42. b: array[0..255, PRadixNode]
  43. TRadixNodeLeafBits = object of TRadixNode
  44. b: array[0..7, int]
  45. TRadixNodeLeafLinear = object of TRadixNode
  46. len: uint8
  47. keys: array[0..31, uint8]
  48. var
  49. root: PRadixNode
  50. proc searchInner(r: PRadixNode, a: int): PRadixNode =
  51. case r.kind
  52. of rnLinear:
  53. var x = cast[ptr TRadixNodeLinear](r)
  54. for i in 0..int(x.len)-1:
  55. if int(x.keys[i]) == a: return x.vals[i]
  56. of rnFull:
  57. var x = cast[ptr TRadixNodeFull](r)
  58. return x.b[a]
  59. else: assert(false)
  60. proc testBit(w, i: int): bool {.inline.} =
  61. result = (w and (1 shl (i %% BitsPerUnit))) != 0
  62. proc setBit(w: var int, i: int) {.inline.} =
  63. w = w or (1 shl (i %% BitsPerUnit))
  64. proc resetBit(w: var int, i: int) {.inline.} =
  65. w = w and not (1 shl (i %% BitsPerUnit))
  66. proc testOrSetBit(w: var int, i: int): bool {.inline.} =
  67. var x = (1 shl (i %% BitsPerUnit))
  68. if (w and x) != 0: return true
  69. w = w or x
  70. proc searchLeaf(r: PRadixNode, a: int): bool =
  71. case r.kind
  72. of rnLeafBits:
  73. var x = cast[ptr TRadixNodeLeafBits](r)
  74. return testBit(x.b[a /% BitsPerUnit], a)
  75. of rnLeafLinear:
  76. var x = cast[ptr TRadixNodeLeafLinear](r)
  77. for i in 0..int(x.len)-1:
  78. if int(x.keys[i]) == a: return true
  79. else: assert(false)
  80. proc exclLeaf(r: PRadixNode, a: int) =
  81. case r.kind
  82. of rnLeafBits:
  83. var x = cast[ptr TRadixNodeLeafBits](r)
  84. resetBit(x.b[a /% BitsPerUnit], a)
  85. of rnLeafLinear:
  86. var x = cast[ptr TRadixNodeLeafLinear](r)
  87. var L = int(x.len)
  88. for i in 0..L-1:
  89. if int(x.keys[i]) == a:
  90. x.keys[i] = x.keys[L-1]
  91. dec(x.len)
  92. return
  93. else: assert(false)
  94. proc contains*(r: PRadixNode, a: ByteAddress): bool =
  95. if r == nil: return false
  96. var x = searchInner(r, a shr 24 and 0xff)
  97. if x == nil: return false
  98. x = searchInner(x, a shr 16 and 0xff)
  99. if x == nil: return false
  100. x = searchInner(x, a shr 8 and 0xff)
  101. if x == nil: return false
  102. return searchLeaf(x, a and 0xff)
  103. proc excl*(r: PRadixNode, a: ByteAddress): bool =
  104. if r == nil: return false
  105. var x = searchInner(r, a shr 24 and 0xff)
  106. if x == nil: return false
  107. x = searchInner(x, a shr 16 and 0xff)
  108. if x == nil: return false
  109. x = searchInner(x, a shr 8 and 0xff)
  110. if x == nil: return false
  111. exclLeaf(x, a and 0xff)
  112. proc addLeaf(r: var PRadixNode, a: int): bool =
  113. if r == nil:
  114. # a linear node:
  115. var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
  116. x.kind = rnLeafLinear
  117. x.len = 1'u8
  118. x.keys[0] = uint8(a)
  119. r = x
  120. return false # not already in set
  121. case r.kind
  122. of rnLeafBits:
  123. var x = cast[ptr TRadixNodeLeafBits](r)
  124. return testOrSetBit(x.b[a /% BitsPerUnit], a)
  125. of rnLeafLinear:
  126. var x = cast[ptr TRadixNodeLeafLinear](r)
  127. var L = int(x.len)
  128. for i in 0..L-1:
  129. if int(x.keys[i]) == a: return true
  130. if L <= high(x.keys):
  131. x.keys[L] = uint8(a)
  132. inc(x.len)
  133. else:
  134. # transform into a full node:
  135. var y = cast[ptr TRadixNodeLeafBits](alloc0(sizeof(TRadixNodeLeafBits)))
  136. y.kind = rnLeafBits
  137. for i in 0..int(x.len)-1:
  138. var u = int(x.keys[i])
  139. setBit(y.b[u /% BitsPerUnit], u)
  140. setBit(y.b[a /% BitsPerUnit], a)
  141. dealloc(r)
  142. r = y
  143. else: assert(false)
  144. proc addInner(r: var PRadixNode, a: int, d: int): bool =
  145. if d == 0:
  146. return addLeaf(r, a and 0xff)
  147. var k = a shr d and 0xff
  148. if r == nil:
  149. # a linear node:
  150. var x = cast[ptr TRadixNodeLinear](alloc0(sizeof(TRadixNodeLinear)))
  151. x.kind = rnLinear
  152. x.len = 1'u8
  153. x.keys[0] = uint8(k)
  154. r = x
  155. return addInner(x.vals[0], a, d-8)
  156. case r.kind
  157. of rnLinear:
  158. var x = cast[ptr TRadixNodeLinear](r)
  159. var L = int(x.len)
  160. for i in 0..L-1:
  161. if int(x.keys[i]) == k: # already exists
  162. return addInner(x.vals[i], a, d-8)
  163. if L <= high(x.keys):
  164. x.keys[L] = uint8(k)
  165. inc(x.len)
  166. return addInner(x.vals[L], a, d-8)
  167. else:
  168. # transform into a full node:
  169. var y = cast[ptr TRadixNodeFull](alloc0(sizeof(TRadixNodeFull)))
  170. y.kind = rnFull
  171. for i in 0..L-1: y.b[int(x.keys[i])] = x.vals[i]
  172. dealloc(r)
  173. r = y
  174. return addInner(y.b[k], a, d-8)
  175. of rnFull:
  176. var x = cast[ptr TRadixNodeFull](r)
  177. return addInner(x.b[k], a, d-8)
  178. else: assert(false)
  179. proc incl*(r: var PRadixNode, a: ByteAddress) {.inline.} =
  180. discard addInner(r, a, 24)
  181. proc testOrIncl*(r: var PRadixNode, a: ByteAddress): bool {.inline.} =
  182. return addInner(r, a, 24)
  183. iterator innerElements(r: PRadixNode): tuple[prefix: int, n: PRadixNode] =
  184. if r != nil:
  185. case r.kind
  186. of rnFull:
  187. var r = cast[ptr TRadixNodeFull](r)
  188. for i in 0..high(r.b):
  189. if r.b[i] != nil:
  190. yield (i, r.b[i])
  191. of rnLinear:
  192. var r = cast[ptr TRadixNodeLinear](r)
  193. for i in 0..int(r.len)-1:
  194. yield (int(r.keys[i]), r.vals[i])
  195. else: assert(false)
  196. iterator leafElements(r: PRadixNode): int =
  197. if r != nil:
  198. case r.kind
  199. of rnLeafBits:
  200. var r = cast[ptr TRadixNodeLeafBits](r)
  201. # iterate over any bit:
  202. for i in 0..high(r.b):
  203. if r.b[i] != 0: # test all bits for zero
  204. for j in 0..BitsPerUnit-1:
  205. if testBit(r.b[i], j):
  206. yield i*BitsPerUnit+j
  207. of rnLeafLinear:
  208. var r = cast[ptr TRadixNodeLeafLinear](r)
  209. for i in 0..int(r.len)-1:
  210. yield int(r.keys[i])
  211. else: assert(false)
  212. iterator elements*(r: PRadixNode): ByteAddress {.inline.} =
  213. for p1, n1 in innerElements(r):
  214. for p2, n2 in innerElements(n1):
  215. for p3, n3 in innerElements(n2):
  216. for p4 in leafElements(n3):
  217. yield p1 shl 24 or p2 shl 16 or p3 shl 8 or p4
  218. proc main() =
  219. const
  220. numbers = [128, 1, 2, 3, 4, 255, 17, -8, 45, 19_000]
  221. var
  222. r: PRadixNode = nil
  223. for x in items(numbers):
  224. echo testOrIncl(r, x)
  225. for x in elements(r):
  226. # ByteAddress being defined as a signed integer cases trouble
  227. # exactly here
  228. echo(cast[uint](x))
  229. main()