Commits

grainednoise committed f8d7a7a

Re-thinking tuples -- just a bit

Comments (0)

Files changed (1)

src/main/java/org/grainednoise/deferred/core/Tuple.java

 package org.grainednoise.deferred.core;
 
 
-public class Tuple {
-	
-	private static final Tuple0 TUPLE0 = new Tuple0() {
-		
-	};
 
+public abstract class Tuple {
+	private static final Tuple0 TUPLE0 = new Tuple0();
 
 	public static final Tuple0 of() {
 		return TUPLE0;
 	}
+	
+	public static final <V1, V2>  Tuple2<V1, V2> of(final V1 value1, final V2 value2) {
+		return new Tuple2<V1, V2>(value1, value2);
+	}
+	
+	public static final <V1>  Tuple1<V1> of(final V1 value1) {
+		return new Tuple1<V1>(value1);
+	}
+	
+	public static final <V1, V2, V3>  Tuple3<V1, V2, V3> of(final V1 value1, final V2 value2, final V3 value3) {
+		return new Tuple3<V1, V2, V3>(value1, value2, value3);
+	}
+	
+	
+	
+	protected abstract String getName();
+	public abstract int procuctArity();
+	public abstract Object productElement(int index);
+	
+	private Tuple() {
+		// Let's keep the subclasses in here
+	}
+	
+	
+	@Override
+	public final String toString() {
+		StringBuilder builder = new StringBuilder(getName());
+		builder.append("(");
+
+		boolean first = true;
+		for (int index = 0; index < procuctArity(); index ++) {
+			if (first) {
+				first = false;
+			}
+			else {
+				builder.append(", ");
+			}
+			builder.append(productElement(index));
+		}
+		
+		builder.append(")");
+		
+		return builder.toString();
+	}
+	
+	@Override
+	public final boolean equals(Object obj) {
+		if (!(obj instanceof Tuple)) {
+			return false;
+		}
+		
+		Tuple other = (Tuple)obj;
+		
+		if (procuctArity() != other.procuctArity()) {
+			return false;
+		}
+		
+		for (int index = 0; index < procuctArity(); index++) {
+			Object first = productElement(index);
+			Object second = other.productElement(index);
+			
+			if (first == null) {
+				if (other != null) {
+					return false;
+				}
+			}
+			else if (!first.equals(second)) {
+				return false;
+				
+			}
+		}
+		
+		return true;
+	}
+	
+	@Override
+	public int hashCode() {
+		int result = 1;
+		
+		for (int index = 0; index < procuctArity(); index++) {
+			Object elem = productElement(index);
+			result = result * 31 + (elem == null ? 1791 : elem.hashCode());
+		}
+		
+		return result;
+	}
 
 	
-	public static final <V1>  Tuple1<V1> of(final V1 value1) {
-		return new Tuple1<V1>() {
-			
-			@Override
-			public V1 get1() {
+	public static final class Tuple0 extends Tuple {
+		
+		private Tuple0() {
+			// Like, none
+		}
+
+		@Override
+		protected String getName() {
+			return "Tuple0";
+		}
+
+		@Override
+		public int procuctArity() {
+			return 0;
+		}
+
+		@Override
+		public Object productElement(int index) {
+			throw new IndexOutOfBoundsException("No elements for " + index);
+		}
+		
+	}
+	
+	
+	public static final class Tuple1<V1> extends Tuple {
+		private final V1 value1;
+
+		private Tuple1(V1 value) {
+			this.value1 = value;
+		}
+		
+		public V1 get1() {
+			return value1;
+		}
+		
+		@Override
+		protected String getName() {
+			return "Tuple1";
+		}
+		
+		@Override
+		public int procuctArity() {
+			return 0;
+		}
+		
+		@Override
+		public Object productElement(int index) {
+			if (index == 0) {
 				return value1;
 			}
 			
-		};
+			throw new IndexOutOfBoundsException("No elements for " + index);
+		}
 	}
+	
+	
 
-	
-	public static final <V1, V2>  Tuple2<V1, V2> of(final V1 value1, final V2 value2) {
-		return new Tuple2<V1, V2>() {
-			
-			@Override
-			public V1 get1() {
+	public static final class Tuple2<V1, V2> extends Tuple {
+		private final V1 value1;
+		private final V2 value2;
+
+		private Tuple2(V1 value, V2 value2) {
+			this.value1 = value;
+			this.value2 = value2;
+		}
+		
+		public V1 get1() {
+			return value1;
+		}
+		
+		public V2 get2() {
+			return value2;
+		}
+		
+		@Override
+		protected String getName() {
+			return "Tuple2";
+		}
+		
+		@Override
+		public int procuctArity() {
+			return 2;
+		}
+		
+		@Override
+		public Object productElement(int index) {
+			if (index == 0) {
 				return value1;
 			}
-			
-			@Override
-			public V2 get2() {
+			if (index == 1) {
 				return value2;
 			}
 			
-		};
+			throw new IndexOutOfBoundsException("No elements for " + index);
+		}
 	}
+	
+	public static final class Tuple3<V1, V2, V3> extends Tuple {
+		private final V1 value1;
+		private final V2 value2;
+		private final V3 value3;
+		
+		private Tuple3(V1 value, V2 value2, V3 value3) {
+			this.value1 = value;
+			this.value2 = value2;
+			this.value3 = value3;
+		}
+		
+		public V1 get1() {
+			return value1;
+		}
+		
+		public V2 get2() {
+			return value2;
+		}
 
-	
-	public static final <V1, V2, V3>  Tuple3<V1, V2, V3> of(final V1 value1, final V2 value2, final V3 value3) {
-		return new Tuple3<V1, V2, V3>() {
-
-			@Override
-			public V1 get1() {
+		public V3 get3() {
+			return value3;
+		}
+		
+		@Override
+		protected String getName() {
+			return "Tuple3";
+		}
+		
+		@Override
+		public int procuctArity() {
+			return 2;
+		}
+		
+		@Override
+		public Object productElement(int index) {
+			if (index == 0) {
 				return value1;
 			}
-
-			@Override
-			public V2 get2() {
+			if (index == 1) {
 				return value2;
 			}
-
-			@Override
-			public V3 get3() {
+			if (index == 2) {
 				return value3;
 			}
 			
-		};
-	}
-	
-	
-	public interface Tuple0 {
-		
-	}
-	
-	public interface Tuple1<V1> extends Tuple0 {
-		public V1 get1();
-	}
-
-	public interface Tuple2<V1, V2> extends Tuple1<V1> {
-		public V2 get2();
-	}
-	
-	
-	public interface Tuple3<V1, V2, V3> extends Tuple2<V1, V2>{
-		public V3 get3();
-	}
-	
-	
-	
-	private Tuple() {
-		//
+			throw new IndexOutOfBoundsException("No elements for " + index);
+		}
 	}
 }