All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.mit.csail.sdg.sim.SimTuple Maven / Gradle / Ivy

The newest version!
/* 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.sim;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Immutable; represents a tuple.
 * 

* Thread Safety: Safe. */ public final class SimTuple implements Iterable { /** Stores the tuple. */ private SimAtom[] array; /** If nonzero, it caches the hash code. */ private int hashCode = 0; /** * Construct a tuple backed by the given array as-is; thus the caller must not * modify it any more. */ private SimTuple(SimAtom[] array) { if (array.length == 0) throw new IllegalArgumentException(); this.array = array; } /** * Construct the n-ary tuple; throws an exception if the given list is empty. */ public static SimTuple make(List list) { if (list.size() == 0) throw new IllegalArgumentException(); SimAtom[] array = new SimAtom[list.size()]; for (int i = 0, n = list.size(); i < n; i++) { array[i] = list.get(i); } return new SimTuple(array); } /** Construct the binary tuple (a,b) */ public static SimTuple make(SimAtom a, SimAtom b) { return new SimTuple(new SimAtom[] { a, b }); } /** Construct the unary tuple containing the given atom. */ public static SimTuple make(SimAtom atom) { return new SimTuple(new SimAtom[] { atom }); } /** Construct the unary tuple containing the given atom. */ public static SimTuple make(String atom) { return new SimTuple(new SimAtom[] { SimAtom.make(atom) }); } /** * Construct the tuple containing the given list of atoms; the list must not be * empty. */ public static SimTuple make(String[] atoms) { SimAtom[] ans = new SimAtom[atoms.length]; for (int i = 0; i < atoms.length; i++) ans[i] = SimAtom.make(atoms[i]); return new SimTuple(ans); } /** Write this SimTuple as (".." ".." "..") */ void write(BufferedOutputStream out) throws IOException { out.write('('); for (int n = array.length, i = 0; i < n; i++) { if (i > 0) out.write(' '); array[i].write(out); } out.write(')'); } /** * Read a (".." ".." "..") tuple assuming the leading "(" has already been * consumed. */ static SimTuple read(BufferedInputStream in) throws IOException { List list = new ArrayList(); while (true) { int c = in.read(); if (c < 0) throw new IOException("Unexpected EOF"); if (c > 0 && c <= ' ') continue; // skip whitespace if (c == ')') break; if (c != '\"') throw new IOException("Expecting start of atom"); list.add(SimAtom.read(in)); c = in.read(); if (c < 0) throw new IOException("Unexpected EOF"); if (c == ')') break; if (!(c <= ' ')) throw new IOException("Expecting \')\' or white space after an atom."); } if (list.size() == 0) throw new IOException("Tuple arity cannot be 0."); return make(list); } /** Returns the arity of this tuple. */ public int arity() { return array.length; } /** Return the i-th atom from this tuple. */ public SimAtom get(int i) { return array[i]; } /** * Returns true if this tuple contains at least one occurrence of the given * atom. */ public boolean has(SimAtom atom) { for (int i = array.length - 1; i >= 0; i--) if (array[i] == atom) return true; return false; } /** * Replace the i-th atom, and return the resulting SimTuple. */ public SimTuple replace(int i, SimAtom newAtom) { if (array[i] == newAtom) return this; SimAtom ar[] = new SimAtom[array.length]; for (int j = 0; j < ar.length; j++) ar[j] = (j == i) ? newAtom : array[j]; return new SimTuple(ar); } /** * Replace each atom using the given SimAtom->SimAtom map; any atom not in the * map will stay unchanged. */ public SimTuple replace(Map map) { SimAtom[] newarray = new SimAtom[array.length]; for (int i = array.length - 1; i >= 0; i--) { SimAtom oldX = array[i]; SimAtom newX = map.get(oldX); newarray[i] = (newX == null ? oldX : newX); } return new SimTuple(newarray); } /** * Prepend the given atom to the front of this tuple, then return the resulting * new Tuple. */ public SimTuple prepend(SimAtom atom) { SimAtom[] newarray = new SimAtom[array.length + 1]; newarray[0] = atom; for (int i = 0; i < array.length; i++) newarray[i + 1] = array[i]; return new SimTuple(newarray); } /** * Append the given atom to the back of this tuple, then return the resulting * new Tuple. */ public SimTuple append(SimAtom atom) { SimAtom[] newarray = new SimAtom[array.length + 1]; for (int i = 0; i < array.length; i++) newarray[i] = array[i]; newarray[array.length] = atom; return new SimTuple(newarray); } /** Return the product of this tuple and that tuple. */ public SimTuple product(SimTuple that) { SimAtom[] c = new SimAtom[array.length + that.array.length]; // If // integer // overflows, // we'll // get // an // exception // here, // which // is // good for (int i = 0; i < this.array.length; i++) c[i] = array[i]; for (int i = 0; i < that.array.length; i++) c[i + array.length] = that.array[i]; return new SimTuple(c); } /** * Return the relational join of this tuple and that tuple; throws an exception * if the join point doesn't match or if both sides are unary. */ public SimTuple join(SimTuple that) { if (array.length + that.array.length == 2 || array[array.length - 1] != that.array[0]) throw new IllegalArgumentException(); SimAtom[] c = new SimAtom[array.length + that.array.length - 2]; // If // integer // overflows, // we'll // get // an // exception // here, // which // is // good for (int i = 0; i < this.array.length - 1; i++) c[i] = array[i]; for (int i = 0; i < that.array.length - 1; i++) c[i + array.length - 1] = that.array[i + 1]; return new SimTuple(c); } /** {@inheritDoc} */ @Override public int hashCode() { int ans = hashCode; if (ans == 0) { // We already know each SimAtom has been canonicalized, so just // computing its IdentityHashCode is faster for (int i = array.length - 1; i >= 0; i--) ans = ans * 31 + System.identityHashCode(array[i]); if (ans == 0) ans++; // so that we don't end up re-computing this SimTuple's // hashcode over and over again hashCode = ans; } return ans; } /** {@inheritDoc} */ @Override public boolean equals(Object that) { if (this == that) return true; else if (!(that instanceof SimTuple)) return false; SimAtom[] other = ((SimTuple) that).array; if (array == other) return true; else if (array.length != other.length) return false; if (hashCode() != that.hashCode()) return false; for (int i = array.length - 1; i >= 0; i--) if (array[i] != other[i]) return false; array = other; // Change it so we share the same array; this is thread safe since these // array contents are never mutated, // so it doesn't matter if some thread sees the old array and some sees // the new array. // JLS 3rd Edition 17.7 guarantees that writes and reads of references // are atomic though not necessarily visible, // so another thread will either see the old array or the new array. return true; } /** Returns the first atom of this tuple. */ public SimAtom head() { return array[0]; } /** Returns the last atom of this tuple. */ public SimAtom tail() { return array[array.length - 1]; } /** * Returns the subtuple containing the first n atoms (n must be between 1 and * arity) */ public SimTuple head(int n) { if (n <= 0 || n > array.length) throw new IllegalArgumentException(); else if (n == array.length) return this; SimAtom newtuple[] = new SimAtom[n]; for (int c = 0; c < newtuple.length; c++) newtuple[c] = array[c]; return new SimTuple(newtuple); } /** * Returns the subtuple containing the last n atoms (n must be between 1 and * arity) */ public SimTuple tail(int n) { if (n <= 0 || n > array.length) throw new IllegalArgumentException(); else if (n == array.length) return this; SimAtom newtuple[] = new SimAtom[n]; for (int a = array.length - n, c = 0; c < newtuple.length; c++) newtuple[c] = array[c + a]; return new SimTuple(newtuple); } /** * Write a human-readable representation of this tuple into the given * StringBuilder object. */ public void toString(StringBuilder sb) { for (int i = 0; i < array.length; i++) { if (i > 0) sb.append("->"); sb.append(array[i]); } } /** {@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(); toString(sb); return sb.toString(); } /** {@inheritDoc} */ @Override public Iterator iterator() { return new Iterator() { private int i = 0; // the next index to read out @Override public boolean hasNext() { return i < array.length; } @Override public SimAtom next() { if (i < array.length) { i++; return array[i - 1]; } else throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException(); } }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy