fmultimap.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> <--------------
class FMULTIMAP{KTP,ETP} < $STR
class FMULTIMAP{KTP,ETP} < $STR is
-- This class implements the mapping abstraction from a key to a list
-- (think set) of target elements.
-- NOTE 1. Unlike FMAP, this class is NOT meant to be used when void -- it
-- must be created initially.
--
-- 2. Most of the primitive FMAP routines have been made private and
-- renamed with a multi_ prefix.
--
-- 3. The routine danger_multi_get violates the strict interface
-- since it returns the ACTUAL flist associated with a particular key,
-- not a new copy. Any attempt to modify the list returned produces
-- results which are not defined.
-- Version 1.3 Nov 98. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 15 Apr 94 bg Original
-- 14 Jul 96 hk Modified for Sather 1.1
-- 26 Mar 97 kh Changed to CARD from INT
-- 9 Nov 98 kh Refined, added pre/post conditions.
private include FMAP_IMPL{KTP,FLIST{ETP}}
target! -> private multi_target!, -- Called in filter
pair! -> private multi_pair!, -- Called in double,etc
pairs! -> private pairs!,
targets! -> private targets!,
keys! -> private keys!, -- Obsolete
insert -> private multi_insert, -- used by insert_pair
insert_pair -> private multi_insert_pair,
create -> private old_create,
delete -> private multi_delete,
-- Unchanged private: key_eq, elt_nil,key_nil, is_key_nil, test
-- get_pair, delete
-- Publicly included
copy -> copy,
get -> danger_multi_get,-- Public, but DANGEROUS.
has_ind -> has_ind,
is_empty ->,
clear -> clear,
ind! -> ind!,
n_inds -> n_inds ;
include CONTAINER_STR{TUP{KTP,ETP}} ;
private include COMPARE{KTP}
elt_eq -> key_eq,
elt_lt -> ,
elt_hash -> key_hash,
elt_nil -> key_nil,
is_elt_nil -> is_key_nil ;
private const initially_provide_for : CARD := 1 ;
private attr total_n_targets : CARD ;
create : SAME is
-- This is the creation routine for a multi-map. It MUST be used
-- before any other operation on the map can be done.
me : SAME := old_create(2) ;
me.total_n_targets := 0 ;
return me
end ;
copy : SAME
pre ~void(self)
post true -- (result = self)
is
-- This routine returns a new copy of the map containing all of
-- the data in self.
res : SAME := old_create(size) ;
res.total_n_targets := 0 ;
loop
res := res.insert_pair(pair!)
end ;
res.hsize := hsize ;
return res
end ;
n_targets : CARD
pre ~void(self)
post (result = total_n_targets)
is
-- This routine returns the total number of targets in the map.
return total_n_targets
end ;
n_targets(
key : KTP
) : CARD
pre ~void(self)
post (has_ind(key)
and (result > 0))
or (~has_ind(key)
and (result = 0))
is
-- This routine returns the number of targets mapped from the given key.
if has_ind(key) then
return danger_multi_get(key).size
else
return 0
end
end ;
size : CARD is
-- This routine is an alias for n_targets to satisfy "CONTAINER{KTP}"
return n_targets
end ;
equals(
other : $RO_MULTIMAP{KTP,ETP}
) : BOOL is
-- This predicate returns true if and only if all of the elements of
-- other are equal to the elements of self.
-- NOTE Ordering is an issue. This routine should be redefined to be more
-- precise for particular descendants.
if size /= other.size then
return false
end ;
loop
elem : KTP := ind! ;
if n_targets(elem) /= other.n_targets(elem) then
return false
end
end ;
return true
end ;
has_pair(
key : KTP,
target : ETP
) : BOOL is
-- This predicate returns true if and only if the given key/target pair
-- is in the map.
if has_ind(key) then
return danger_multi_get(key).contains(target)
else
return false
end
end ;
private multi_insert_pair(
pairs : TUP{KTP,FLIST{ETP}}
) : SAME
pre ~void(self)
post (test(pairs.t1))
-- and (get(pairs.t1) = pairs.t2))
is
-- This routine returns a map in which all of the pairs have been
-- inserted.
return multi_insert(pairs.t1,pairs.t2)
end ;
private double_size : SAME
pre ~void(self)
post (result.size = initial(self.size))
and (result.asize = (initial(self.asize) - 1) * 2 + 1)
is
-- This routine returns a new map of twice the size of self containing
-- self's entries. This version of this routine supersedes the one included
-- from FMAP.
new_size : CARD := (asize - 1) * 2 + 1 ;
res : SAME := allocate(new_size) ;
loop
res := res.multi_insert_pair(multi_pair!)
end ;
res.total_n_targets := total_n_targets ;
SYS::destroy(self) ; -- old one should not be used now
return res
end ;
private halve_size : SAME
pre ~void(self)
and (hsize < (asize - 1) / 4)
post (result.size = initial(self.size))
and (result.asize = (initial(self.asize) - 1) / 2 + 1)
is
-- This routine returns a new map of half the size of self containing
-- self's entries. This version of this routine supersedes the one included
-- from FMAP.
new_size : CARD := (asize - 1) / 2 + 1 ;
res : SAME := allocate(new_size) ;
loop
res := res.multi_insert_pair(multi_pair!)
end ;
res.total_n_targets := total_n_targets ;
SYS::destroy(self) ; -- old one should not be used now
return res
end ;
insert(
key : KTP,
target : ETP
) : SAME
pre true
post ~void(result)
and (result.total_n_targets = (initial(total_n_targets) + 1))
is
-- This routine inserts the target given mapped from the key.
list : FLIST{ETP} ;
if has_ind(key) then
list := danger_multi_get(key)
else
list := FLIST{ETP}::create
end ;
list := list.push(target) ;
total_n_targets := total_n_targets + 1 ;
res : SAME := multi_insert(key,list) ;
return res
end ;
insert_pair(
pair : TUP{KTP,ETP}
) : SAME
pre true
post ~void(result)
and (result.total_n_targets = (initial(total_n_targets) + 1))
is
-- This routine inserts the given key/value pair into the map.
return insert(pair.t1,pair.t2)
end ;
delete(
key : KTP,
target : ETP
) : SAME
pre true
post ~void(result)
and ~(result.total_n_targets > initial(total_n_targets))
is
-- This routine deletes the target element from those mapped by the
-- given key if it is in the map range, otherwise do nothing.
list : FLIST{ETP} ;
if has_ind(key) then
list := danger_multi_get(key)
else
list := FLIST{ETP}::create
end ;
if ~list.contains(target) then -- do nothing
return self
end ;
list.delete_elt(target) ;
total_n_targets := total_n_targets - 1 ;
if list.size = 0 then
return multi_delete(key)
else
return multi_insert(key,list)
end
end ;
delete_all(
key : KTP
) : SAME
pre ~void(self)
post ~result.test(key)
is
-- This routine deletes all of the elements mapped by key.
if has_ind(key) then
return multi_delete(key)
end
end ;
get_all(
key : KTP
) : FLIST{ETP}
pre ~void(self)
post has_ind(key)
-- and (result = danger_multi_get(key)))
or (result.size = 0)
is
-- This routine returns a copy of the list of elements mapped by
-- the given key.
if has_ind(key) then
return danger_multi_get(key).copy
else
return FLIST{ETP}::create
end
end ;
target! : ETP
pre ~void(self)
post true -- ???????????
is
-- This iter yields all of the targets in the map in arbitrary order.
loop
target : FLIST{ETP} := multi_target! ;
loop
yield target.elt!
end
end
end ;
elt! : ETP
pre ~void(self)
post true -- ???????????
is
-- This iter is a synonym for target!
loop
yield target!
end
end ;
target!(
once key : KTP
) : ETP
pre true
post true -- (result = danger_multi_get(key)[ind!])
is
-- This iter yields all of the elements mapped by key in an arbitrary
-- sequence.
list : FLIST{ETP} ;
if has_ind(key) then
list := danger_multi_get(key)
else
list := FLIST{ETP}::create
end ;
loop
yield list.elt!
end
end ;
pair! : TUP{KTP, ETP}
pre ~void(self)
post test(result.t1)
is
-- This iter yields all key/target pairs in the map. The key may be
-- repeated if more than one element is mapped by it.
loop
pair : TUP{KTP,FLIST{ETP}} := multi_pair! ;
loop
yield TUP{KTP,ETP}::create(pair.t1,pair.t2.elt!)
end
end
end ;
end ; -- FMULTIMAP{KTP,ETP}