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}