home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / sa104os2.zip / SATHR104.ZIP / SATHER / LIBRARY / FSET.SA < prev    next >
Text File  |  1995-02-05  |  13KB  |  345 lines

  1. -- Copyright (C) International Computer Science Institute, 1994.  COPYRIGHT  --
  2. -- NOTICE: This code is provided "AS IS" WITHOUT ANY WARRANTY and is subject --
  3. -- to the terms of the SATHER LIBRARY GENERAL PUBLIC LICENSE contained in    --
  4. -- the file "Doc/License" of the Sather distribution.  The license is also   --
  5. -- available from ICSI, 1947 Center St., Suite 600, Berkeley CA 94704, USA.  --
  6. --------> Please email comments to "sather-bugs@icsi.berkeley.edu". <----------
  7.  
  8. -- fset.sa: Hash-based sets of objects of type T.
  9. -------------------------------------------------------------------
  10. class FSET{T} is
  11.    -- Hash array based sets of objects of type T requiring writebacks.
  12.    -- 
  13.    -- If T is a subtype of $NIL{T}, then `nil' may not be an element,
  14.    -- otherwise the type's default value may not be a element.
  15.    -- 
  16.    -- If T is a subtype of $IS_EQ{T}, then `is_eq' will be used for
  17.    -- element equality (eg. string equality for STR), otherwise 
  18.    -- object equality is used.  Notice that in an FMAP{$OB}, unless
  19.    -- $IS_EQ{$OB} has been defined (_not_ $IS_EQ{K}), the equality
  20.    -- routine will not be used.
  21.    -- 
  22.    -- If T is a subtype of $HASH, then `hash' will be used for the hash
  23.    -- value, otherwise the element `id' will be used.
  24.    -- 
  25.    -- May be inherited with `elt_eq', `elt_nil', and `elt_hash' redefined
  26.    -- to get a different behavior.
  27.    -- 
  28.    -- The tables grow by amortized doubling and so require writeback
  29.    -- when inserting and deleting elements.
  30.    -- We keep the load factor at .5 to cut down on collision snowballing.
  31.    -- The simple collision resolution allows us to support deletions,
  32.    -- but makes the behavior with poor hash functions quadratic.
  33.    -- Puts a sentinel at the end of the table to avoid one check while
  34.    -- searching.
  35.  
  36.    include AREF{T};
  37.    
  38.    private attr hsize:INT;    -- Number of stored entries.
  39.    
  40.    invariant:BOOL is        
  41.       -- Class invariant.
  42.       return void(self) or hsize.is_bet(0,asize) end;
  43.    
  44.    elt_eq(e1,e2:T):BOOL is
  45.       -- True if `e1' is equal to `e2' for the semantics of this set.
  46.       -- If T descends from $IS_EQ{T}, use its `is_eq', otherwise use
  47.       -- object equality. Often redefined in descendants.
  48.       typecase e1
  49.       when $IS_EQ{T} then return e1.is_eq(e2) 
  50. --    else return SYS::ob_eq(e1,e2) end end;                                    -- NLP
  51.       else; end; return SYS::ob_eq(e1,e2); end;                                 -- NLP
  52.    
  53.    elt_nil:T is
  54.       -- The element used to represent an empty hash entry.
  55.       -- If T descends from $NIL{T}, use T::nil, otherwise use void. 
  56.       -- Often redefined in descendants.      
  57.       t:T; 
  58.       typecase t 
  59.       when $NIL{T} then return t.nil
  60. --    else return void end end;                                                 -- NLP
  61.       else; end; return void; end;                                              -- NLP
  62.    
  63.    elt_hash(e:T):INT is
  64.       -- The hash index into self for `e'. Must have the property that
  65.       -- two elements which are `elt_eq' have the same hash value. 
  66.       -- If T descends from $HASH use T::hash, otherwise use `id'.
  67.       -- Often redefined in descendants. Self mustn't be void.
  68.       typecase e 
  69.       when $HASH then return e.hash 
  70. --    else return SYS::id(e) end end;                                           -- NLP
  71.       else; end; return SYS::id(e); end;                                        -- NLP
  72.  
  73.    create:SAME is return void end;
  74.    
  75.    create(n:INT):SAME 
  76.       -- Make a table capable of dealing with `n' elements without
  77.       -- expansion. You can simply insert into a void table to create 
  78.       -- one as well. Self may be void (and usually is).
  79.       pre n>=1 is 
  80.       return allocate(1.lshift((3*n/2).highest_bit+1)+1) end;
  81.  
  82.    private allocate(n:INT):SAME is
  83.       -- Allocate `n' locations (must be power of 2 plus 1) and
  84.       -- initialize to `elt_nil'.
  85.       r::=new(n); 
  86.       if ~void(elt_nil) then loop r.aset!(elt_nil) end end;
  87.       return r end;
  88.    
  89.    size:INT is
  90.       -- Number of entries in the table. Self may be void.
  91. --    if void(self) then return 0 else return hsize end end;                    -- NLP
  92.       if void(self) then return 0; end; return hsize; end;                      -- NLP
  93.  
  94.    copy:SAME is
  95.       -- A copy of self.
  96.       r:SAME; loop r:=r.insert(elt!) end; return r end;
  97.    
  98.    elt!:T is
  99.       -- Yield the elements in self in an arbitrary order. Do not insert
  100.       -- or delete from self while calling this. Self may be void.
  101.       if ~void(self) then 
  102.      loop r::=aelt!; 
  103.         if ~elt_eq(r,elt_nil) then yield r end end end end;
  104.  
  105.    first_elt:T is
  106.       -- The first element in the table, if any, otherwise elt_nil.
  107.       if ~void(self) then 
  108.      loop r::=aelt!; 
  109.         if ~elt_eq(r,elt_nil) then return r end end end;
  110.       return elt_nil end;
  111.    
  112.    test(e:T):BOOL is
  113.       -- True if `e' is `elt_eq' to an element contained in self. 
  114.       -- Self may be void.
  115.       if void(self) then return false end;  
  116.       h::=elt_hash(e).band(asize-2);
  117.       loop te::=[h];  
  118.      if elt_eq(te,e) then return true
  119.      elsif elt_eq(te,elt_nil) then break! end;  
  120.      h:=h+1 end;
  121.       if h=asize-1 then        -- hit sentinel
  122.      h:=0;
  123.      loop te::=[h];
  124.         if elt_eq(te,e) then return true
  125.         elsif elt_eq(te,elt_nil) then break! end;  
  126.         h:=h+1 end;
  127.      assert h/=asize-1 end; -- table mustn't be filled
  128.       return false end;
  129.    
  130.    get(e:T):T is
  131.       -- If `e' is `elt_eq' to a table entry, return that entry, 
  132.       -- otherwise return `elt_nil'. Useful when different objects 
  133.       -- are treated as equal (eg. a table of strings used to get a 
  134.       -- unique representative for each class of equal strings).
  135.       -- Self may be void.
  136.       if void(self) then return elt_nil end;
  137.       h::=elt_hash(e).band(asize-2);    
  138.       loop te::=[h];
  139.      if elt_eq(te,e) then return te
  140.      elsif elt_eq(te,elt_nil) then break! end;
  141.      h:=h+1 end;
  142.       if h=asize-1 then h:=0;    -- hit sentinel
  143.      loop te::=[h];
  144.         if elt_eq(te,e) then return te
  145.         elsif elt_eq(te,elt_nil) then break! end;
  146.         h:=h+1 end;
  147.      assert h/=asize-1 end; -- table mustn't be filled
  148.       return elt_nil end;
  149.    
  150.    private double_size:SAME 
  151.       -- A new table of twice the size of self with self's entries
  152.       -- copied over. 
  153.       pre ~void(self) is
  154.       r::=allocate((asize-1)*2+1); 
  155.       loop r:=r.insert(elt!) end;
  156.       return r end;
  157.    
  158.    insert(e:T):SAME is
  159.       -- A possibly new table which includes `e'. If an entry 
  160.       -- is `elt_eq' to `e' then overwrite it with `e'.
  161.       -- Usage: `tbl:=tbl.insert(e)'. 
  162.       -- Creates a new table if void(self).
  163.       r::=self;
  164.       if void(r) then r:=allocate(5)
  165.       elsif (hsize+1)*2>asize then r:=double_size end;
  166.       asz::=r.asize;
  167.       h::=r.elt_hash(e).band(asz-2);
  168.       loop te::=r[h];
  169.      if elt_eq(te,elt_nil) then break!
  170.      elsif elt_eq(te,e) then r[h]:=e; return r end;
  171.      h:=h+1 end;
  172.       if h=asz-1 then h:=0;    -- hit sentinel
  173.      loop te::=r[h];
  174.         if elt_eq(te,elt_nil) then break!
  175.         elsif elt_eq(te,e) then r[h]:=e; return r end;
  176.         h:=h+1 end;
  177.      assert h/=asz-1 end; -- table mustn't be filled     
  178.       r[h]:=e; r.hsize:=r.hsize+1; return r end;
  179.    
  180.    private halve_size:SAME 
  181.       -- A new table of half the size of self with self's entries
  182.       -- copied over. 
  183.       pre ~void(self) and hsize<(asize-1)/4 is
  184.       r::=allocate((asize-1)/2+1);
  185.       loop r:=r.insert(elt!) end;
  186.       return r end;
  187.    
  188.    delete(e:T):SAME is
  189.       -- A possibly new table which deletes the element `e' if it
  190.       -- is contained in self. Doesn't modify the table if arg 
  191.       -- is not contained. Usage: `tbl:=tbl.delete(e)'.
  192.       -- Self may be void.
  193.       if void(self) then return void end;
  194.       h::=elt_hash(e).band(asize-2);
  195.       loop te::=[h];
  196.      if elt_eq(te,elt_nil) then return self
  197.      elsif elt_eq(te,e) then break! end;
  198.      if h=asize-2 then h:=0 else h:=h+1 end end;
  199.       [h]:=elt_nil; hsize:=hsize-1; i::=h; -- h is the index of arg
  200.      -- Now check the block after h for collisions.
  201.       loop 
  202.      if i=asize-2 then i:=0 else i:=i+1 end;
  203.      te::=[i];
  204.      if elt_eq(te,elt_nil) then break! end;
  205.      hsh::=elt_hash(te).band(asize-2);
  206.      if hsh<=i then        -- block doesn't wrap around
  207.         if h<i and h>=hsh then -- hole in way
  208.            [h]:=[i]; h:=i; [i]:=elt_nil end
  209.      else            -- block wraps
  210.         if h>=hsh or h<i then -- hole in way
  211.            [h]:=[i]; h:=i; [i]:=elt_nil end end end;
  212.       if asize>=33 and hsize<(asize-1)/4 then return halve_size
  213. --    else return self end end;                                                 -- NLP
  214.       end; return self; end;                                                    -- NLP
  215.  
  216.    clear:SAME is
  217.       -- Clear out self, return the space if it has 17 or less entries
  218.       -- otherwise return void. Self may be void.
  219.       if void(self) then return void end;
  220.       if asize<=17 then r::=self; r.hsize:=0;
  221.      loop r.aset!(elt_nil) end; return r
  222. --    else return void end end;                                                 -- NLP
  223.       end; return void; end;                                                    -- NLP
  224.  
  225.    is_empty:BOOL is        
  226.       -- True if the set is empty. Self may be void.
  227.       return (void(self)) or (hsize=0) end;
  228.    
  229.    is_eq(s:SAME):BOOL is    
  230.       -- True if `s' has the same elements as self. Self may be void.
  231.       loop if ~s.test(elt!) then return false end end;
  232.       loop if ~test(s.elt!) then return false end end;
  233.       return true end;
  234.    
  235.    is_disjoint_from(s:SAME):BOOL is
  236.       -- True if self and `s' have no elements in common.
  237.       -- Self may be void.
  238.       loop if s.test(elt!) then return false end end;
  239.       return true end;
  240.    
  241.    intersects(s:SAME):BOOL is
  242.       -- True if self and `s' have elements in common.
  243.       -- Self may be void.
  244.       return ~is_disjoint_from(s) end;
  245.    
  246.    is_subset(s:SAME):BOOL is
  247.       -- True if all elements of self are contained in `s'.
  248.       -- Self may be void.
  249.       loop if ~s.test(elt!) then return false end end;
  250.       return true end;
  251.    
  252.    to_union(s:SAME):SAME is
  253.       -- The union of self and `s', modifies self.
  254.       -- Self may be void.
  255.       r::=self; loop r:=r.insert(s.elt!) end; return r end;
  256.    
  257.    union(s:SAME):SAME is
  258.       -- A new set which is the union of self and `s'.
  259.       -- Self may be void.
  260.       return copy.to_union(s) end;
  261.    
  262.    to_intersect(s:SAME):SAME is
  263.       -- The intersection of self and `s', modifies self.
  264.       -- Self may be void.
  265.       r::=self; loop r:=r.delete(s.elt!) end; return r end;
  266.    
  267.    intersect(s:SAME):SAME is
  268.       -- A new set which is the intersection of self and s.
  269.       -- Self may be void.
  270.       r:SAME;
  271.       loop e::=elt!;
  272.      if s.test(e) then r:=r.insert(e) end end; return r end;
  273.    
  274.    to_difference(s:SAME):SAME is
  275.       -- The difference of self and `s', modifies self.
  276.       -- Self may be void.
  277.       r::=self; loop r:=r.delete(s.elt!) end; return r end;
  278.       
  279.    difference(s:SAME):SAME is
  280.       -- A new set which is the difference between self and `s'.
  281.       -- Self may be void.
  282.       r:SAME;
  283.       loop e::=elt!;
  284.      if ~s.test(e) then r:=r.insert(e) end end; 
  285.       return r end;
  286.    
  287.    to_sym_difference(s:SAME):SAME is
  288.       -- The symmetric difference of self and `s', modifies self.
  289.       -- Self may be void.
  290.       r::=self;
  291.       loop e::=s.elt!;
  292.      if r.test(e) then r:=r.delete(e)
  293.      else r:=r.insert(e) end end;
  294.       return r end;
  295.    
  296.    sym_difference(s:SAME):SAME is
  297.       -- A new set which is the symmetric difference between self 
  298.       -- and `s'. Self may be void.
  299.       r:SAME;
  300.       loop e::=elt!; 
  301.      if ~s.test(e) then r:=r.insert(e) end end;
  302.       loop e::=s.elt!; 
  303.      if ~test(e) then r:=r.insert(e) end end;
  304.       return r end;
  305.    
  306.    map(m:ROUT{T}:T):SAME is
  307.       -- A new set whose elements are `m' applied to those of self.
  308.       -- Self may be void.
  309.       r:SAME; loop r:=r.insert(m.call(elt!)) end; return r end;
  310.       
  311.    filter(t:ROUT{T}:BOOL):SAME is
  312.       -- A new set whose elements are those of self which satisfy `t'.
  313.       -- Self may be void.
  314.       r:SAME;
  315.       loop e::=elt!; if t.call(e) then r:=r.insert(e) end end; 
  316.       return r end;
  317.  
  318.    some(t:ROUT{T}:BOOL):BOOL is
  319.       -- True if some element of self satisfies `t'.
  320.       -- Self may be void.
  321.       loop if t.call(elt!) then return true end end;
  322.       return false end;
  323.  
  324.    every(t:ROUT{T}:BOOL):BOOL is
  325.       -- True if every element of self satisfies `t'.
  326.       -- Self may be void.
  327.       loop if ~t.call(elt!) then return false end end;
  328.       return true end;
  329.  
  330.    notany(t:ROUT{T}:BOOL):BOOL is
  331.       -- True if none of the elements of self satisfies `t'.
  332.       -- Self may be void.
  333.       loop if t.call(elt!) then return false end end;
  334.       return true end;
  335.    
  336.    notevery(t:ROUT{T}:BOOL):BOOL is
  337.       -- True if not every element of self satisfies `t'.
  338.       -- Self may be void.
  339.       loop if ~t.call(elt!) then return true end end;
  340.       return false end;
  341.    
  342. end -- class FSET{T}
  343.  
  344. -------------------------------------------------------------------
  345.