package com.rubiconproject.oss.kv.tuple;
/**
* Ordered set of elements.
* <p>
* You can use a tuple as a multi-valued key for hash-based or
* ordered collections. Tuples properly implement hashCode and
* equals to compare all items in the tuple with respect to order.
* As a key to an ordered collection, the tuple gives the first
* element precedence.
* <p>
* You can also use a tuple to return multiple values from a function.
* Use one of the shorthand types ({@link Tuple2}, {@link Tuple3}, etc.)
* as the return type for the function. Use one of the overloaded
* {@link Tuple#from(Object,Object)} methods to
* generate the tuple within the function. Use the {@link Tuple#extract(Variable)} method
* to fetch values from the tuple back in the caller.
*
* @author Michael L Perry
*
* @param <First> The type of the first element in the tuple.
* @param <Rest> The type of the tuple containing the rest of the elements.
*
*/
/*
* Copyright (c) 2008, Mallard Software Designs, Inc.
* http://mallardsoft.com
* All rights reserved.
*
* Redistribution and use of this software in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
public class Tuple<First extends Comparable<First>, Rest extends Comparable<Rest>> implements SeparatedAppender, Comparable<Tuple<First, Rest>> {
protected First first;
protected Rest rest;
protected Tuple(First first, Rest rest) {
this.first = first;
this.rest = rest;
}
/**
* Remove the first element from the tuple and return the rest.
* To extract all elements from the tuple, chain extract calls.
*
* @param m
* @return
*/
public Rest extract(Variable<First> m) {
m.set(first);
return rest;
}
public <T extends Comparable<T>> Tuple<T, Tuple<First, Rest>> prepend(T m) {
return new Tuple<T, Tuple<First, Rest>>(m, this);
}
// Compare two tuples. All elements must be equal.
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (obj == null)
return false;
if (!(obj instanceof Tuple))
return false;
Tuple<First, Rest> that = (Tuple<First, Rest>) obj;
return
(this.first == null ? that.first == null : this.first.equals(that.first)) &&
this.rest.equals(that.rest);
}
// Calculate a hash code based on the hash of each element.
public int hashCode() {
return (first == null ? 0 : first.hashCode()) + rest.hashCode() * 37;
}
public String toString() {
return toString("(", ", ", ")");
}
// Display the tuple using the open, separator, and close.
public String toString(String open, String separator, String close) {
StringBuffer result = new StringBuffer();
result.append(open).append(first);
((SeparatedAppender)rest).appendString(result, separator);
return result.append(close).toString();
}
public void appendString(StringBuffer buffer, String separator) {
buffer.append(separator).append(first);
((SeparatedAppender)rest).appendString(buffer, separator);
}
// Order by the most significant element first.
// The tuples must agree in size and type.
public int compareTo(Tuple<First, Rest> that) {
int compare = this.first.compareTo(that.first);
if (compare != 0)
return compare;
else
return this.rest.compareTo(that.rest);
}
public static <T1 extends Comparable<T1>> Tuple1<T1> from(T1 m1) {
return new Tuple1<T1>(m1);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>> Tuple2<T1, T2> from(T1 m1, T2 m2) {
return new Tuple2<T1, T2>(m1, m2);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>> Tuple3<T1, T2, T3> from(T1 m1, T2 m2, T3 m3) {
return new Tuple3<T1, T2, T3>(m1, m2, m3);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>> Tuple4<T1, T2, T3, T4> from(T1 m1, T2 m2, T3 m3, T4 m4) {
return new Tuple4<T1, T2, T3, T4>(m1, m2, m3, m4);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>> Tuple5<T1, T2, T3, T4, T5> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5) {
return new Tuple5<T1, T2, T3, T4, T5>(m1, m2, m3, m4, m5);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>> Tuple6<T1, T2, T3, T4, T5, T6> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5, T6 m6) {
return new Tuple6<T1, T2, T3, T4, T5, T6>(m1, m2, m3, m4, m5, m6);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>> Tuple7<T1, T2, T3, T4, T5, T6, T7> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5, T6 m6, T7 m7) {
return new Tuple7<T1, T2, T3, T4, T5, T6, T7>(m1, m2, m3, m4, m5, m6, m7);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>> Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5, T6 m6, T7 m7, T8 m8) {
return new Tuple8<T1, T2, T3, T4, T5, T6, T7, T8>(m1, m2, m3, m4, m5, m6, m7, m8);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>, T9 extends Comparable<T9>> Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5, T6 m6, T7 m7, T8 m8, T9 m9) {
return new Tuple9<T1, T2, T3, T4, T5, T6, T7, T8, T9>(m1, m2, m3, m4, m5, m6, m7, m8, m9);
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>, T9 extends Comparable<T9>, T10 extends Comparable<T10>> Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> from(T1 m1, T2 m2, T3 m3, T4 m4, T5 m5, T6 m6, T7 m7, T8 m8, T9 m9, T10 m10) {
return new Tuple10<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(m1, m2, m3, m4, m5, m6, m7, m8, m9, m10);
}
public static <T1 extends Comparable<T1>, Rest extends Comparable<Rest>> T1 get1(Tuple<T1, Rest> tuple) {
return tuple.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, Rest extends Comparable<Rest>> T2 get2(Tuple<T1, Tuple<T2, Rest>> tuple) {
return tuple.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, Rest extends Comparable<Rest>> T3 get3(Tuple<T1, Tuple<T2, Tuple<T3, Rest>>> tuple) {
return tuple.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, Rest extends Comparable<Rest>> T4 get4(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Rest>>>> tuple) {
return tuple.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, Rest extends Comparable<Rest>> T5 get5(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Rest>>>>> tuple) {
return tuple.rest.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, Rest extends Comparable<Rest>> T6 get6(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Tuple<T6, Rest>>>>>> tuple) {
return tuple.rest.rest.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, Rest extends Comparable<Rest>> T7 get7(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Tuple<T6, Tuple<T7, Rest>>>>>>> tuple) {
return tuple.rest.rest.rest.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>, Rest extends Comparable<Rest>> T8 get8(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Tuple<T6, Tuple<T7, Tuple<T8, Rest>>>>>>>> tuple) {
return tuple.rest.rest.rest.rest.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>, T9 extends Comparable<T9>, Rest extends Comparable<Rest>> T9 get9(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Tuple<T6, Tuple<T7, Tuple<T8, Tuple<T9, Rest>>>>>>>>> tuple) {
return tuple.rest.rest.rest.rest.rest.rest.rest.rest.first;
}
public static <T1 extends Comparable<T1>, T2 extends Comparable<T2>, T3 extends Comparable<T3>, T4 extends Comparable<T4>, T5 extends Comparable<T5>, T6 extends Comparable<T6>, T7 extends Comparable<T7>, T8 extends Comparable<T8>, T9 extends Comparable<T9>, T10 extends Comparable<T10>, Rest extends Comparable<Rest>> T10 get10(Tuple<T1, Tuple<T2, Tuple<T3, Tuple<T4, Tuple<T5, Tuple<T6, Tuple<T7, Tuple<T8, Tuple<T9, Tuple<T10, Rest>>>>>>>>>> tuple) {
return tuple.rest.rest.rest.rest.rest.rest.rest.rest.rest.first;
}
}