h_multimap.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-------------------------> GNU Sather - sourcefile <-------------------------
-- Copyright (C) 1995 by International Computer Science Institute --
-- 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> <--------------
-- h_multimap.sa: Hash table based multimap
-- Author: Benedict A. Gomes <gomes@samosa.ICSI.Berkeley.EDU>
class MULTIMAP{ITP,TTP} < $MULTIMAP{ITP,TTP}
class MULTIMAP{ITP,TTP} < $MULTIMAP{ITP,TTP} is
include H_MULTIMAP_IMPL{ITP,TTP}
aset->aset,
delete->delete;
include MULTIMAP_INCL{ITP,TTP};
end;
class VMULTIMAP{ITP,TTP} < $VMULTIMAP{ITP,TTP}
class VMULTIMAP{ITP,TTP} < $VMULTIMAP{ITP,TTP} is
include H_MULTIMAP_IMPL{ITP,TTP}
aset->aset,
delete->delete;
include RO_MULTIMAP_INCL{ITP,TTP};
add(e:TUP{ITP,TTP}):SAME is
res ::= copy; res[e.t1] := e.t2; return res;
end;
delete(e:TUP{ITP,TTP}):SAME is
res ::= copy; res.delete(e.t1,e.t2); return res;
end;
delete_all(e:TUP{ITP,TTP}):SAME is
res ::= copy; res.delete_all(e.t1,e.t2); return res;
end;
is_eq(a:$OB):BOOL is
-- Return true if 'self' and 'v' have the same value
typecase a
when $RO_BAG{TUP{ITP,TTP}} then
if size /= a.size then return false; end;
loop e:TUP{ITP,TTP} := a.unique!;
if count(e)/=a.count(e) then return false; end;
end;
return true;
else return false end;
end;
hash:INT is
res:INT := 0; loop e ::= elt!; res := res.bxor(elt_hash(e)); end;
return res;
end;
end;
class H_MULTIMAP_IMPL{ITP,TTP}
class H_MULTIMAP_IMPL{ITP,TTP} is
-- Core of a multimap implementation based on the
-- DYNAMIC_DATABUCKET_TABLE. A multimap is a hash table from
-- indices to bags of targets
private include DYNAMIC_DATABUCKET_TABLE{ITP,BAG{TTP}}
create->create,
map_key!->ind!;
readonly attr total_size: INT;
size: INT is return total_size end;
copy: SAME pre ~void(self) is
-- The copy routine is not the same as that for a generic
-- DDT, since each of the "items" i.e. the bags has to
-- be copied as well
res ::= new;
res.store := store.create(store.asize);
res.asize := asize;
res.n_inds := n_inds;
res.minsize := minsize;
res.bound := bound;
res.doubles := doubles;
res.split_pos := split_pos;
loop
i ::= 0.upto!(asize-1);
res.store[i] := store[i].copy_list;
l ::= res.store[i];
loop li ::= l.list!; li.data := li.data.copy end;
end;
res.total_size := total_size;
return res
end;
n_targets(k:ITP): INT
pre ~void(self)
is
loop
b ::= bucket(hash(k)).list!;
if elt_key_eq(k,b.item) then
return b.data.size
end
end;
return 0
end;
has(e:TUP{ITP,TTP}):BOOL is return has(e.t1,e.t2) end;
has(k:ITP,e:TTP): BOOL
pre ~void(self)
is
loop
b ::= bucket(hash(k)).list!;
if elt_key_eq(k,b.item) then
return b.data.has(e)
end
end;
return false
end;
target!(once k:ITP): TTP
-- Return the values associated with "k"
pre ~void(self)
is
loop
b ::= bucket(hash(k)).list!;
if elt_key_eq(k,b.item) then
loop yield b.data.elt! end;
quit
end
end
end;
target!: TTP
pre ~void(self)
is
loop
b ::= bucket( 0.upto!(asize-1) );
loop
bk ::= b.list!;
loop yield bk.data.elt! end;
end
end
end;
elt!: TUP{ITP,TTP}
pre ~void(self)
is
loop
b ::= bucket( 0.upto!(asize-1) );
loop
bk ::= b.list!;
loop yield #(b.item,bk.data.elt!) end;
end;
end;
end;
aset(k:ITP,e:TTP)
-- Add the pair '(k,e)', even if it already exists
pre ~void(self)
is
h ::= hash(k);
loop
b ::= bucket(h).list!;
if elt_key_eq(b.item,k) then
ssize ::= b.data.size;
b.data.add(e); -- (ben) Changed from insert to add
if ssize < b.data.size then
total_size := total_size + 1
end;
return
end
end;
newset ::= #BAG{TTP};
newset.add(e); -- Changed from insert to add
set_bucket(h,#DATABUCKET{ITP,BAG{TTP}}(k,newset,bucket(h)));
total_size := total_size + 1;
n_inds := n_inds + 1;
update_insert
end;
delete(k:ITP,e:TTP)
-- Delete a single occurence of the key value pair(k,e)
pre ~void(self)
is
h: INT;
b,prev: DATABUCKET{ITP,BAG{TTP}};
h := hash(k);
b := bucket(h);
loop until!( void(b) );
if elt_key_eq(b.item,k) then
if b.data.has(e) then
total_size := total_size - 1;
if b.data.size > 1 then
b.data.delete(e)
else
if void(prev) then set_bucket(h,b.next)
else prev.next(b.next) end;
n_inds := n_inds - 1;
update_delete
end
end;
return
end;
prev := b;
b := b.next
end
end;
delete(k:ITP)
-- Delete all elements associated with element "k"
pre ~void(self)
is
dummy ::= map_delete(k);
total_size := total_size - dummy.size
end;
delete_all(k:ITP,e:TTP)
-- Delete all occurences of the key value pair(k,e) Not very
-- efficient version that just iterates through 'delete' until
-- convergence.
pre ~void(self)
is
old_n_targs:INT := n_targets(k);
loop delete(k,e);
new_n_targs:INT := n_targets(k);
until!(new_n_targs = old_n_targs);
old_n_targs := new_n_targs;
end;
end;
unique!:TUP{ITP,TTP} is
-- Yield the unique tuples in self. Currently converts into a
-- set and then yields the elements. Should be rewritten more
-- efficiently
s ::= #VSET{TUP{ITP,TTP}}(self);
loop yield s.elt!; end;
end;
end;