/*
* Created on Apr 2, 2006
*
* Copyright (c) 2006, the JUNG Project and the Regents of the University
* of California
* All rights reserved.
*
* This software is open-source under the BSD license; see either
* "license.txt" or
* http://jung.sourceforge.net/license.txt for a description.
*/
package edu.uci.ics.jung.graph.util;
import java.io.Serializable;
import java.util.Collection;
import java.util.Iterator;
/**
* An implementation of <code>Collection</code> that stores exactly 2 non-null
* objects and is not mutable. They respect <code>equals</code> and may be used
* as indices or map keys.
* <p>
* Note that they do not protect from malevolent behavior: if one or another
* object in the tuple is mutable, then it can be changed with the usual bad
* effects.
*/
@SuppressWarnings("serial")
public final class Pair<T> implements Collection<T>, Serializable {
private T first;
private T second;
/**
* Creates a <code>Pair</code> from the specified elements.
*
* @param value1
* the first value in the new <code>Pair</code>
* @param value2
* the second value in the new <code>Pair</code>
* @throws IllegalArgumentException
* if either argument is null
*/
public Pair(T value1, T value2) {
if (value1 == null || value2 == null) {
throw new IllegalArgumentException(
"Pair cannot contain null values");
}
first = value1;
second = value2;
}
/**
* Creates a Pair from the passed Collection. The size of the Collection
* must be 2.
*
* @param values
* the elements of the new <code>Pair</code>
* @throws IllegalArgumentException
* if the input collection is null, contains null values, or has
* != 2 elements.
*/
public Pair(Collection<? extends T> values) {
if (values == null) {
throw new IllegalArgumentException(
"Input collection cannot be null");
}
if (values.size() == 2) {
if (values.contains(null)) {
throw new IllegalArgumentException(
"Pair cannot contain null values");
}
Iterator<? extends T> iter = values.iterator();
first = iter.next();
second = iter.next();
} else {
throw new IllegalArgumentException(
"Pair may only be created from a Collection of exactly 2 elements");
}
}
/**
* Creates a <code>Pair</code> from the passed array. The size of the array
* must be 2.
*
* @throws IllegalArgumentException
* if the input array is null, contains null values, or has != 2
* elements.
*/
public Pair(T[] values) {
if (values == null) {
throw new IllegalArgumentException("Input array cannot be null");
}
if (values.length == 2) {
if (values[0] == null || values[1] == null) {
throw new IllegalArgumentException(
"Pair cannot contain null values");
}
first = values[0];
second = values[1];
} else {
throw new IllegalArgumentException(
"Pair may only be created from an "
+ "array of 2 elements");
}
}
/**
* Returns the first element.
*/
public T getFirst() {
return first;
}
/**
* Returns the second element.
*/
public T getSecond() {
return second;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof Pair) {
Pair otherPair = (Pair) o;
Object otherFirst = otherPair.getFirst();
Object otherSecond = otherPair.getSecond();
return (this.first == otherFirst
|| (this.first != null && this.first.equals(otherFirst)))
&& (this.second == otherSecond || (this.second != null
&& this.second.equals(otherSecond)));
}
return false;
}
@Override
public int hashCode() {
int hashCode = 1;
hashCode = 31 * hashCode + (first == null ? 0 : first.hashCode());
hashCode = 31 * hashCode + (second == null ? 0 : second.hashCode());
return hashCode;
}
@Override
public String toString() {
return "<" + first.toString() + ", " + second.toString() + ">";
}
@Override
public boolean add(T o) {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public boolean addAll(Collection<? extends T> c) {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public void clear() {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public boolean contains(Object o) {
return (first == o || first.equals(o) || second == o
|| second.equals(o));
}
@Override
public boolean containsAll(Collection<?> c) {
if (c.size() > 2) {
return false;
}
Iterator<?> iter = c.iterator();
Object c_first = iter.next();
Object c_second = iter.next();
return this.contains(c_first) && this.contains(c_second);
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public Iterator<T> iterator() {
return new PairIterator();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
@Override
public int size() {
return 2;
}
@Override
public Object[] toArray() {
Object[] to_return = new Object[2];
to_return[0] = first;
to_return[1] = second;
return to_return;
}
@Override
@SuppressWarnings("unchecked")
public <S> S[] toArray(S[] a) {
S[] to_return = a;
if (a.length < 2) {
// TODO check
// to_return = (S[])java.lang.reflect.Array.newInstance(type, 2);
Object[] arr = new Object[2];
to_return = (S[]) arr;
}
to_return[0] = (S) first;
to_return[1] = (S) second;
if (to_return.length > 2) {
to_return[2] = null;
}
return to_return;
}
private class PairIterator implements Iterator<T> {
int position;
private PairIterator() {
position = 0;
}
@Override
public boolean hasNext() {
return position < 2;
}
@Override
public T next() {
position++;
if (position == 1) {
return first;
} else if (position == 2) {
return second;
} else {
return null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Pairs cannot be mutated");
}
}
}