//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\
// 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) {}
}
}