1
0
Fork 0

Implement insert

master
Michael Raitza 2020-02-14 20:48:49 +01:00
parent f06eda5f16
commit ea07711f17
1 changed files with 57 additions and 68 deletions

View File

@ -14,8 +14,8 @@
! critical bit) in a length field (encoded as an integer and a mask) and two ! critical bit) in a length field (encoded as an integer and a mask) and two
! successor pointers. Arbitrary data objects make up its leaves. ! successor pointers. Arbitrary data objects make up its leaves.
USING: accessors arrays assocs fry kernel math namespaces sequences serialize USING: accessors arrays assocs combinators.short-circuit fry kernel locals math
trees trees.private ; namespaces sequences serialize trees trees.private ;
IN: trees.cb IN: trees.cb
TUPLE: cb < tree ; TUPLE: cb < tree ;
@ -75,8 +75,8 @@ SYMBOL: new-side
: with-key ( key quot -- ) : with-key ( key quot -- )
[ [
{ current-key key-bytes new-side } swap { current-key key-bytes } swap
dup key>bytes left 3array zip dup key>bytes 2array zip
] dip with-variables ; inline ] dip with-variables ; inline
! Extract the critical byte ! Extract the critical byte
@ -93,42 +93,9 @@ SYMBOL: new-side
! Tree insertion must be done by traversing the tree from the root, as it is ! Tree insertion must be done by traversing the tree from the root, as it is
! ordered. ! ordered.
! ! Insert a node at a leaf-node by first inserting a split node.
! : cb-insert ( value leaf-node -- node created? )
! [ current-key get swap <node> ] dip
! dup key>> key>bytes key-bytes get swap
! bytes-diff swap <cb-node>
! ! ( new-leaf old-leaf side cb-node -- )
! [ swap
! [ [ set-node-link ] keep
! set-node+link
! ] with-side
! ] keep t ;
! DEFER: cb-set
! ! Insert a node into a non-empty tree.
! : (cb-set) ( value parent node -- parent node created? )
! dup cb-node? [
! select-side [
! [ node-link (cb-set) ] keep
! swap [ [ set-node-link ] keep ] dip
! ] with-side
! ] [
! cb-insert
! ] if ;
! ! Insert a node into the tree
! : cb-set ( value node -- node created? )
! [ dup (cb-set) ] [ current-key get swap <node> t ] if* ;
! ** Walking the tree for the best fit ! ** Walking the tree for the best fit
! We need to remember the parent node as it will be the split node where our new GENERIC: cb-best-fit ( node -- node )
! value starts to differ, should it not be (key-)identical with the current
! node. Start with =f= as the parent.
GENERIC: cb-best-fit ( parent/f node -- node child )
M: f cb-best-fit ; M: f cb-best-fit ;
@ -136,61 +103,83 @@ M: node cb-best-fit ;
M: cb-node cb-best-fit M: cb-node cb-best-fit
select-side [ select-side [
nip dup node-link cb-best-fit node-link cb-best-fit
] with-side ; ] with-side ;
GENERIC: cb-update ( value parent/f node -- node created? ) GENERIC: cb-update ( value node -- node created? )
M: f cb-update M: f cb-update
2drop current-key get swap <node> t ; drop current-key get swap <node> t ;
! Attach a new leaf node and record =new-side=. New leaf node is attached
! opposite of =new-side=.
: attach-node ( value side cb-node -- cb-node ) : attach-node ( value side cb-node -- cb-node )
swap [ swap [ new-side set ] keep
[
[ current-key get swap <node> ] dip [ current-key get swap <node> ] dip
[ set-node+link ] keep [ set-node+link ] keep
] with-side ; ] with-side ;
! Update the tree by either updating a leaf node with a new key object and value
! or create a new split node and attach a fresh leaf node with the new key and
! value.
M: node cb-update M: node cb-update
dup key>> current-key get = [ dup key>> current-key get = [
current-key get >>key current-key get >>key
nip swap >>value f swap >>value f
] [ ] [
dup key>> key>bytes key-bytes get swap key>> key>bytes key-bytes get swap
bytes-diff swap <cb-node> bytes-diff swap <cb-node>
attach-node t attach-node t
] if ; ] if ;
GENERIC: cb-insert ( new-node cur-node -- node ) ! Break off the search when:
! - the top node is no longer a split node
! - the top split node is larger than the new split node (i.e. refers to a later
! byte or more significant bit in the current byte)
: break? ( new-node node -- ? )
{ [ nip cb-node? not ]
[ [ byte#>> ] bi@ < ]
[ { [ [ byte#>> ] bi@ = ]
[ [ bits>> ] bi@ < ]
} 2&& ]
} 2|| ;
M: f cb-insert drop ; ! Walk the tree and insert =new-node= at the pre-determined best place. We have
! to keep track of the parent instead of the current node, as we might need to
! relink from the parent to =new-node=.
GENERIC: cb-insert ( new-node parent -- )
M: node cb-insert M:: cb cb-insert ( n p -- )
new-side get [ p root>> :> c
swap [ set-node-link ] keep n c break?
[ n p root<<
new-side get [
c n set-node-link
] with-side
]
[ n c cb-insert ] if ;
M:: cb-node cb-insert ( n p -- )
p select-side [
drop
p node-link :> c
n c break?
[ n p set-node-link
new-side get [
c n set-node-link
] with-side
]
[ n c cb-insert ] if
] with-side ; ] with-side ;
M: cb-node cb-insert
2dup
[ [ [ byte#>> ] bi@ < ]
[ [ [ byte#>> ] bi@ = ]
[ [ bits>> ] bi@ <]
] 2&&
] 2|| [
! break
select-side [ set-node-link ] with-side
] [
! step down
] if
PRIVATE> PRIVATE>
M: cb set-at ( value key cb -- ) M: cb set-at ( value key cb -- )
[ swap [ swap [
[ ! ( value root -- new created? root ) [ root>> cb-best-fit cb-update ]
[ f swap cb-best-fit cb-update ] keep swap [ swap [ cb-insert t ] [ 2drop f ] if ] bi
[ cb-insert t ] [ 2nip f ] if ] with-key ] keep
] with-key swap ] change-root
swap [ dup inc-count ] when drop ; swap [ dup inc-count ] when drop ;
! ** Deletion ! ** Deletion