//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- namespace Microsoft.Boogie { using System; using System.IO; using System.Collections; using System.Diagnostics.Contracts; /// /// A class representing a mathematical set. /// public class Set : ICloneable, IEnumerable { /*[Own]*/ Hashtable ht; [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(ht != null); } public Set() { ht = new Hashtable(); //:base(); } private Set(Hashtable/*!*/ ht) { Contract.Requires(ht != null); this.ht = ht; //:base(); } public Set(int capacity) { ht = new Hashtable(capacity); //:base(); } public readonly static Set/*!*/ Empty = new Set(); public void Clear() { ht.Clear(); } /// /// This method idempotently adds "o" to the set. /// In notation: /// this.SetElements = this.SetElements_old \union {o}; /// public void Add(object/*!*/ o) { Contract.Requires(o != null); ht[o] = o; } /// /// this.SetElements = this.SetElements_old \union s.SetElements; /// public void AddRange(Set/*!*/ s) { Contract.Requires(s != null); foreach (object/*!*/ o in s) { Contract.Assert(o != null); Add(o); } } /// /// this.SetElements = this.SetElements_old \setminus {o}; /// public void Remove(object/*!*/ o) { Contract.Requires(o != null); ht.Remove(o); } /// /// this.SetElements = this.SetElements_old \setminus s.SetElements; /// public void RemoveRange(Set/*!*/ s) { Contract.Requires(s != null); if (s == this) { ht.Clear(); } else { foreach (object/*!*/ o in s) { Contract.Assert(o != null); ht.Remove(o); } } } /// /// Returns an arbitrary element from the set. /// public object/*!*/ Choose() { Contract.Requires((Count > 0)); Contract.Ensures(Contract.Result() != null); IEnumerator iter = GetEnumerator(); iter.MoveNext(); return cce.NonNull(iter.Current); } /// /// Picks an arbitrary element from the set, removes it, and returns it. /// public object/*!*/ Take() { Contract.Requires((Count > 0)); Contract.Ensures(Contract.Result() != null); Contract.Ensures(Count == Contract.OldValue(Count) - 1); object r = Choose(); Remove(r); return r; } public void Intersect(Set/*!*/ s) { Contract.Requires(s != null); Hashtable h = new Hashtable(ht.Count); foreach (object/*!*/ key in ht.Keys) { Contract.Assert(key != null); if (s.ht.ContainsKey(key)) { h.Add(key, key); } } ht = h; } /// /// The getter returns true iff "o" is in the set. /// The setter adds the value "o" (for "true") or removes "o" (for "false") /// public bool this[object/*!*/ o] { get { Contract.Requires(o != null); return ht.ContainsKey(o); } set { if (value) { Add(o); } else { Remove(o); } } } /// /// Returns true iff "o" is an element of "this". /// /// /// [Pure] public bool Contains(object/*!*/ o) { Contract.Requires(o != null); if (!this.ht.ContainsKey(o)) { return false; } return true; } /// /// Returns true iff every element of "s" is an element of "this", that is, if /// "s" is a subset of "this". /// /// /// public bool ContainsRange(Set/*!*/ s) { Contract.Requires(s != null); if (s != this) { foreach (object/*!*/ key in s.ht.Keys) { Contract.Assert(key != null); if (!this.ht.ContainsKey(key)) { return false; } } } return true; } public object/*!*/ Clone() { Contract.Ensures(Contract.Result() != null); return new Set((Hashtable/*!*/)cce.NonNull(ht.Clone())); } public virtual int Count { get { return ht.Count; } } [Pure] public IEnumerator/*!*/ GetEnumerator() { Contract.Ensures(Contract.Result() != null); return ht.Keys.GetEnumerator(); } [Pure] public override string/*!*/ ToString() { Contract.Ensures(Contract.Result() != null); string s = null; foreach (object/*!*/ key in ht.Keys) { Contract.Assert(key != null); if (s == null) { s = "{"; } else { s += ", "; } s += key.ToString(); } if (s == null) { return "{}"; } else { return s + "}"; } } public bool AddAll(IEnumerable/*!*/ objs) { Contract.Requires(objs != null); foreach (object/*!*/ o in objs) { Contract.Assert(o != null); this.Add(o); } return true; } //----------------------------- Static Methods --------------------------------- // Functional Intersect public static Set/*!*/ Intersect(Set/*!*/ a, Set/*!*/ b) { Contract.Requires(b != null); Contract.Requires(a != null); Contract.Ensures(Contract.Result() != null); //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); Set/*!*/ res = (Set/*!*/)cce.NonNull(a.Clone()); res.Intersect(b); return res; } // Functional Union public static Set/*!*/ Union(Set/*!*/ a, Set/*!*/ b) { Contract.Requires(a != null); Contract.Requires(b != null); Contract.Ensures(Contract.Result() != null); // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); Set/*!*/ res = (Set/*!*/)cce.NonNull(a.Clone()); res.AddRange(b); return res; } public delegate bool SetFilter(object/*!*/ obj); public static Set/*!*/ Filter(Set/*!*/ a, SetFilter/*!*/ filter) { Contract.Requires(filter != null); Contract.Requires(a != null); Contract.Ensures(Contract.Result() != null); Set inter = new Set(); foreach (object/*!*/ elem in a) { Contract.Assert(elem != null); if (filter(elem)) { inter.Add(elem); } } return inter; } } public interface IWorkList : ICollection { bool Add(object o); bool AddAll(IEnumerable objs); bool IsEmpty(); object Pull(); } }