/* * ModeShape (http://www.modeshape.org) * * 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 org.modeshape.jcr.query; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.Iterator; import org.mapdb.Serializer; import org.modeshape.common.util.ObjectUtil; import org.modeshape.jcr.query.model.TypeSystem.TypeFactory; import org.modeshape.jcr.value.ValueFormatException; import org.modeshape.schematic.internal.HashCode; /** * A simple set of classes for working with tuples of data. * * @author Randall Hauch (rhauch@redhat.com) */ public class Tuples { private Tuples() { } /** * Create a tuple with the given two values. * * @param v1 the first value * @param v2 the second value * @return the tuple; never null */ public static <T1, T2> Tuple2<T1, T2> tuple( T1 v1, T2 v2 ) { return new Tuple2<>(v1, v2); } /** * Create a tuple with the given three values. * * @param v1 the first value * @param v2 the second value * @param v3 the third value * @return the tuple; never null */ public static <T1, T2, T3> Tuple3<T1, T2, T3> tuple( T1 v1, T2 v2, T3 v3 ) { return new Tuple3<>(v1, v2, v3); } /** * Create a tuple with the given four values. * * @param v1 the first value * @param v2 the second value * @param v3 the third value * @param v4 the fourth value * @return the tuple; never null */ public static <T1, T2, T3, T4> Tuple4<T1, T2, T3, T4> tuple( T1 v1, T2 v2, T3 v3, T4 v4 ) { return new Tuple4<>(v1, v2, v3, v4); } /** * Create a tuple with the given values. Note that this always creates a n-ary tuple, so use {@link #tuple(Object, Object)}, * {@link #tuple(Object, Object, Object)} or {@link #tuple(Object, Object, Object, Object)} for tuples smaller than 5. * * @param values the values * @return the tuple; never null */ public static TupleN tuple( Object[] values ) { return new TupleN(values); } /** * Create a type factory for tuples of size 2. * * @param type1 the first type; may not be null * @param type2 the second type; may not be null * @return the type factory; never null */ public static <T1, T2> TypeFactory<Tuple2<T1, T2>> typeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2 ) { return new Tuple2TypeFactory<>(type1, type2); } /** * Create a type factory for tuples of size 3. * * @param type1 the first type; may not be null * @param type2 the second type; may not be null * @param type3 the third type; may not be null * @return the type factory; never null */ public static <T1, T2, T3> TypeFactory<Tuple3<T1, T2, T3>> typeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2, TypeFactory<T3> type3 ) { return new Tuple3TypeFactory<>(type1, type2, type3); } /** * Create a type factory for tuples of size 4. * * @param type1 the first type; may not be null * @param type2 the second type; may not be null * @param type3 the third type; may not be null * @param type4 the fourth type; may not be null * @return the type factory; never null */ public static <T1, T2, T3, T4> TypeFactory<Tuple4<T1, T2, T3, T4>> typeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2, TypeFactory<T3> type3, TypeFactory<T4> type4 ) { return new Tuple4TypeFactory<>(type1, type2, type3, type4); } /** * Create a type factory for n-ary tuples. * * @param types the collection of types for each slot in the tuple * @return the type factory; never null */ public static TypeFactory<?> typeFactory( Collection<TypeFactory<?>> types ) { return new TupleNTypeFactory(types); } /** * Create a type factory for uniform tuples. * * @param type the type of each/every slot in the tuples * @param tupleSize the size of the tuples * @return the type factory; never null */ public static TypeFactory<?> typeFactory( TypeFactory<?> type, int tupleSize ) { if (tupleSize <= 1) return type; if (tupleSize == 2) return typeFactory(type, type); if (tupleSize == 3) return typeFactory(type, type, type); if (tupleSize == 4) return typeFactory(type, type, type, type); Collection<TypeFactory<?>> types = new ArrayList<>(tupleSize); for (int i = 0; i != tupleSize; ++i) { types.add(type); } return new TupleNTypeFactory(types); } /** * Create a {@link Serializer} for tuples of size 2. * * @param first the serializer for the first slot * @param second the serializer for the second slot * @return the serializer; never null */ public static <T1, T2> Serializer<Tuple2<T1, T2>> serializer( Serializer<T1> first, Serializer<T2> second ) { return new Tuple2Serializer<>(first, second); } /** * Create a {@link Serializer} for tuples of size 3. * * @param first the serializer for the first slot * @param second the serializer for the second slot * @param third the serializer for the third slot * @return the serializer; never null */ public static <T1, T2, T3> Serializer<Tuple3<T1, T2, T3>> serializer( Serializer<T1> first, Serializer<T2> second, Serializer<T3> third ) { return new Tuple3Serializer<>(first, second, third); } /** * Create a {@link Serializer} for tuples of size 4. * * @param first the serializer for the first slot * @param second the serializer for the second slot * @param third the serializer for the third slot * @param fourth the serializer for the fourth slot * @return the serializer; never null */ public static <T1, T2, T3, T4> Serializer<Tuple4<T1, T2, T3, T4>> serializer( Serializer<T1> first, Serializer<T2> second, Serializer<T3> third, Serializer<T4> fourth ) { return new Tuple4Serializer<>(first, second, third, fourth); } /** * Create a {@link Serializer} for n-ary tuples * * @param serializers the serializers for each slot in the tuples * @return the serializer; never null */ public static Serializer<TupleN> serializer( Serializer<?>[] serializers ) { return new TupleNSerializer(serializers); } /** * Create a {@link Serializer} for uniform tuples. * * @param serializer the serializer of each/every slot in the tuples * @param tupleSize the size of the tuples * @return the type factory; never null */ public static Serializer<?> serializer( Serializer<?> serializer, int tupleSize ) { if (tupleSize <= 1) return serializer; if (tupleSize == 2) return serializer(serializer, serializer); if (tupleSize == 3) return serializer(serializer, serializer, serializer); if (tupleSize == 4) return serializer(serializer, serializer, serializer, serializer); Serializer<?>[] serializers = new Serializer<?>[tupleSize]; Arrays.fill(serializers, serializer); return new TupleNSerializer(serializers); } public static final class Tuple2Serializer<T1, T2> implements Serializer<Tuple2<T1, T2>>, Serializable { private static final long serialVersionUID = 1L; private final Serializer<T1> serializer1; private final Serializer<T2> serializer2; public Tuple2Serializer( Serializer<T1> serializer1, Serializer<T2> serializer2 ) { this.serializer1 = serializer1; this.serializer2 = serializer2; } @Override public int fixedSize() { return 1; // not fixed size } @Override public void serialize( DataOutput out, Tuple2<T1, T2> value ) throws IOException { serializer1.serialize(out, value.v1); serializer2.serialize(out, value.v2); } @Override public Tuple2<T1, T2> deserialize( DataInput in, int available ) throws IOException { T1 v1 = serializer1.deserialize(in, available); T2 v2 = serializer2.deserialize(in, available); return tuple(v1, v2); } } public static final class Tuple3Serializer<T1, T2, T3> implements Serializer<Tuple3<T1, T2, T3>>, Serializable { private static final long serialVersionUID = 1L; private final Serializer<T1> serializer1; private final Serializer<T2> serializer2; private final Serializer<T3> serializer3; public Tuple3Serializer( Serializer<T1> serializer1, Serializer<T2> serializer2, Serializer<T3> serializer3 ) { this.serializer1 = serializer1; this.serializer2 = serializer2; this.serializer3 = serializer3; } @Override public int fixedSize() { return 1; // not fixed size } @Override public void serialize( DataOutput out, Tuple3<T1, T2, T3> value ) throws IOException { serializer1.serialize(out, value.v1); serializer2.serialize(out, value.v2); serializer3.serialize(out, value.v3); } @Override public Tuple3<T1, T2, T3> deserialize( DataInput in, int available ) throws IOException { T1 v1 = serializer1.deserialize(in, available); T2 v2 = serializer2.deserialize(in, available); T3 v3 = serializer3.deserialize(in, available); return tuple(v1, v2, v3); } } public static final class Tuple4Serializer<T1, T2, T3, T4> implements Serializer<Tuple4<T1, T2, T3, T4>>, Serializable { private static final long serialVersionUID = 1L; private final Serializer<T1> serializer1; private final Serializer<T2> serializer2; private final Serializer<T3> serializer3; private final Serializer<T4> serializer4; public Tuple4Serializer( Serializer<T1> serializer1, Serializer<T2> serializer2, Serializer<T3> serializer3, Serializer<T4> serializer4 ) { this.serializer1 = serializer1; this.serializer2 = serializer2; this.serializer3 = serializer3; this.serializer4 = serializer4; } @Override public int fixedSize() { return 1; // not fixed size } @Override public void serialize( DataOutput out, Tuple4<T1, T2, T3, T4> value ) throws IOException { serializer1.serialize(out, value.v1); serializer2.serialize(out, value.v2); serializer3.serialize(out, value.v3); serializer4.serialize(out, value.v4); } @Override public Tuple4<T1, T2, T3, T4> deserialize( DataInput in, int available ) throws IOException { T1 v1 = serializer1.deserialize(in, available); T2 v2 = serializer2.deserialize(in, available); T3 v3 = serializer3.deserialize(in, available); T4 v4 = serializer4.deserialize(in, available); return tuple(v1, v2, v3, v4); } } public static final class TupleNSerializer implements Serializer<TupleN>, Serializable { private static final long serialVersionUID = 1L; private final Serializer<Object>[] serializers; private final int size; @SuppressWarnings( "unchecked" ) public TupleNSerializer( Serializer<?>[] serializers ) { this.serializers = (Serializer<Object>[])serializers; this.size = serializers.length; } @Override public int fixedSize() { return 1; // not fixed size } @Override public void serialize( DataOutput out, TupleN value ) throws IOException { for (int i = 0; i != size; ++i) { serializers[i].serialize(out, value.values[i]); } } @Override public TupleN deserialize( DataInput in, int available ) throws IOException { Object[] values = new Object[size]; for (int i = 0; i != size; ++i) { values[i] = serializers[i].deserialize(in, available); } return tuple(values); } } @SuppressWarnings( "unchecked" ) protected static int compareValues( Object value1, Object value2 ) { if (value1 == null) { return value2 == null ? 0 : -1; } return value2 == null ? 1 : ((Comparable<Object>)value1).compareTo(value2); } public static final class Tuple2<T1, T2> implements Comparable<Tuple2<T1, T2>> { public final T1 v1; public final T2 v2; private final int hc; public Tuple2( T1 v1, T2 v2 ) { this.v1 = v1; this.v2 = v2; this.hc = HashCode.compute(v1, v2); } @Override public int compareTo( Tuple2<T1, T2> that ) { if (that == this) return 0; int diff = compareValues(this.v1, that.v1); if (diff != 0) return diff; return compareValues(this.v2, that.v2); } @Override public int hashCode() { return hc; } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof Tuple2) { Tuple2<?, ?> that = (Tuple2<?, ?>)obj; return ObjectUtil.isEqualWithNulls(this.v1, that.v1) && ObjectUtil.isEqualWithNulls(this.v2, that.v2); } return false; } @Override public String toString() { return "<" + v1 + "," + v2 + ">"; } } public static final class Tuple3<T1, T2, T3> implements Comparable<Tuple3<T1, T2, T3>> { public final T1 v1; public final T2 v2; public final T3 v3; private final int hc; public Tuple3( T1 v1, T2 v2, T3 v3 ) { this.v1 = v1; this.v2 = v2; this.v3 = v3; this.hc = HashCode.compute(v1, v2, v3); } @Override public int compareTo( Tuple3<T1, T2, T3> that ) { if (that == this) return 0; int diff = compareValues(this.v1, that.v1); if (diff != 0) return diff; diff = compareValues(this.v2, that.v2); if (diff != 0) return diff; return compareValues(this.v3, that.v3); } @Override public int hashCode() { return hc; } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof Tuple3) { Tuple3<?, ?, ?> that = (Tuple3<?, ?, ?>)obj; return ObjectUtil.isEqualWithNulls(this.v1, that.v1) && ObjectUtil.isEqualWithNulls(this.v2, that.v2) && ObjectUtil.isEqualWithNulls(this.v3, that.v3); } return false; } @Override public String toString() { return "<" + v1 + "," + v2 + "," + v3 + ">"; } } public static final class Tuple4<T1, T2, T3, T4> implements Comparable<Tuple4<T1, T2, T3, T4>> { public final T1 v1; public final T2 v2; public final T3 v3; public final T4 v4; private final int hc; public Tuple4( T1 v1, T2 v2, T3 v3, T4 v4 ) { this.v1 = v1; this.v2 = v2; this.v3 = v3; this.v4 = v4; this.hc = HashCode.compute(v1, v2, v3, v4); } @Override public int compareTo( Tuple4<T1, T2, T3, T4> that ) { if (that == this) return 0; int diff = compareValues(this.v1, that.v1); if (diff != 0) return diff; diff = compareValues(this.v2, that.v2); if (diff != 0) return diff; diff = compareValues(this.v3, that.v3); if (diff != 0) return diff; return compareValues(this.v4, that.v4); } @Override public int hashCode() { return hc; } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof Tuple4) { Tuple4<?, ?, ?, ?> that = (Tuple4<?, ?, ?, ?>)obj; return ObjectUtil.isEqualWithNulls(this.v1, that.v1) && ObjectUtil.isEqualWithNulls(this.v2, that.v2) && ObjectUtil.isEqualWithNulls(this.v3, that.v3) && ObjectUtil.isEqualWithNulls(this.v4, that.v4); } return false; } @Override public String toString() { return "<" + v1 + "," + v2 + "," + v3 + "," + v4 + ">"; } } public static final class TupleN implements Comparable<TupleN> { protected final Object[] values; private final int hc; public TupleN( Object[] values ) { this.values = values; this.hc = HashCode.compute(values); } @Override public int compareTo( TupleN that ) { if (that == this) return 0; int diff = this.values.length - that.values.length; if (diff != 0) return diff; for (int i = 0; i != values.length; ++i) { diff = compareValues(this.values[i], that.values[i]); if (diff != 0) return diff; } return 0; } @Override public int hashCode() { return hc; } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof TupleN) { TupleN that = (TupleN)obj; if (this.values.length == that.values.length) { for (int i = 0; i != values.length; ++i) { if (ObjectUtil.isEqualWithNulls(this.values[i], that.values[i])) return false; } return true; } } return false; } @Override public String toString() { return Arrays.toString(values); } } public interface TupleFactory<T> { Serializer<T> getSerializer( BufferManager bufferMgr ); } protected static final class Tuple2Comparator<T1, T2> implements Comparator<Tuple2<T1, T2>>, Serializable { private static final long serialVersionUID = 1L; private final Comparator<T1> comparator1; private final Comparator<T2> comparator2; protected Tuple2Comparator( Comparator<T1> comparator1, Comparator<T2> comparator2 ) { this.comparator1 = comparator1; this.comparator2 = comparator2; } @Override public int compare( Tuple2<T1, T2> arg0, Tuple2<T1, T2> arg1 ) { int diff = comparator1.compare(arg0.v1, arg1.v1); if (diff != 0) return diff; return comparator2.compare(arg0.v2, arg1.v2); } @Override public boolean equals( Object obj ) { if (obj == this) return true; if (obj instanceof Tuple2Comparator) { @SuppressWarnings( "unchecked" ) Tuple2Comparator<T1, T2> that = (Tuple2Comparator<T1, T2>)obj; return comparator1.equals(that.comparator1) && comparator2.equals(that.comparator2); } return false; } @Override public int hashCode() { return 1; } } @SuppressWarnings( "unchecked" ) protected static final class Tuple2TypeFactory<T1, T2> implements TypeFactory<Tuple2<T1, T2>>, TupleFactory<Tuple2<T1, T2>> { private final TypeFactory<T1> type1; private final TypeFactory<T2> type2; private final Class<Tuple2<T1, T2>> type; private final Comparator<Tuple2<T1, T2>> comparator; private final String typeName; protected Tuple2TypeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2 ) { this.type1 = type1; this.type2 = type2; Class<?> clazz = Tuple2.class; this.type = (Class<Tuple2<T1, T2>>)clazz; this.comparator = new Tuple2Comparator<>(type1.getComparator(), type2.getComparator()); this.typeName = "Tuple2<" + type1.getTypeName() + "," + type2.getTypeName() + ">"; } @Override public Serializer<Tuple2<T1, T2>> getSerializer( BufferManager bufferMgr ) { Serializer<T1> ser1 = (Serializer<T1>)bufferMgr.nullSafeSerializerFor(type1); Serializer<T2> ser2 = (Serializer<T2>)bufferMgr.nullSafeSerializerFor(type2); return new Tuple2Serializer<>(ser1, ser2); } @Override public Class<Tuple2<T1, T2>> getType() { return this.type; } @Override public Comparator<Tuple2<T1, T2>> getComparator() { return comparator; } @Override public String getTypeName() { return typeName; } @Override public Tuple2<T1, T2> create( String value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public Tuple2<T1, T2> create( Object value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public String asString( Object value ) { return value.toString(); } @Override public long length( Object value ) { if (value instanceof Tuple2) { Tuple2<?, ?> tuple = (Tuple2<?, ?>)value; return type1.length(tuple.v1) + type2.length(tuple.v2); } return asString(value).length(); } @Override public String asReadableString( Object value ) { return asString(value); } } @SuppressWarnings( "unchecked" ) protected static final class Tuple3TypeFactory<T1, T2, T3> implements TypeFactory<Tuple3<T1, T2, T3>>, TupleFactory<Tuple3<T1, T2, T3>> { private final TypeFactory<T1> type1; private final TypeFactory<T2> type2; private final TypeFactory<T3> type3; private final Class<Tuple3<T1, T2, T3>> type; private final Comparator<Tuple3<T1, T2, T3>> comparator; private final String typeName; protected Tuple3TypeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2, TypeFactory<T3> type3 ) { this.type1 = type1; this.type2 = type2; this.type3 = type3; Class<?> clazz = Tuple3.class; this.type = (Class<Tuple3<T1, T2, T3>>)clazz; final Comparator<T1> comparator1 = type1.getComparator(); final Comparator<T2> comparator2 = type2.getComparator(); final Comparator<T3> comparator3 = type3.getComparator(); this.comparator = (Comparator<Tuple3<T1, T2, T3>> & Serializable) (arg0, arg1) -> { int diff = comparator1.compare(arg0.v1, arg1.v1); if (diff != 0) return diff; diff = comparator2.compare(arg0.v2, arg1.v2); if (diff != 0) return diff; return comparator3.compare(arg0.v3, arg1.v3); }; this.typeName = "Tuple3<" + type1.getTypeName() + "," + type2.getTypeName() + "," + type3.getTypeName() + ">"; } @Override public Serializer<Tuple3<T1, T2, T3>> getSerializer( BufferManager bufferMgr ) { Serializer<T1> ser1 = (Serializer<T1>)bufferMgr.nullSafeSerializerFor(type1); Serializer<T2> ser2 = (Serializer<T2>)bufferMgr.nullSafeSerializerFor(type2); Serializer<T3> ser3 = (Serializer<T3>)bufferMgr.nullSafeSerializerFor(type3); return new Tuple3Serializer<>(ser1, ser2, ser3); } @Override public Class<Tuple3<T1, T2, T3>> getType() { return this.type; } @Override public Comparator<Tuple3<T1, T2, T3>> getComparator() { return comparator; } @Override public String getTypeName() { return typeName; } @Override public Tuple3<T1, T2, T3> create( String value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public Tuple3<T1, T2, T3> create( Object value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public String asString( Object value ) { return value.toString(); } @Override public long length( Object value ) { if (value instanceof Tuple3) { Tuple3<?, ?, ?> tuple = (Tuple3<?, ?, ?>)value; return type1.length(tuple.v1) + type2.length(tuple.v2) + type3.length(tuple.v3); } return asString(value).length(); } @Override public String asReadableString( Object value ) { return asString(value); } } @SuppressWarnings( "unchecked" ) protected static final class Tuple4TypeFactory<T1, T2, T3, T4> implements TypeFactory<Tuple4<T1, T2, T3, T4>>, TupleFactory<Tuple4<T1, T2, T3, T4>> { private final TypeFactory<T1> type1; private final TypeFactory<T2> type2; private final TypeFactory<T3> type3; private final TypeFactory<T4> type4; private final Class<Tuple4<T1, T2, T3, T4>> type; private final Comparator<Tuple4<T1, T2, T3, T4>> comparator; private final String typeName; protected Tuple4TypeFactory( TypeFactory<T1> type1, TypeFactory<T2> type2, TypeFactory<T3> type3, TypeFactory<T4> type4 ) { this.type1 = type1; this.type2 = type2; this.type3 = type3; this.type4 = type4; Class<?> clazz = Tuple4.class; this.type = (Class<Tuple4<T1, T2, T3, T4>>)clazz; final Comparator<T1> comparator1 = type1.getComparator(); final Comparator<T2> comparator2 = type2.getComparator(); final Comparator<T3> comparator3 = type3.getComparator(); final Comparator<T4> comparator4 = type4.getComparator(); this.comparator = (Comparator<Tuple4<T1, T2, T3, T4>> & Serializable) (arg0, arg1) -> { int diff = comparator1.compare(arg0.v1, arg1.v1); if (diff != 0) return diff; diff = comparator2.compare(arg0.v2, arg1.v2); if (diff != 0) return diff; diff = comparator3.compare(arg0.v3, arg1.v3); if (diff != 0) return diff; return comparator4.compare(arg0.v4, arg1.v4); }; this.typeName = "Tuple4<" + type1.getTypeName() + "," + type2.getTypeName() + "," + type3.getTypeName() + "," + type4.getTypeName() + ">"; } @Override public Serializer<Tuple4<T1, T2, T3, T4>> getSerializer( BufferManager bufferMgr ) { Serializer<T1> ser1 = (Serializer<T1>)bufferMgr.nullSafeSerializerFor(type1); Serializer<T2> ser2 = (Serializer<T2>)bufferMgr.nullSafeSerializerFor(type2); Serializer<T3> ser3 = (Serializer<T3>)bufferMgr.nullSafeSerializerFor(type3); Serializer<T4> ser4 = (Serializer<T4>)bufferMgr.nullSafeSerializerFor(type4); return new Tuple4Serializer<>(ser1, ser2, ser3, ser4); } @Override public Class<Tuple4<T1, T2, T3, T4>> getType() { return this.type; } @Override public Comparator<Tuple4<T1, T2, T3, T4>> getComparator() { return comparator; } @Override public String getTypeName() { return typeName; } @Override public Tuple4<T1, T2, T3, T4> create( String value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public Tuple4<T1, T2, T3, T4> create( Object value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public String asString( Object value ) { return value.toString(); } @Override public long length( Object value ) { if (value instanceof Tuple4) { Tuple4<?, ?, ?, ?> tuple = (Tuple4<?, ?, ?, ?>)value; return type1.length(tuple.v1) + type2.length(tuple.v2) + type3.length(tuple.v3) + type4.length(tuple.v4); } return asString(value).length(); } @Override public String asReadableString( Object value ) { return asString(value); } } @SuppressWarnings( "unchecked" ) protected static final class TupleNTypeFactory implements TypeFactory<TupleN>, TupleFactory<TupleN> { protected final TypeFactory<?>[] types; private final Comparator<TupleN> comparator; private final String typeName; protected TupleNTypeFactory( Collection<TypeFactory<?>> typeFactories ) { this.types = new TypeFactory<?>[typeFactories.size()]; final Comparator<Object>[] comparators = new Comparator[types.length]; Iterator<TypeFactory<?>> typeIter = typeFactories.iterator(); for (int i = 0; i != this.types.length; ++i) { TypeFactory<?> typeFactory = typeIter.next(); this.types[i] = typeFactory; comparators[i] = (Comparator<Object>)typeFactory.getComparator(); } this.comparator = (Comparator<TupleN> & Serializable) (arg0, arg1) -> { int diff = 0; for (int i = 0; i != types.length; ++i) { diff = comparators[i].compare(arg0.values[i], arg1.values[i]); if (diff != 0) return diff; } return diff; }; StringBuilder sb = new StringBuilder("TupleN<"); for (int i = 0; i != types.length; ++i) { if (i != 0) sb.append(','); sb.append(types[i].getTypeName()); } sb.append(">"); this.typeName = sb.toString(); } @Override public Serializer<TupleN> getSerializer( BufferManager bufferMgr ) { Serializer<?>[] serializers = new Serializer<?>[types.length]; for (int i = 0; i != types.length; ++i) { serializers[i] = bufferMgr.nullSafeSerializerFor(types[i]); } return new TupleNSerializer(serializers); } @Override public Class<TupleN> getType() { return TupleN.class; } @Override public Comparator<TupleN> getComparator() { return comparator; } @Override public String getTypeName() { return this.typeName; } @Override public TupleN create( String value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public TupleN create( Object value ) throws ValueFormatException { throw new UnsupportedOperationException(); } @Override public String asString( Object value ) { return value.toString(); } @Override public long length( Object value ) { if (value instanceof TupleN) { TupleN tuple = (TupleN)value; int len = 0; for (int i = 0; i != types.length; ++i) { len += types[i].length(tuple.values[i]); } return len; } return asString(value).length(); } @Override public String asReadableString( Object value ) { return asString(value); } } }