//----------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All Rights Reserved. // //----------------------------------------------------------------------------- namespace Microsoft.Boogie { using System; using System.IO; using System.Collections; using System.Collections.Generic; using System.Diagnostics.Contracts; /// /// A class representing a mathematical set. /// public class GSet : ICloneable, IEnumerable, IEnumerable { /*[Own]*/ Dictionary ht; List arr; // keep elements in a well-defined order; otherwise iteration is non-deterministic [ContractInvariantMethod] void ObjectInvariant() { Contract.Invariant(ht != null); Contract.Invariant(arr != null); Contract.Invariant(ht.Count == arr.Count); } public GSet() { ht = new Dictionary(); arr = new List(); //:base(); } private GSet(Dictionary/*!*/ ht, List arr) { Contract.Requires(ht != null); Contract.Requires(arr != null); this.ht = ht; this.arr = arr; //:base(); } public GSet(int capacity) { ht = new Dictionary(capacity); arr = new List(capacity); //:base(); } public readonly static GSet/*!*/ Empty = new GSet(); public void Clear() { ht.Clear(); arr.Clear(); } /// /// This method idempotently adds "o" to the set. /// In notation: /// this.SetElements = this.SetElements_old \union {o}; /// public void Add(T o) { if (!ht.ContainsKey(o)) { ht[o] = arr.Count; arr.Add(o); } } /// /// this.SetElements = this.SetElements_old \union s.GSetElements; /// public void AddRange(IEnumerable s) { foreach (T o in s) { Add(o); } } /// /// this.SetElements = this.SetElements_old \setminus {o}; /// public void Remove(T o) { int idx; if (ht.TryGetValue(o, out idx)) { var last = arr[arr.Count - 1]; arr.RemoveAt(arr.Count - 1); if (idx != arr.Count) { arr[idx] = last; ht[last] = idx; } ht.Remove(o); } } /// /// this.SetElements = this.SetElements_old \setminus s.SetElements; /// public void RemoveRange(IEnumerable s) { Contract.Requires(s != null); if (s == this) { ht.Clear(); arr.Clear(); } else { foreach (T o in s) { Remove(o); } } } /// /// Returns an arbitrary element from the set. /// public T Choose() { Contract.Requires((Count > 0)); foreach(var e in this) return e; return default(T); } /// /// Picks an arbitrary element from the set, removes it, and returns it. /// public T Take() { Contract.Requires((Count > 0)); Contract.Ensures(Count == Contract.OldValue(Count) - 1); T r = Choose(); Remove(r); return r; } public void Intersect(GSet/*!*/ s) { Contract.Requires(s != null); if (s == this) return; ht.Clear(); var newArr = new List(); foreach (T key in arr) { if (s.ht.ContainsKey(key)) { ht[key] = newArr.Count; newArr.Add(key); } } arr = newArr; } /// /// 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[T o] { get { 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(T o) { return this.ht.ContainsKey(o); } /// /// Returns true iff every element of "s" is an element of "this", that is, if /// "s" is a subset of "this". /// /// /// public bool ContainsRange(IEnumerable s) { Contract.Requires(s != null); if (s != this) { foreach (T key in s) { if (!this.ht.ContainsKey(key)) { return false; } } } return true; } public object/*!*/ Clone() { Contract.Ensures(Contract.Result() != null); return new GSet(new Dictionary(ht), new List(arr)); } public virtual int Count { get { return ht.Count; } } [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 + "}"; } } //----------------------------- Static Methods --------------------------------- // Functional Intersect public static GSet/*!*/ Intersect(GSet/*!*/ a, GSet/*!*/ b) { Contract.Requires(b != null); Contract.Requires(a != null); Contract.Ensures(Contract.Result>() != null); //Contract.Ensures(Contract.ForAll(result, x => a[x] && b[x] )); GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); res.Intersect(b); return res; } // Functional Union public static GSet/*!*/ Union(GSet/*!*/ a, GSet/*!*/ b) { Contract.Requires(a != null); Contract.Requires(b != null); Contract.Ensures(Contract.Result>() != null); // Contract.Ensures(Contract.ForAll(result, x => a[x] || b[x] )); GSet/*!*/ res = (GSet/*!*/)cce.NonNull(a.Clone()); res.AddRange(b); return res; } public delegate bool SetFilter(object/*!*/ obj); public static GSet/*!*/ Filter(GSet/*!*/ a, Func filter) { Contract.Requires(filter != null); Contract.Requires(a != null); Contract.Ensures(Contract.Result>() != null); GSet inter = new GSet(); foreach (T elem in a) { Contract.Assert(elem != null); if (filter(elem)) { inter.Add(elem); } } return inter; } public IEnumerator GetEnumerator() { return arr.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)arr).GetEnumerator(); } public bool AddAll(IEnumerable s) { foreach (T e in s) Add(e); return true; } } public interface IWorkList : ICollection { bool Add(object o); bool AddAll(IEnumerable objs); bool IsEmpty(); object Pull(); } }