/* Alloy Analyzer 4 -- Copyright (c) 2006-2009, Felix Chang
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package edu.mit.csail.sdg.alloy4compiler.translator;
import java.util.Iterator;
import java.util.NoSuchElementException;
import edu.mit.csail.sdg.alloy4.ErrorAPI;
import kodkod.instance.Tuple;
import kodkod.instance.TupleSet;
/** Immutable; represents a collection of Alloy tuples; comparison is by identity rather than by value. */
public final class A4TupleSet implements Iterable<A4Tuple> {
/** The Kodkod tupleset. */
private final TupleSet tuples;
/** The A4Solution that this came from. */
private final A4Solution sol;
/** Construct a TupleSet from the kodkod TupleSet, while renaming each atom using the atom2name map in sol.
* <br> NOTE: caller must ensure the Kodkod tupleset is not modified, since we expect the resulting A4Tupleset to be constant.
*/
A4TupleSet(TupleSet tuples, A4Solution sol) {
this.tuples = tuples;
this.sol = sol;
}
/** Return the underlying Kodkod tupleset. */
public TupleSet debugGetKodkodTupleset() { return tuples.clone(); }
/** Returns a read-only iterator that iterates over each tuple in this TupleSet. */
public Iterator<A4Tuple> iterator() {
return new Iterator<A4Tuple>() {
private final Iterator<Tuple> it = tuples.iterator();
public final boolean hasNext() { return it.hasNext(); }
public final A4Tuple next() {
if (!it.hasNext()) throw new NoSuchElementException();
return new A4Tuple(it.next(), sol);
}
public final void remove() { throw new UnsupportedOperationException(); }
};
}
/** Returns the arity. */
public int arity() { return tuples.arity(); }
/** Returns the number of tuples in this tuple set. */
public int size() { return tuples.size(); }
/** Construct a new tupleset as the product of this and that; this and that must be come from the same solution. */
public A4TupleSet product(A4TupleSet that) throws ErrorAPI {
if (sol != that.sol) throw new ErrorAPI("A4TupleSet.product() requires 2 tuplesets from the same A4Solution.");
return new A4TupleSet(tuples.product(that.tuples), sol);
}
/** Construct a new tupleset as the union of this and that; this and that must be come from the same solution.
* Note: if that==null, then the method returns this A4TupleSet as-is. */
public A4TupleSet plus(A4TupleSet that) throws ErrorAPI {
if (that==null) return this;
if (sol != that.sol) throw new ErrorAPI("A4TupleSet.plus() requires 2 tuplesets from the same A4Solution.");
if (arity() != that.arity()) throw new ErrorAPI("A4TupleSet.plus() requires 2 tuplesets with the same arity.");
if (this==that || tuples.size()==0) return that; else if (that.tuples.size()==0) return this; // special short cut
TupleSet ts = tuples.clone();
ts.addAll(that.tuples);
if (tuples.size()==ts.size()) return this;
if (that.tuples.size()==ts.size()) return that;
return new A4TupleSet(ts, sol);
}
/** Construct a new tupleset as the subtraction of this and that; this and that must be come from the same solution.
* Note: if that==null, then the method returns this A4TupleSet as-is. */
public A4TupleSet minus(A4TupleSet that) throws ErrorAPI {
if (that==null) return this;
if (sol != that.sol) throw new ErrorAPI("A4TupleSet.minus() requires 2 tuplesets from the same A4Solution.");
if (arity() != that.arity()) throw new ErrorAPI("A4TupleSet.minus() requires 2 tuplesets with the same arity.");
if (tuples.size()==0 || that.tuples.size()==0) return this; // special short cut
TupleSet ts = tuples.clone();
ts.removeAll(that.tuples);
if (tuples.size()!=ts.size()) return new A4TupleSet(ts, sol); else return this;
}
/** Construct a new tupleset as the intersection of this and that; this and that must be come from the same solution. */
public A4TupleSet intersect(A4TupleSet that) throws ErrorAPI {
if (sol != that.sol) throw new ErrorAPI("A4TupleSet.intersect() requires 2 tuplesets from the same A4Solution.");
if (arity() != that.arity()) throw new ErrorAPI("A4TupleSet.intersect() requires 2 tuplesets with the same arity.");
if (this.tuples.size()==0) return this; // special short cut
if (that.tuples.size()==0) return that; // special short cut
TupleSet ts = tuples.clone();
ts.retainAll(that.tuples);
if (tuples.size()!=ts.size()) return new A4TupleSet(ts, sol); else return this;
}
/** Prints a human-readable description of this TupleSet. */
@Override public String toString() {
StringBuilder sb=new StringBuilder("{");
for(A4Tuple t:this) {
if (sb.length()>1) sb.append(", ");
sb.append(t);
}
return sb.append('}').toString();
}
}