//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // PLEASE DO NOT EDIT WITHOUT THE EXPLICIT CONSENT OF THE AUTHOR! \\ //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ using System; using System.Text; using System.Collections; namespace Ilog.Language.Util { /** * Extends Hashtable methods to allow safe "higher-order" maps (i.e., * Maps of Maps). Of course, testing and storing a Map will work only * if it is immutable (nothing more is put into or removed from it * after being initially filled). This is enforced by setting a lock * as soon as either Equals or GetHashCode is used on a given Map. * * @version Last modified on Sat May 21 10:56:49 2005 by hak * @author Hassan Aït-Kaci * @copyright © 2000 ILOG, S.A. */ public class Map : Hashtable { /** * Constructs a Map with default initial capacity. */ public Map () : base() {} /** * Constructs a Map with specified initial capacity */ public Map (int capacity) : base(capacity) {} /** * This indicates whether or not this Map is locked. */ private bool locked = false; public bool IsLocked { get { return locked; } } /** * Locks this Map to be immutable hence. */ public void Lock () { locked = true; } /** * This is a cache for this Map hash code. */ private int hashcode = 0; /** * Clears the contents of this map if it is not locked; * otherwise throws a LockedMapException. */ public override void Clear () { if (locked) throw new LockedMapException("Can't clear a locked Map"); base.Clear(); } /** * Indexers for this map, where the set indexer checks for lock * and throws a LockedMapException if so. */ public override object this [object o] { get { return base[o]; } set { if (locked) throw new LockedMapException("Can't modify a locked Map"); base[o] = value; } } /** * If this Map is not locked, removes the specified object and its * value; otherwise throws a LockedMapException. */ public override void Remove (object o) { if (locked) throw new LockedMapException("Can't remove from a locked Map"); base.Remove(o); } /** * Returns a hash code for this Map and locks it. */ public override int GetHashCode () { if (!locked) { locked = true; int count = 0; foreach (DictionaryEntry entry in this) { // Use the hash codes of the first 10 entries: if (++count > 10) break; hashcode ^= entry.GetHashCode(); } } return hashcode; } /** * Returns true iff the specified map contains the same entries as * this map. Both maps are locked as a side-effect of calling * this method. */ public override bool Equals (object other) { locked = true; if (this == other) return true; if (!(other is Map)) return false; Map that = (Map)other; that.locked = true; if (this.Count != that.Count) return false; foreach (DictionaryEntry entry in this) if (!entry.Value.Equals(that[entry.Key])) return false; return true; } /** * Returns a string represenation for this map. */ public override string ToString () { StringBuilder s = new StringBuilder("{"); String sep = ""; foreach (DictionaryEntry entry in this) { s.Append(sep).Append(entry.Key).Append("->").Append(entry.Value); sep = ", "; } return s.Append("}").ToString(); } } //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\ // Ancillary class /** * Signals that a map is locked on attempting to modify or test * it. */ public class LockedMapException : ApplicationException { /** * Constructs a new LockedMapException with no message. */ public LockedMapException () {} /** * Constructs a new LockedMapException with a message. */ public LockedMapException (string msg) : base(msg) {} } }