/******************************************************************************* * Copyright (c) 2007-2013 IBM Corporation & CWI * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * * * Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation * * Michael Steindorfer - Michael.Steindorfer@cwi.nl - CWI *******************************************************************************/ package org.rascalmpl.value.impl.reference; import java.util.Iterator; import org.rascalmpl.value.ITuple; import org.rascalmpl.value.IValue; import org.rascalmpl.value.exceptions.FactTypeUseException; import org.rascalmpl.value.impl.AbstractValue; import org.rascalmpl.value.type.Type; import org.rascalmpl.value.type.TypeFactory; import org.rascalmpl.value.visitors.IValueVisitor; class Tuple extends AbstractValue implements ITuple { protected final Type fType; protected final IValue[] fElements; /*package*/ Tuple(IValue... elements) { super(); this.fType = TypeFactory.getInstance().tupleType(elements); this.fElements = elements; } private Tuple(Tuple other, int i, IValue elem) { this.fType = other.getType(); fElements = other.fElements.clone(); fElements[i] = elem; } @Override public Type getType() { return fType; } @Override public <T, E extends Throwable> T accept(IValueVisitor<T, E> v) throws E { return v.visitTuple(this); } @Override public boolean isEqual(IValue other) { return equals(other); } /*package*/ Tuple(Type tupleType, IValue[] elems) { super(); this.fType = tupleType; this.fElements = elems; } @Override public Iterator<IValue> iterator() { return new Iterator<IValue>() { private int count = 0; @Override public boolean hasNext() { return count < arity(); } @Override public IValue next() { return get(count++); } @Override public void remove() { throw new UnsupportedOperationException("Can not remove elements from a tuple"); } }; } @Override public int hashCode() { int hash = 0; for (int i = 0; i < fElements.length; i++) { hash = (hash << 1) ^ (hash >> 1) ^ fElements[i].hashCode(); } return hash; } @Override public boolean equals(Object o) { if (this == o) { return true; } else if (o == null) { return false; } else if (getClass() == o.getClass()) { Tuple peer = (Tuple) o; if (!fType.comparable(peer.fType)) { return false; } int arity = arity(); if (arity != peer.arity()) { return false; } for (int i = 0; i < arity; i++) { if (!get(i).equals(peer.get(i))) { return false; } } return true; } return false; } @Override public IValue get(int i) throws IndexOutOfBoundsException { try { return fElements[i]; } catch (ArrayIndexOutOfBoundsException e) { throw new IndexOutOfBoundsException("Tuple index " + i + " is larger than tuple width " + arity()); } } @Override public IValue get(String label) throws FactTypeUseException { return fElements[fType.getFieldIndex(label)]; } @Override public ITuple set(int i, IValue arg) throws IndexOutOfBoundsException { return new Tuple(this, i, arg); } @Override public ITuple set(String label, IValue arg) throws FactTypeUseException { int i = fType.getFieldIndex(label); return new Tuple(this, i, arg); } @Override public int arity() { return fElements.length; } @Override public IValue select(int... fields) throws IndexOutOfBoundsException { Type type = fType.select(fields); if (type.isFixedWidth()) { return doSelect(type, fields); } return get(fields[0]); } @Override public IValue selectByFieldNames(String... fields) throws FactTypeUseException { Type type = fType.select(fields); if (type.isFixedWidth()) { int[] indexes = new int[fields.length]; int i = 0; for (String name : fields) { indexes[i] = type.getFieldIndex(name); } return doSelect(type, indexes); } return get(fields[0]); } private IValue doSelect(Type type, int... fields) throws IndexOutOfBoundsException { if (fields.length == 1) return get(fields[0]); IValue[] elems = new IValue[fields.length]; Type[] elemTypes = new Type[fields.length]; for (int i = 0; i < fields.length; i++) { elems[i] = get(fields[i]); elemTypes[i] = elems[i].getType(); } return new Tuple(TypeFactory.getInstance().tupleType(elemTypes), elems); } }