//-----------------------------------------------------------------------------
//
// 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