cit_util/src/Equivalence.mg


                                                                           
  Equivalence.ig                                                           
                                                                           
  Generic equivalence classes                                              
                                                                           
  Copyright (c) 2000 California Institute of Technology                    
  All rights reserved.                                                     
  Department of Computer Science                                           
  Pasadena, CA 91125.                                                      
                                                                           
  Author: Karl Papadantonakis <kp@caltech.edu                              
                                                                           
  Permission to use, copy, modify, and distribute this software            
  and its documentation for any purpose and without fee is hereby          
  granted, provided that the above copyright notice appear in all          
  copies. The California Institute of Technology makes no representations  
  about the suitability of this software for any purpose. It is            
  provided as is without express or implied warranty. Export of this     
  software outside of the United States of America may require an          
  export license.                                                          

GENERIC MODULE Equivalence(Elem, ElemElemTbl);

TYPE
  Public = T OBJECT METHODS
    init(sizeHint: CARDINAL := 0;
         leaderPreference: Preference := NIL): Default;
  END;

  PrivateIter = Iterator BRANDED "DefEquivIter(" & Elem.Brand & ")" OBJECT
    iter: ElemElemTbl.Iterator;
    tbl: Default;
  OVERRIDES
    next := Next;
  END;

REVEAL
  Default = Public BRANDED "DefEquiv(" & Elem.Brand & ")" OBJECT
    t: ElemElemTbl.T;
    p: Preference;
  OVERRIDES
    init := Init;
    equal := Equal;
    identify := Identify;
    canon := Canon;
    iterate := Iterate;
  END;

PROCEDURE Init(self: Default;
               sizeHint: CARDINAL := 0;
               leaderPreference: Preference := NIL): Default =
  BEGIN
    self.t := NEW(ElemElemTbl.Default).init(sizeHint);
    self.p := leaderPreference;
    RETURN self;
  END Init;

PROCEDURE Equal(self: Default; e1, e2: Elem.T): BOOLEAN =
  BEGIN
    RETURN Elem.Equal(Canon(self, e1), Canon(self, e2));
  END Equal;

PROCEDURE Identify(self: Default; e1, e2: Elem.T): BOOLEAN =
  VAR
    c1 := Canon(self, e1);
    c2 := Canon(self, e2);
    not: BOOLEAN;
  BEGIN
    IF Elem.Equal(c1, c2) THEN
      RETURN TRUE;
    ELSE
      IF self.p = NIL OR self.p.is(c2, c1) THEN
        not := self.t.put(c1, c2);
      ELSE
        not := self.t.put(c2, c1);
      END;
      <* ASSERT NOT not *>
      RETURN FALSE;
    END;
  END Identify;

PROCEDURE CanonNonMutating(self: Default; cur: Elem.T): Elem.T =
  BEGIN
    WHILE self.t.get(cur, cur) DO END;
    RETURN cur;
  END CanonNonMutating;

PROCEDURE Canon(self: Default; e: Elem.T): Elem.T =
  VAR
    cur := e;
    len := 0;
  BEGIN
    WHILE self.t.get(cur, cur) DO
      INC(len);
    END;
    (* path compression: *)
    IF len # 0 THEN
      WITH y = self.t.put(e, cur) DO <* ASSERT y *> END;
    END;
    RETURN cur;
  END Canon;

PROCEDURE Iterate(self: Default): Iterator =
  BEGIN
    RETURN NEW(PrivateIter, iter := self.t.iterate(), tbl := self);
  END Iterate;

PROCEDURE Next(self: PrivateIter; VAR alias, canon: Elem.T): BOOLEAN =
  VAR
    dummy: Elem.T;
    result := self.iter.next(alias, dummy);
  BEGIN
    canon := CanonNonMutating(self.tbl, alias);
    RETURN result;
  END Next;

BEGIN
END Equivalence.