avl_map.g 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. # This file is part of asmc, a bootstrapping OS with minimal seed
  2. # Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
  3. # https://gitlab.com/giomasce/asmc
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. # You should have received a copy of the GNU General Public License
  13. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. # Despite the file name, this is not a true AVL implementation: it
  15. # implements a (hopefully) correct binary search tree, but there are
  16. # not AVL rotations, so the tree is not guaranteed to remain
  17. # balanced. At the beginning I planned to eventually add rotation, but
  18. # at some point I decided to switch to red-black trees, for which I
  19. # found a ready-to-use free implementation on the Internet. So this
  20. # file was left behind. It still works, but it will probably never be
  21. # completed.
  22. const AVL_LEFT 0
  23. const AVL_RIGHT 4
  24. const AVL_KEY 8
  25. const AVL_VALUE 12
  26. const AVL_PARENT 16
  27. const SIZEOF_AVL 20
  28. fun avl_init 2 {
  29. $key
  30. $parent
  31. @key 1 param = ;
  32. @parent 0 param = ;
  33. $avl
  34. @avl SIZEOF_AVL malloc = ;
  35. avl AVL_LEFT take_addr 0 = ;
  36. avl AVL_RIGHT take_addr 0 = ;
  37. avl AVL_KEY take_addr key strdup = ;
  38. avl AVL_VALUE take_addr 0 = ;
  39. avl AVL_PARENT take_addr parent = ;
  40. avl ret ;
  41. }
  42. fun avl_destroy 1 {
  43. $avl
  44. @avl 0 param = ;
  45. if avl AVL_LEFT take 0 != {
  46. avl AVL_LEFT take avl_destroy ;
  47. }
  48. if avl AVL_RIGHT take 0 != {
  49. avl AVL_RIGHT take avl_destroy ;
  50. }
  51. avl AVL_KEY take free ;
  52. avl free ;
  53. }
  54. const MAP_AVL 0
  55. const MAP_SIZE 4
  56. const SIZEOF_MAP 8
  57. fun map_init 0 {
  58. $map
  59. @map SIZEOF_MAP malloc = ;
  60. map MAP_AVL take_addr 0 = ;
  61. map MAP_SIZE take_addr 0 = ;
  62. map ret ;
  63. }
  64. fun map_destroy 1 {
  65. $map
  66. @map 0 param = ;
  67. if map MAP_AVL take 0 != {
  68. map MAP_AVL take avl_destroy ;
  69. }
  70. map free ;
  71. }
  72. fun _map_find 3 {
  73. $map
  74. $key
  75. $create
  76. @map 2 param = ;
  77. @key 1 param = ;
  78. @create 0 param = ;
  79. $avl
  80. @avl map MAP_AVL take = ;
  81. $ptr
  82. @ptr map MAP_AVL take_addr = ;
  83. $parent
  84. @parent 0 = ;
  85. while 1 {
  86. if avl 0 == {
  87. if create {
  88. @avl key parent avl_init = ;
  89. ptr avl = ;
  90. map MAP_SIZE take_addr map MAP_SIZE take 1 + = ;
  91. avl ret ;
  92. } else {
  93. 0 ret ;
  94. }
  95. }
  96. $cmp
  97. @cmp key avl AVL_KEY take strcmp = ;
  98. if cmp 0 == {
  99. avl ret ;
  100. }
  101. if cmp 0 < {
  102. @ptr avl AVL_LEFT take_addr = ;
  103. @parent avl = ;
  104. @avl avl AVL_LEFT take = ;
  105. } else {
  106. @ptr avl AVL_RIGHT take_addr = ;
  107. @parent avl = ;
  108. @avl avl AVL_RIGHT take = ;
  109. }
  110. }
  111. }
  112. fun map_at 2 {
  113. $map
  114. $key
  115. @map 1 param = ;
  116. @key 0 param = ;
  117. $avl
  118. @avl map key 0 _map_find = ;
  119. avl 0 != "map_at: key does not exist" assert_msg ;
  120. # "map_at(" log ;
  121. # key log ;
  122. # ") = " log ;
  123. # avl AVL_VALUE take itoa log ;
  124. # "\n" log ;
  125. avl AVL_VALUE take ret ;
  126. }
  127. fun map_has 2 {
  128. $map
  129. $key
  130. @map 1 param = ;
  131. @key 0 param = ;
  132. $avl
  133. @avl map key 0 _map_find = ;
  134. # "map_has(" log ;
  135. # key log ;
  136. # ") = " log ;
  137. # avl 0 != itoa log ;
  138. # "\n" log ;
  139. avl 0 != ret ;
  140. }
  141. fun map_set 3 {
  142. $map
  143. $key
  144. $value
  145. @map 2 param = ;
  146. @key 1 param = ;
  147. @value 0 param = ;
  148. $avl
  149. @avl map key 1 _map_find = ;
  150. avl 0 != "map_set: error 1" assert_msg ;
  151. # "map_set(" log ;
  152. # key log ;
  153. # ", " log ;
  154. # value itoa log ;
  155. # ")\n" log ;
  156. avl AVL_VALUE take_addr value = ;
  157. }
  158. fun _map_erase_leaf 2 {
  159. $map
  160. $avl
  161. @map 1 param = ;
  162. @avl 0 param = ;
  163. map MAP_SIZE take_addr map MAP_SIZE take 1 - = ;
  164. avl AVL_LEFT take 0 == "_map_erase_leaf: has left child" assert_msg ;
  165. avl AVL_RIGHT take 0 == "_map_erase_leaf: has right child" assert_msg ;
  166. $parent
  167. @parent avl AVL_PARENT take = ;
  168. avl avl_destroy ;
  169. if parent 0 == {
  170. map MAP_AVL take avl == "_map_erase_leaf: wrong root" assert_msg ;
  171. map MAP_AVL take_addr 0 = ;
  172. ret ;
  173. }
  174. if parent AVL_LEFT take avl == {
  175. parent AVL_LEFT take_addr 0 = ;
  176. ret ;
  177. }
  178. if parent AVL_RIGHT take avl == {
  179. parent AVL_RIGHT take_addr 0 = ;
  180. ret ;
  181. }
  182. 0 "_map_erase_leaf: cannot find among parent's children" assert_msg ;
  183. }
  184. fun _avl_swap 2 {
  185. $avl
  186. $avl2
  187. @avl 1 param = ;
  188. @avl2 0 param = ;
  189. $tmp
  190. @tmp avl AVL_VALUE take = ;
  191. avl AVL_VALUE take_addr avl2 AVL_VALUE take = ;
  192. avl2 AVL_VALUE take_addr tmp = ;
  193. @tmp avl AVL_KEY take = ;
  194. avl AVL_KEY take_addr avl2 AVL_KEY take = ;
  195. avl2 AVL_KEY take_addr tmp = ;
  196. }
  197. fun _map_erase 2 {
  198. $map
  199. $avl
  200. @map 1 param = ;
  201. @avl 0 param = ;
  202. if avl 0 != {
  203. if avl AVL_LEFT take 0 != {
  204. $avl2
  205. @avl2 avl AVL_LEFT take = ;
  206. while avl2 AVL_RIGHT take 0 != {
  207. @avl2 avl2 AVL_RIGHT take = ;
  208. }
  209. avl avl2 _avl_swap ;
  210. map avl2 _map_erase ;
  211. ret ;
  212. }
  213. if avl AVL_RIGHT take 0 != {
  214. $avl2
  215. @avl2 avl AVL_RIGHT take = ;
  216. while avl2 AVL_LEFT take 0 != {
  217. @avl2 avl2 AVL_LEFT take = ;
  218. }
  219. avl avl2 _avl_swap ;
  220. map avl2 _map_erase ;
  221. ret ;
  222. }
  223. map avl _map_erase_leaf ;
  224. }
  225. }
  226. fun map_erase 2 {
  227. $map
  228. $key
  229. @map 1 param = ;
  230. @key 0 param = ;
  231. $avl
  232. @avl map key 0 _map_find = ;
  233. map avl _map_erase ;
  234. # "map_erase(" log ;
  235. # key log ;
  236. # ")\n" log ;
  237. }
  238. fun map_size 1 {
  239. $map
  240. @map 0 param = ;
  241. map MAP_SIZE take ret ;
  242. }
  243. fun _map_foreach 3 {
  244. $avl
  245. $func
  246. $ctx
  247. @avl 2 param = ;
  248. @func 1 param = ;
  249. @ctx 0 param = ;
  250. if avl 0 == {
  251. ret ;
  252. }
  253. avl AVL_LEFT take func ctx _map_foreach ;
  254. ctx avl AVL_KEY take avl AVL_VALUE take func \3 ;
  255. avl AVL_RIGHT take func ctx _map_foreach ;
  256. }
  257. fun map_foreach 3 {
  258. $map
  259. $func
  260. $ctx
  261. @map 2 param = ;
  262. @func 1 param = ;
  263. @ctx 0 param = ;
  264. map MAP_AVL take func ctx _map_foreach ;
  265. }