/******************************************************************************* * Copyright 2014 Felipe Takiyama * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package br.usp.poli.takiyama.common; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import br.usp.poli.takiyama.utils.Lists; public final class Tuple<E> implements Iterable<E> { private final List<E> values; private final int size; /* ************************************************************************ * Constructors * ************************************************************************/ private Tuple() { values = new ArrayList<E>(0); size = 0; } private Tuple(List<E> values) { this.values = new ArrayList<E>(values); this.size = values.size(); } /* ************************************************************************ * Static factories * ************************************************************************/ /** * Returns an empty tuple. * * @return an empty tuple. */ public static <E> Tuple<E> getInstance() { return new Tuple<E>(); } /** * Returns a tuple with the elements of the specified list, in the same * order. * * @param values A list of elements to put in the tuple * @return A tuple with the specified elements */ public static <E> Tuple<E> getInstance(List<E> values) { return new Tuple<E>(values); } public static <E> Tuple<E> getInstance(E ... values) { List<E> vals = Lists.listOf(values); return new Tuple<E>(vals); } /** * Returns a tuple with the elements of the specified tuple, in the same * order. * * @param t The tuple to copy * @return A copy of the specified tuple */ public static <E> Tuple<E> getInstance(Tuple<E> t) { return new Tuple<E>(t.values); } /** * Returns a tuple with one element. * * @param <E> The type of element to put in the tuple * @param value The value to put in the tuple * @return A tuple with the specified element */ public static <E> Tuple<E> getInstance(E value) { List<E> single = Lists.listOf(value); return new Tuple<E>(single); } /* ************************************************************************ * Getters * ************************************************************************/ /** * Returns the element at the specified position in this Tuple. * * @param index Index of the element to return. * @return Returns the element at the specified position in this tuple. */ public E get(int index) { return values.get(index); } /** * Returns a sub-tuple of this tuple between the specified * <code>fromIndex</code> (inclusive) and <code>toIndex</code>, (exclusive). * * @param fromIndex low end point (inclusive) of the sub-tuple * @param toIndex high end point (exclusive) of the sub-tuple * @return A sub-tuple of this tuple */ public Tuple<E> subTuple(int fromIndex, int toIndex) { // List<E> temp = new ArrayList<E>(toIndex - fromIndex); // for (int i = fromIndex; i < toIndex; i++) { // temp.add(values.get(i)); // } // return Tuple.getInstance(temp); return Tuple.getInstance(values.subList(fromIndex, toIndex)); } /** * Returns a sub-tuple of this tuple composed by the elements given * in the specified list of indexes. * <p> * For instance, let t = (0, 10, 20, 30) be a tuple. If we want the * sub-tuple given by indexes {0, 2} then this method would return * t' = (0, 20). * </p> * * @param indexes A list of indexes to extract from this tuple. * @return A sub-tuple of this tuple based on the list of indexes. */ public Tuple<E> subTuple(int[] indexes) { List<E> temp = new ArrayList<E>(values.size() - indexes.length); for (int i = 0; i < indexes.length; i++) { temp.add(get(indexes[i])); } return Tuple.getInstance(temp); } /** * Returns the number of elements in this tuple. * * @return The number of elements in this tuple. */ public int size() { return size;// values.size(); } /** * Returns <code>true</code> if this tuple contains no elements or is null. * * @return <code>True</code> if this tuple has no elements or is null, * <code>false</code> otherwise. */ public boolean isEmpty() { return (values == null || values.isEmpty()); } @Override public Iterator<E> iterator() { return values.iterator(); } /* ************************************************************************ * Setters * ************************************************************************/ /** * Removes the element at the specified index. All values to the right * of the index will be shifted to left. * * @see {@link ArrayList#remove} * @param index The index of the element to be removed. * @return A copy of this tuple with the element specified removed. */ public Tuple<E> remove(int index) { List<E> newValues = new ArrayList<E>(values); newValues.remove(index); return Tuple.getInstance(newValues); } /** * Replaces the element at the specified position in this tuple with the * specified element. The tuple is not modified, a new tuple is generated * instead. * @param index Index of the element to replace * @param element Element to be stored at the specified position * @return A new tuple with the element at the specified position replaced * by the specified element. */ public Tuple<E> set(int index, E element) { List<E> temp = new ArrayList<E>(values); temp.set(index, element); return Tuple.getInstance(temp); } /* ************************************************************************ * hashCode, equals and toString * ************************************************************************/ @Override public String toString() { return values.toString(); } @Override public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof Tuple)) return false; ListIterator<E> e1 = values.listIterator(); @SuppressWarnings("rawtypes") ListIterator e2 = ((Tuple) obj).values.listIterator(); while(e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1 == null ? o2 == null : o1.equals(o2))) return false; } return !(e1.hasNext() || e2.hasNext()); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((values == null) ? 0 : values.hashCode()); return result; } }