tgeneric3.nim 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. import strutils
  2. type
  3. PNode[T,D] = ref TNode[T,D]
  4. TItem {.acyclic, pure, final, shallow.} [T,D] = object
  5. key: T
  6. value: D
  7. node: PNode[T,D]
  8. when not (D is string):
  9. val_set: bool
  10. TItems[T,D] = seq[ref TItem[T,D]]
  11. TNode {.acyclic, pure, final, shallow.} [T,D] = object
  12. slots: TItems[T,D]
  13. left: PNode[T,D]
  14. count: int32
  15. RPath[T,D] = tuple[
  16. Xi: int,
  17. Nd: PNode[T,D] ]
  18. const
  19. cLen1 = 2
  20. cLen2 = 16
  21. cLen3 = 32
  22. cLenCenter = 80
  23. clen4 = 96
  24. cLenMax = 128
  25. cCenter = cLenMax div 2
  26. proc len[T,D] (n:PNode[T,D]): int {.inline.} =
  27. return n.count
  28. proc clean[T: SomeOrdinal|SomeNumber](o: var T) {.inline.} = discard
  29. proc clean[T: string|seq](o: var T) {.inline.} =
  30. o = nil
  31. proc clean[T,D] (o: ref TItem[T,D]) {.inline.} =
  32. when (D is string) :
  33. o.value = nil
  34. else :
  35. o.val_set = false
  36. proc isClean[T,D] (it: ref TItem[T,D]): bool {.inline.} =
  37. when (D is string) :
  38. return it.value == nil
  39. else :
  40. return not it.val_set
  41. proc isClean[T,D](n: PNode[T,D], x: int): bool {.inline.} =
  42. when (D is string):
  43. return n.slots[x].value == nil
  44. else:
  45. return not n.slots[x].val_set
  46. proc setItem[T,D](Akey: T, Avalue: D, ANode: PNode[T,D]): ref TItem[T,D] {.inline.} =
  47. new(result)
  48. result.key = Akey
  49. result.value = Avalue
  50. result.node = ANode
  51. when not (D is string) :
  52. result.val_set = true
  53. proc cmp[T:int8|int16|int32|int64|int] (a,b: T): T {.inline.} =
  54. return a-b
  55. template binSearchImpl *(docmp: untyped) =
  56. var bFound = false
  57. result = 0
  58. var H = haystack.len - 1
  59. while result <= H :
  60. var I {.inject.} = (result + H) shr 1
  61. var SW = docmp
  62. if SW < 0: result = I + 1
  63. else:
  64. H = I - 1
  65. if SW == 0 : bFound = true
  66. if bFound: inc(result)
  67. else: result = - result
  68. proc bSearch[T,D] (haystack: PNode[T,D], needle:T): int {.inline.} =
  69. binSearchImpl(haystack.slots[I].key.cmp(needle))
  70. proc DeleteItem[T,D] (n: PNode[T,D], x: int): PNode[T,D] {.inline.} =
  71. var w = n.slots[x]
  72. if w.node != nil :
  73. clean(w)
  74. return n
  75. dec(n.count)
  76. if n.count > 0 :
  77. for i in countup(x, n.count - 1) : n.slots[i] = n.slots[i + 1]
  78. n.slots[n.count] = nil
  79. case n.count
  80. of cLen1 : setLen(n.slots, cLen1)
  81. of cLen2 : setLen(n.slots, cLen2)
  82. of cLen3 : setLen(n.slots, cLen3)
  83. of cLenCenter : setLen(n.slots, cLenCenter)
  84. of cLen4 : setLen(n.slots, cLen4)
  85. else: discard
  86. result = n
  87. else :
  88. result = n.left
  89. n.slots = @[]
  90. n.left = nil
  91. proc internalDelete[T,D] (ANode: PNode[T,D], key: T, Avalue: var D): PNode[T,D] =
  92. var Path: array[0..20, RPath[T,D]]
  93. var n = ANode
  94. result = n
  95. clean(Avalue)
  96. var h = 0
  97. while n != nil:
  98. var x = bSearch(n, key)
  99. if x <= 0 :
  100. Path[h].Nd = n
  101. Path[h].Xi = - x
  102. inc(h)
  103. if x == 0 :
  104. n = n.left
  105. else :
  106. x = (-x) - 1
  107. if x < n.count :
  108. n = n.slots[x].node
  109. else :
  110. n = nil
  111. else :
  112. dec(x)
  113. if isClean(n, x) : return
  114. Avalue = n.slots[x].value
  115. var n2 = DeleteItem(n, x)
  116. dec(h)
  117. while (n2 != n) and (h >= 0) :
  118. n = n2
  119. var w = addr Path[h]
  120. x = w.Xi - 1
  121. if x >= 0 :
  122. if (n == nil) and isClean(w.Nd, x) :
  123. n = w.Nd
  124. n.slots[x].node = nil
  125. n2 = DeleteItem(n, x)
  126. else :
  127. w.Nd.slots[x].node = n
  128. return
  129. else :
  130. w.Nd.left = n
  131. return
  132. dec(h)
  133. if h < 0:
  134. result = n2
  135. return
  136. proc internalFind[T,D] (n: PNode[T,D], key: T): ref TItem[T,D] {.inline.} =
  137. var wn = n
  138. while wn != nil :
  139. var x = bSearch(wn, key)
  140. if x <= 0 :
  141. if x == 0 :
  142. wn = wn.left
  143. else :
  144. x = (-x) - 1
  145. if x < wn.count :
  146. wn = wn.slots[x].node
  147. else :
  148. return nil
  149. else :
  150. return wn.slots[x - 1]
  151. return nil
  152. proc traceTree[T,D](root: PNode[T,D]) =
  153. proc traceX(x: int) =
  154. write stdout, "("
  155. write stdout, x
  156. write stdout, ") "
  157. proc traceEl(el: ref TItem[T,D]) =
  158. write stdout, " key: "
  159. write stdout, el.key
  160. write stdout, " value: "
  161. write stdout, el.value
  162. proc traceln(space: string) =
  163. writeLine stdout, ""
  164. write stdout, space
  165. proc doTrace(n: PNode[T,D], level: int) =
  166. var space = spaces(2 * level)
  167. traceln(space)
  168. write stdout, "node: "
  169. if n == nil:
  170. writeLine stdout, "is empty"
  171. return
  172. write stdout, n.count
  173. write stdout, " elements: "
  174. if n.left != nil:
  175. traceln(space)
  176. write stdout, "left: "
  177. doTrace(n.left, level+1)
  178. for i, el in n.slots:
  179. if el != nil and not isClean(el):
  180. traceln(space)
  181. traceX(i)
  182. if i >= n.count:
  183. write stdout, "error "
  184. else:
  185. traceEl(el)
  186. if el.node != nil: doTrace(el.node, level+1)
  187. else : write stdout, " empty "
  188. elif i < n.count :
  189. traceln(space)
  190. traceX(i)
  191. write stdout, "clean: "
  192. when T is string :
  193. if el.key != nil: write stdout, el.key
  194. else : write stdout, el.key
  195. if el.node != nil: doTrace(el.node, level+1)
  196. else : write stdout, " empty "
  197. writeLine stdout,""
  198. doTrace(root, 0)
  199. proc InsertItem[T,D](APath: RPath[T,D], ANode:PNode[T,D], Akey: T, Avalue: D) =
  200. var x = - APath.Xi
  201. inc(APath.Nd.count)
  202. case APath.Nd.count
  203. of cLen1: setLen(APath.Nd.slots, cLen2)
  204. of cLen2: setLen(APath.Nd.slots, cLen3)
  205. of cLen3: setLen(APath.Nd.slots, cLenCenter)
  206. of cLenCenter: setLen(APath.Nd.slots, cLen4)
  207. of cLen4: setLen(APath.Nd.slots, cLenMax)
  208. else: discard
  209. for i in countdown(APath.Nd.count.int - 1, x + 1): shallowCopy(APath.Nd.slots[i], APath.Nd.slots[i - 1])
  210. APath.Nd.slots[x] = setItem(Akey, Avalue, ANode)
  211. proc SplitPage[T,D](n, left: PNode[T,D], xi: int, Akey:var T, Avalue:var D): PNode[T,D] =
  212. var x = -xi
  213. var it1: TItems[T,D]
  214. it1.newSeq(cLenCenter)
  215. new(result)
  216. result.slots.newSeq(cLenCenter)
  217. result.count = cCenter
  218. if x == cCenter:
  219. for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i])
  220. for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i])
  221. result.left = n
  222. else :
  223. if x < cCenter :
  224. for i in 0..x-1: shallowCopy(it1[i], left.slots[i])
  225. it1[x] = setItem(Akey, Avalue, n)
  226. for i in x+1 .. cCenter-1: shallowCopy(it1[i], left.slots[i-1])
  227. var w = left.slots[cCenter-1]
  228. Akey = w.key
  229. Avalue = w.value
  230. result.left = w.node
  231. for i in 0..cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i])
  232. else :
  233. for i in 0..cCenter-1: shallowCopy(it1[i], left.slots[i])
  234. x = x - (cCenter + 1)
  235. for i in 0..x-1: shallowCopy(result.slots[i], left.slots[cCenter + i + 1])
  236. result.slots[x] = setItem(Akey, Avalue, n)
  237. for i in x+1 .. cCenter-1: shallowCopy(result.slots[i], left.slots[cCenter + i])
  238. var w = left.slots[cCenter]
  239. Akey = w.key
  240. Avalue = w.value
  241. result.left = w.node
  242. left.count = cCenter
  243. shallowCopy(left.slots, it1)
  244. proc internalPut[T,D](ANode: ref TNode[T,D], Akey: T, Avalue: D, Oldvalue: var D): ref TNode[T,D] =
  245. var h: int
  246. var Path: array[0..30, RPath[T,D]]
  247. var left: PNode[T,D]
  248. var n = ANode
  249. result = ANode
  250. h = 0
  251. while n != nil:
  252. var x = bSearch[T,D](n, Akey)
  253. if x <= 0 :
  254. Path[h].Nd = n
  255. Path[h].Xi = x
  256. inc(h)
  257. if x == 0 :
  258. n = n.left
  259. else :
  260. x = (-x)-1
  261. if x < n.count :
  262. n = n.slots[x].node
  263. else :
  264. n = nil
  265. else :
  266. var w = n.slots[x - 1]
  267. Oldvalue = w.value
  268. w.value = Avalue
  269. return
  270. dec(h)
  271. left = nil
  272. var lkey = Akey
  273. var lvalue = Avalue
  274. while h >= 0 :
  275. if Path[h].Nd.count < cLenMax :
  276. InsertItem(Path[h], n, lkey, lvalue)
  277. return
  278. else :
  279. left = Path[h].Nd
  280. n = SplitPage(n, left, Path[h].Xi, lkey, lvalue)
  281. dec(h)
  282. new(result)
  283. result.slots.newSeq(cLen1)
  284. result.count = 1
  285. result.left = left
  286. result.slots[0] = setItem(lkey, lvalue, n)
  287. proc CleanTree[T,D](n: PNode[T,D]): PNode[T,D] =
  288. if n.left != nil :
  289. n.left = CleanTree(n.left)
  290. for i in 0 .. n.count - 1 :
  291. var w = n.slots[i]
  292. if w.node != nil :
  293. w.node = CleanTree(w.node)
  294. clean(w.value)
  295. clean(w.key)
  296. n.slots = nil
  297. return nil
  298. proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]): PNode[T,D] {.closure.} ): PNode[T,D] =
  299. if n != nil :
  300. if n.left != nil :
  301. n.left = VisitAllNodes(n.left, visit)
  302. for i in 0 .. n.count - 1 :
  303. var w = n.slots[i]
  304. if w.node != nil :
  305. w.node = VisitAllNodes(w.node, visit)
  306. return visit(n)
  307. return nil
  308. proc VisitAllNodes[T,D](n: PNode[T,D], visit: proc(n: PNode[T,D]) {.closure.} ) =
  309. if n != nil:
  310. if n.left != nil :
  311. VisitAllNodes(n.left, visit)
  312. for i in 0 .. n.count - 1 :
  313. var w = n.slots[i]
  314. if w.node != nil :
  315. VisitAllNodes(w.node, visit)
  316. visit(n)
  317. proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: D) {.closure.} ) =
  318. if n != nil:
  319. if n.left != nil :
  320. VisitAll(n.left, visit)
  321. for i in 0 .. n.count - 1 :
  322. var w = n.slots[i]
  323. if not w.isClean :
  324. visit(w.key, w.value)
  325. if w.node != nil :
  326. VisitAll(w.node, visit)
  327. proc VisitAll[T,D](n: PNode[T,D], visit: proc(Akey: T, Avalue: var D):bool {.closure.} ): PNode[T,D] =
  328. if n != nil:
  329. var n1 = n.left
  330. if n1 != nil :
  331. var n2 = VisitAll(n1, visit)
  332. if n1 != n2 :
  333. n.left = n2
  334. var i = 0
  335. while i < n.count :
  336. var w = n.slots[i]
  337. if not w.isClean :
  338. if visit(w.key, w.value) :
  339. result = DeleteItem(n, i)
  340. if result == nil : return
  341. dec(i)
  342. n1 = w.node
  343. if n1 != nil :
  344. var n2 = VisitAll(n1, visit)
  345. if n1 != n2 :
  346. w.node = n2
  347. inc(i)
  348. return n
  349. iterator keys* [T,D] (n: PNode[T,D]): T =
  350. if n != nil :
  351. var Path: array[0..20, RPath[T,D]]
  352. var level = 0
  353. var nd = n
  354. var i = -1
  355. while true :
  356. if i < nd.count :
  357. Path[level].Nd = nd
  358. Path[level].Xi = i
  359. if i < 0 :
  360. if nd.left != nil :
  361. nd = nd.left
  362. inc(level)
  363. else : inc(i)
  364. else :
  365. var w = nd.slots[i]
  366. if not w.isClean() :
  367. yield w.key
  368. if w.node != nil :
  369. nd = w.node
  370. i = -1
  371. inc(level)
  372. else : inc(i)
  373. else :
  374. dec(level)
  375. if level < 0 : break
  376. nd = Path[level].Nd
  377. i = Path[level].Xi
  378. inc(i)
  379. when isMainModule:
  380. proc test() =
  381. var oldvalue: int
  382. var root = internalPut[int, int](nil, 312, 312, oldvalue)
  383. var someOtherRoot = internalPut[string, int](nil, "312", 312, oldvalue)
  384. var it1 = internalFind(root, 312)
  385. echo it1.value
  386. for i in 1..1_000_000:
  387. root = internalPut(root, i, i, oldvalue)
  388. var cnt = 0
  389. oldvalue = -1
  390. when true : # code compiles, when this or the other when is switched to false
  391. for k in root.keys :
  392. if k <= oldvalue :
  393. echo k
  394. oldvalue = k
  395. inc(cnt)
  396. echo cnt
  397. when true :
  398. cnt = 0
  399. VisitAll(root, proc(key, val: int) = inc(cnt))
  400. echo cnt
  401. when true :
  402. root = VisitAll(root, proc(key: int, value: var int): bool =
  403. return key mod 2 == 0 )
  404. cnt = 0
  405. oldvalue = -1
  406. VisitAll(root, proc(key: int, value: int) {.closure.} =
  407. if key <= oldvalue :
  408. echo key
  409. oldvalue = key
  410. inc(cnt) )
  411. echo cnt
  412. root = VisitAll(root, proc(key: int, value: var int): bool =
  413. return key mod 2 != 0 )
  414. cnt = 0
  415. oldvalue = -1
  416. VisitAll(root, proc(key: int, value: int) {.closure.} =
  417. if key <= oldvalue :
  418. echo "error ", key
  419. oldvalue = key
  420. inc(cnt) )
  421. echo cnt
  422. #traceTree(root)
  423. test()