tgeneric3.nim 12 KB

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