tree_nodes.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-------------------------> GNU Sather - sourcefile <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute and/or modify it under the terms of the GNU Library General --
-- Public License (LGPL) as published by the Free Software Foundation; --
-- either version 2 of the license, or (at your option) any later version. --
-- This library 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 Doc/LGPL for more details. --
-- The license text is also available from: Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --
--------------> Please email comments to <bug-sather@gnu.org> <--------------
abstract class $BT_NODE{ KEY < $IS_LT{KEY}, ETP,
abstract class $BT_NODE{ KEY < $IS_LT{KEY}, ETP,
NODE < $BT_NODE{KEY,ETP,NODE} } is
-- This abstraction is for a standard balanced tree node. It provides
-- all of the expected operations.
-- Version 1.1 Mar 97. Copright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 22 Mar 95 hk Original
-- 13 Mar 97 kh Changed to CARD from INT
create : SAME ;
-- This routine creates an empty tree node.
create(
pair : TUP{KEY,ETP}
) : SAME ;
-- This creates a new node with the given key and data element.
is_eq(
other : NODE
) : BOOL ;
-- This predicate returns true if and only if self and other are equal,
-- otherwise false.
aget(
key : CARD
) : BT_NELEM{KEY,ETP,NODE} ;
-- This routine returns the node element 'indexed' by the key provided.
size : CARD ;
Min_Size : CARD ;
Max_Size : CARD ;
-- These three merely return properties of the node itself
set_item(
pos : CARD,
pair : TUP{KEY,ETP}
) ;
-- This routine sets the node in the given position to have the value
-- of pair.
set_node(
pos : CARD,
node : NODE
) ;
-- This routine sets the node in the given position to have the value
-- of node.
-- The following pairs of routines are used in testing node properties and insertion and deletion on the left (respectively right) node elements.
--
-- Free tests if the siblings have unused 'slots'
--
-- Spare tests if the siblings have spare (ie void) 'slots'
--
-- Push inserts space for a node into the balanced tree.
--
-- Pull deletes a node space from the tree.
--
-- Join attaches a sub-tree to the current node.
left_free(
stack : A_STACK{TUP{CARD,NODE}}
) : BOOL ;
right_free(
stack : A_STACK{TUP{CARD,NODE}}
) : BOOL ;
left_spare(
stack : A_STACK{TUP{CARD,NODE}}
) : BOOL ;
right_spare(
stack : A_STACK{TUP{CARD,NODE}}
) : BOOL ;
push_left(
elem : NODE,
pos : CARD,
stack:A_STACK{TUP{CARD,NODE}}
) ;
push_right(
elem : NODE,
pos : CARD,
stack : A_STACK{TUP{CARD,NODE}}
) ;
pull_left(
pos : CARD,
stack : A_STACK{TUP{CARD,NODE}}
) ;
pull_right(
pos : CARD,
stack : A_STACK{TUP{CARD,NODE}}
) ;
join_left(
pos : CARD,
stack : A_STACK{TUP{CARD,NODE}}
) ;
join_right(
pos : CARD,
stack : A_STACK{TUP{CARD,NODE}}
) ;
split(
elem : NODE,
pos : CARD
) : NODE ;
-- This routine splits self into two sub-trees, building a sub-tree
-- on the given element, which is then returned.
node_insert(
node : NODE,
pos : CARD
) ;
-- This routine carries out an actual insertion of the given node at the
-- position indicated.
node_delete(
pos : CARD
) ;
-- This routine deletes the node at the indicated position, rebalancing
-- the tree as necessary.
find_pred(
stack : A_STACK{TUP{CARD,NODE}}
) ;
-- This routine alters the stack so that the predecssor of the stack top
-- is at the top of the stack on exit.
find(
key : KEY,
stack :A_STACK{TUP{CARD,NODE}}
) : BOOL ;
-- This routine attempts to find the element with the given key. If it
-- is found it is on the top of the stack and true is returned, otherwise
-- false is returned.
ind! : KEY ;
-- This iter yields a sequence of the keys in the tree in order.
elt! : ETP ;
-- This iter yields a sequence of the node values on the tree in order.
pair! : TUP{KEY,ETP} ;
-- This iter yields the key/value pairs on the tree in order.
end ; -- $BT_NODE
immutable class BT_NELEM{KEY<$IS_LT{KEY}, ELT,
immutable class BT_NELEM{KEY<$IS_LT{KEY}, ELT,
NODE < $BT_NODE{ KEY, ELT, NODE } } is
-- This class is defined for internal use in BT_NODE to store nodes
-- and items efficiently.
-- Version 1.1 Mar 97. Copright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 22 Mar 95 hk Original
-- 13 Mar 97 kh Changed for style
attr node : NODE ;
attr item : TUP{ KEY, ELT } ;
create(
nod : NODE,
obj : TUP{KEY,ELT}
) : SAME is
-- This routine creates a new node element.
return node(nod).item(obj)
end ;
end ; -- BT_NELEM
class BT_NODE{ KEY < $IS_LT{KEY}, ELT } <
class BT_NODE{ KEY < $IS_LT{KEY}, ELT } <
$BT_NODE{KEY,ELT,BT_NODE{KEY,ELT}} is
-- This class is defined for internal use within the balanced tree
-- implementation. It is used to represent both the root and all other
-- internal nodes. The general structure of a node is
--
-- [0].node [0].item [1].node [1].item ... [k].node [k].item [k+1].node
-- ([k+1].item is always unused)
-- Version 1.2 Nov 98. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 22 Mar 95 hk Original
-- 13 Jan 97 kh Changed to CARD from INT
-- 12 Nov 98 kh Revised for 1.2, added pre/post conditions.
include AREF{BT_NELEM{KEY,ELT,SAME}}
aset->private aset ;
-- The array of items and nodes.
attr size : CARD ;
-- This attribute gives the current 'fill ratio' of the node.
const Max_Size : CARD := 4 ;
-- This constant gives the maximum number of element tuples at a node.
-- It must be EVEN and greater than 2!
const Min_Size : CARD := Max_Size / 2 ;
create : SAME is
-- This routine creates a new node with one more elements than Max_Size!
return new(Max_Size + 1)
end ;
create(
tuple : TUP{KEY,ELT}
) : SAME is
-- This routine creates a new node which contains the given key/element
-- tuple.
me : SAME := new(Max_Size + 1) ;
me.set_item(0, tuple) ;
me.size := 1 ;
return me
end ;
is_eq(
other : SAME
) : BOOL is
-- This predicate returns true if and only if self and same are
-- identical.
return SYS::ob_eq(self,other)
end ;
set_item(
pos : CARD,
tuple : TUP{KEY,ELT}
)
pre ~void(self)
and (pos <= Max_Size)
post true
is
-- This routine sets the indicated element of the array to have the
-- given node key/value pair.
[pos] := [pos].item(tuple)
end ;
set_node(
pos : CARD,
node : SAME
)
pre ~void(self)
and (pos <= Max_Size)
post true
is
-- This routine sets the indicated node to be node.
[pos] := [pos].node(node)
end ;
left_free(
stack : A_STACK{TUP{CARD,SAME}}
) : BOOL
pre ~void(stack.top)
and (stack.top.t2 /= self)
post true
is
-- This predicate returns true if and only if there is space for
-- additional nodes to the left.
parent : TUP{CARD,SAME} := stack.top ;
return (parent.t1 > 0)
and (parent.t2[parent.t1 - 1].node.size < Max_Size)
end ;
right_free(
stack : A_STACK{TUP{CARD,SAME}}
) : BOOL
pre ~void(stack.top)
and (stack.top.t2 /= self)
post true
is
-- This predicate returns true if and only if there is space for
-- additional nodes to the right.
parent : TUP{CARD,SAME} := stack.top ;
return (parent.t1 < parent.t2.size)
and (parent.t2[parent.t1 + 1].node.size < Max_Size)
end ;
left_spare(
stack : A_STACK{TUP{CARD,SAME}}
) : BOOL
pre ~void(stack.top)
and (stack.top.t2 /= self)
post true
is
-- This predicate returns true if and only if the left sibling has spare
-- space.
parent : TUP{CARD,SAME} := stack.top ;
return (parent.t1 > 0)
and (parent.t2[parent.t1-1].node.size > Min_Size)
end ;
right_spare(
stack : A_STACK{TUP{CARD,SAME}}
) : BOOL
pre ~void(stack.top)
and (stack.top.t2 /= self)
post true
is
-- This predicate returns true if and only if the right sibling has spare
-- space.
parent : TUP{CARD,SAME} := stack.top ;
return (parent.t1 < parent.t2.size)
and (parent.t2[parent.t1 + 1].node.size > Min_Size)
end ;
push_left(
elem : SAME,
pos : CARD, stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(self)
and (size = Max_Size)
post true --- ?????????
is
-- This routine inserts the given element at the indicated position in
-- stack.
parent,
left : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
left := parent[ppos - 1].node ;
left.set_item(left.size,parent[ppos - 1].item ) ;
if pos = 0 then -- item goes up
left.set_node(left.size + 1,elem[0].node) ;
parent.set_item(ppos - 1,elem[0].item) ;
set_node(0,elem[1].node)
else -- item[0] goes up, insert item
parent.set_item(ppos - 1,[0].item) ;
left.set_node(left.size + 1,[0].node) ;
loop -- Move the rest down one
index := 0.upto!(pos - 2) ;
[index] := [index + 1]
end ;
[pos - 1] := elem[0] ; -- attach the given element
set_node(pos,elem[1].node)
end ;
left.size := left.size + 1 -- adjust tree size.
end ;
push_right(
elem : SAME,
pos : CARD,
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(self)
and (size = Max_Size)
post true -- ??????????
is
-- This routine inserts the given element at the indicated position in
-- stack.
parent,
right : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
right := parent[ppos + 1].node ;
loop -- move up, creating needed space
index := right.size.downto!(0) ;
right[index + 1] := right[index]
end ;
right.set_item(0,parent[ppos].item ) ; -- Put it in!
if pos = size then -- item goes up
parent.set_item(ppos,elem[0].item) ;
set_node(size,elem[0].node) ;
right.set_node(0,elem[1].node)
else -- last goes up, item inserted.
parent.set_item(ppos,[size - 1].item) ;
right.set_node(0,[size].node) ;
set_node(size,[size - 1].node) ;
loop -- move up
index := (size - 2).downto!(pos) ;
[index + 1] := [index]
end ;
[pos] := elem[0] ;
set_node(pos + 1,elem[1].node)
end ;
right.size := right.size + 1 -- adjust size
end ;
split(
elem : SAME,
pos : CARD
) : SAME
pre ~void(self)
and (size = Max_Size)
post true ---?????????????
is
-- This routine splits the array at the indicated position, attaching
-- the portion split off to elem, which is then returned.
index : CARD ;
newNode : SAME := create ;
if pos <= Min_Size then -- item does not go right
loop -- to move sub-tree to newNode
index := Min_Size.upto!(size) ;
newNode[index - Min_Size] := [index] ;
[index] := void
end ;
if pos = Min_Size then -- item goes up
newNode.set_node(0,elem[1].node) ;
set_node(Min_Size,elem[0].node)
else -- item stays left
loop -- so move self up the array.
index := Min_Size.downto!(pos + 1) ;
[index] := [index - 1]
end ;
[pos] := elem[0] ; -- put it into place in self
set_node(pos + 1,elem[1].node) ;
elem.set_item(0,[Min_Size].item) ;
set_item(Min_Size,void) -- clear links in self
end
else -- item goes right
loop -- to fill elem
index := size.downto!(pos) ;
newNode[index - Min_Size] := [index] ;
[index] := void -- discard from self!
end ;
newNode.set_node(pos - Min_Size,elem[1].node) ;
newNode[pos - Min_Size - 1] := elem[0] ;
loop -- insert remainder in newNode
index := (pos - 1).downto!(Min_Size + 1) ;
newNode[index - Min_Size - 1] := [index] ;
[index] := void -- and clear from self!
end ;
elem.set_item(0,[Min_Size].item) ; -- establish 'root'
set_item(Min_Size,void)
end ;
size := Min_Size ;
newNode.size := Min_Size ;
elem.set_node(0,self) ; -- generate new node to insert
elem.set_node(1,newNode) ;
assert elem.size = 1 ;
return elem
end ;
node_insert(
node : SAME,
pos : CARD
)
pre ~void(self)
and (pos <= Max_Size)
and (size < Max_Size)
post true -- ??????????????
is
-- This routine inserts the given node at the indicated position.
index : CARD ;
loop
index := size.downto!(pos) ;
[index + 1] := [index]
end ;
[pos] := node[0] ;
set_node(pos + 1, node[1].node) ;
size := size + 1
end ;
pull_left(
pos : CARD,
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(stack)
and ~void(self)
post true -- ????????????????
is
-- This routine pulls the indicated element out of the stack LHS.
parent,
left : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
left := parent[ppos - 1].node ;
loop -- Move hole to LH end
index := pos.downto!(1) ;
[index] := [index - 1]
end ;
set_item(0,parent[ppos - 1].item) ; -- get from parent
set_node(0, left[size].node) ;
parent.set_item(ppos - 1,left[left.size - 1].item) ;
-- refill parent
left[left.size] := void ; -- leave to garbage collector
left.set_item(left.size - 1,void) ;
left.size := left.size - 1
end ;
pull_right(
pos : CARD,
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(stack)
and ~void(self)
post true -- ???????????????
is
-- This routine pulls the indicated element out of the stack RHS.
parent,
right : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
right := parent[ppos + 1].node ;
loop
index := pos.upto!(size - 1) ; -- Close hole.
[index] := [index + 1]
end ;
set_item(size - 1,parent[ppos].item) ; -- Get right end from parent.
set_node(size,right[0].node) ;
parent.set_item(ppos,right[0].item) ;
loop
index := 1.upto!(right.size) ;
right[index - 1] := right[index]
end ;
right[right.size] := void ; -- for garbage collector
right.size := right.size - 1
end ;
join_left(
pos : CARD,
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(stack)
and ~void(self)
and (size = Min_Size)
post true -- ????????????????
is
-- This routine makes a hole for the insertion of the left sibling.
parent,
left : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
left := parent[ppos - 1].node ;
assert left.size = Min_Size ;
loop -- Move hole to the left.
index := pos.downto!(1) ;
[index] := [index - 1]
end ;
set_node(0,left[left.size].node) ; -- Get from parent.
set_item(0,parent[ppos - 1].item) ;
loop -- Make BIG hole for left sibling
index := size.downto!( 0 ) ;
[index + Min_Size] := [index] -- [index + left.size] := [index]
end ;
loop -- put it in
index := 0.upto!(Min_Size - 1) ;
[index] := left[index]
end ;
parent.set_node(ppos - 1,self) ;
parent.set_item(ppos - 1,parent[ppos].item) ;
size := Max_Size
end ;
join_right(
pos : CARD,
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(stack)
and ~void(self)
and (size = Min_Size)
post true -- ????????????????
is
-- This routine makes a hole for the insertion of the right sibling.
parent,
right : SAME ;
index,
ppos : CARD ;
parent := stack.top.t2 ;
ppos := stack.top.t1 ;
right := parent[ppos + 1].node ;
assert right.size = Min_Size ;
loop -- Close hole
index := (pos + 1).upto!(size) ;
[index - 1] := [index]
end ;
set_item(size - 1,parent[ppos].item) ; -- Get from parent
loop -- Do joining
index := 0.upto!(right.size) ;
[size + index] := right[index]
end ;
parent.set_node(ppos + 1,self) ;
size := Max_Size
end ;
node_delete(
pos : CARD
)
pre ~void(self)
and (pos <= Max_Size)
post (size = initial(size - 1))
is
-- This routine is the one which actually deletes (removes) a node,
-- leaving the space for reclamation by the garbage collector.
index : CARD ;
loop
index := pos.upto!(size - 1) ;
[index] := [index + 1]
end ;
[size] := void ;
size := size - 1
end ;
find_pred(
stack : A_STACK{TUP{CARD,SAME}}
)
pre ~void(stack)
and ~void(self)
post true -- ???????????
is
-- This routine follows the link to the predecessor, which it then
-- leaves on the top of the stack.
node : SAME := stack.top.t2[stack.top.t1].node ;
loop
until!(void(node)) ;
stack.push(TUP{CARD,SAME}::create(node.size,node)) ;
node := node[node.size].node
end
end ;
find(
key : KEY,
stack : A_STACK{TUP{CARD,SAME}}
) : BOOL
pre ~void(stack)
and ~void(self)
post true
is
-- This predicate returns true if and only if a node with the given key
-- is present in the stack, otherwise false. If the node is present then it
-- is at the top of the stack.
if void(self) then
return false
end ;
loop
index : CARD := 0.upto!(size - 1) ;
if [index].item.t1 = key then
stack.push(TUP{CARD,SAME}::create(index,self)) ;
return true
elsif key < [index].item.t1 then
stack.push(TUP{CARD,SAME}::create(index,self)) ;
return ~void([index].node)
and [index].node.find(key,stack)
end
end ;
stack.push(TUP{CARD,SAME}::create(size,self)) ;
return ~void([size].node)
and [size].node.find(key,stack)
end ;
ind! : KEY
pre true
post true
is
-- This iter yields all of the individual key values in sequence.
if ~void(self) then
loop
index : CARD := 0.upto!(size) ;
loop
yield [index].node.ind!
end ;
if ~void([index].item) then
yield [index].item.t1
end
end
end
end ;
elt! : ELT
pre true
post true
is
-- This iter yields successive values of the node values in the tree.
if ~void(self) then
loop
index : CARD := 0.upto!(size) ;
loop
yield [index].node.elt!
end ;
if ~void([index].item) then
yield [index].item.t2
end
end
end
end ;
pair! : TUP{KEY,ELT}
pre true
post true
is
-- This iter yields successive values of the node key/value pairs in
-- the tree.
if ~void(self) then
loop
index : CARD := 0.upto!(size) ;
loop
yield [index].node.pair!
end ;
if ~void([index].item) then
yield [index].item
end
end
end
end ;
end ; -- BT_NODE