123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309 |
- # This file is part of asmc, a bootstrapping OS with minimal seed
- # Copyright (C) 2018 Giovanni Mascellani <gio@debian.org>
- # https://gitlab.com/giomasce/asmc
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <https://www.gnu.org/licenses/>.
- # Despite the file name, this is not a true AVL implementation: it
- # implements a (hopefully) correct binary search tree, but there are
- # not AVL rotations, so the tree is not guaranteed to remain
- # balanced. At the beginning I planned to eventually add rotation, but
- # at some point I decided to switch to red-black trees, for which I
- # found a ready-to-use free implementation on the Internet. So this
- # file was left behind. It still works, but it will probably never be
- # completed.
- const AVL_LEFT 0
- const AVL_RIGHT 4
- const AVL_KEY 8
- const AVL_VALUE 12
- const AVL_PARENT 16
- const SIZEOF_AVL 20
- fun avl_init 2 {
- $key
- $parent
- @key 1 param = ;
- @parent 0 param = ;
- $avl
- @avl SIZEOF_AVL malloc = ;
- avl AVL_LEFT take_addr 0 = ;
- avl AVL_RIGHT take_addr 0 = ;
- avl AVL_KEY take_addr key strdup = ;
- avl AVL_VALUE take_addr 0 = ;
- avl AVL_PARENT take_addr parent = ;
- avl ret ;
- }
- fun avl_destroy 1 {
- $avl
- @avl 0 param = ;
- if avl AVL_LEFT take 0 != {
- avl AVL_LEFT take avl_destroy ;
- }
- if avl AVL_RIGHT take 0 != {
- avl AVL_RIGHT take avl_destroy ;
- }
- avl AVL_KEY take free ;
- avl free ;
- }
- const MAP_AVL 0
- const MAP_SIZE 4
- const SIZEOF_MAP 8
- fun map_init 0 {
- $map
- @map SIZEOF_MAP malloc = ;
- map MAP_AVL take_addr 0 = ;
- map MAP_SIZE take_addr 0 = ;
- map ret ;
- }
- fun map_destroy 1 {
- $map
- @map 0 param = ;
- if map MAP_AVL take 0 != {
- map MAP_AVL take avl_destroy ;
- }
- map free ;
- }
- fun _map_find 3 {
- $map
- $key
- $create
- @map 2 param = ;
- @key 1 param = ;
- @create 0 param = ;
- $avl
- @avl map MAP_AVL take = ;
- $ptr
- @ptr map MAP_AVL take_addr = ;
- $parent
- @parent 0 = ;
- while 1 {
- if avl 0 == {
- if create {
- @avl key parent avl_init = ;
- ptr avl = ;
- map MAP_SIZE take_addr map MAP_SIZE take 1 + = ;
- avl ret ;
- } else {
- 0 ret ;
- }
- }
- $cmp
- @cmp key avl AVL_KEY take strcmp = ;
- if cmp 0 == {
- avl ret ;
- }
- if cmp 0 < {
- @ptr avl AVL_LEFT take_addr = ;
- @parent avl = ;
- @avl avl AVL_LEFT take = ;
- } else {
- @ptr avl AVL_RIGHT take_addr = ;
- @parent avl = ;
- @avl avl AVL_RIGHT take = ;
- }
- }
- }
- fun map_at 2 {
- $map
- $key
- @map 1 param = ;
- @key 0 param = ;
- $avl
- @avl map key 0 _map_find = ;
- avl 0 != "map_at: key does not exist" assert_msg ;
- # "map_at(" log ;
- # key log ;
- # ") = " log ;
- # avl AVL_VALUE take itoa log ;
- # "\n" log ;
- avl AVL_VALUE take ret ;
- }
- fun map_has 2 {
- $map
- $key
- @map 1 param = ;
- @key 0 param = ;
- $avl
- @avl map key 0 _map_find = ;
- # "map_has(" log ;
- # key log ;
- # ") = " log ;
- # avl 0 != itoa log ;
- # "\n" log ;
- avl 0 != ret ;
- }
- fun map_set 3 {
- $map
- $key
- $value
- @map 2 param = ;
- @key 1 param = ;
- @value 0 param = ;
- $avl
- @avl map key 1 _map_find = ;
- avl 0 != "map_set: error 1" assert_msg ;
- # "map_set(" log ;
- # key log ;
- # ", " log ;
- # value itoa log ;
- # ")\n" log ;
- avl AVL_VALUE take_addr value = ;
- }
- fun _map_erase_leaf 2 {
- $map
- $avl
- @map 1 param = ;
- @avl 0 param = ;
- map MAP_SIZE take_addr map MAP_SIZE take 1 - = ;
- avl AVL_LEFT take 0 == "_map_erase_leaf: has left child" assert_msg ;
- avl AVL_RIGHT take 0 == "_map_erase_leaf: has right child" assert_msg ;
- $parent
- @parent avl AVL_PARENT take = ;
- avl avl_destroy ;
- if parent 0 == {
- map MAP_AVL take avl == "_map_erase_leaf: wrong root" assert_msg ;
- map MAP_AVL take_addr 0 = ;
- ret ;
- }
- if parent AVL_LEFT take avl == {
- parent AVL_LEFT take_addr 0 = ;
- ret ;
- }
- if parent AVL_RIGHT take avl == {
- parent AVL_RIGHT take_addr 0 = ;
- ret ;
- }
- 0 "_map_erase_leaf: cannot find among parent's children" assert_msg ;
- }
- fun _avl_swap 2 {
- $avl
- $avl2
- @avl 1 param = ;
- @avl2 0 param = ;
- $tmp
- @tmp avl AVL_VALUE take = ;
- avl AVL_VALUE take_addr avl2 AVL_VALUE take = ;
- avl2 AVL_VALUE take_addr tmp = ;
- @tmp avl AVL_KEY take = ;
- avl AVL_KEY take_addr avl2 AVL_KEY take = ;
- avl2 AVL_KEY take_addr tmp = ;
- }
- fun _map_erase 2 {
- $map
- $avl
- @map 1 param = ;
- @avl 0 param = ;
- if avl 0 != {
- if avl AVL_LEFT take 0 != {
- $avl2
- @avl2 avl AVL_LEFT take = ;
- while avl2 AVL_RIGHT take 0 != {
- @avl2 avl2 AVL_RIGHT take = ;
- }
- avl avl2 _avl_swap ;
- map avl2 _map_erase ;
- ret ;
- }
- if avl AVL_RIGHT take 0 != {
- $avl2
- @avl2 avl AVL_RIGHT take = ;
- while avl2 AVL_LEFT take 0 != {
- @avl2 avl2 AVL_LEFT take = ;
- }
- avl avl2 _avl_swap ;
- map avl2 _map_erase ;
- ret ;
- }
- map avl _map_erase_leaf ;
- }
- }
- fun map_erase 2 {
- $map
- $key
- @map 1 param = ;
- @key 0 param = ;
- $avl
- @avl map key 0 _map_find = ;
- map avl _map_erase ;
- # "map_erase(" log ;
- # key log ;
- # ")\n" log ;
- }
- fun map_size 1 {
- $map
- @map 0 param = ;
- map MAP_SIZE take ret ;
- }
- fun _map_foreach 3 {
- $avl
- $func
- $ctx
- @avl 2 param = ;
- @func 1 param = ;
- @ctx 0 param = ;
- if avl 0 == {
- ret ;
- }
- avl AVL_LEFT take func ctx _map_foreach ;
- ctx avl AVL_KEY take avl AVL_VALUE take func \3 ;
- avl AVL_RIGHT take func ctx _map_foreach ;
- }
- fun map_foreach 3 {
- $map
- $func
- $ctx
- @map 2 param = ;
- @func 1 param = ;
- @ctx 0 param = ;
- map MAP_AVL take func ctx _map_foreach ;
- }
|