All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.d2ab.util.Pair Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/*
 * Copyright 2015 Daniel Skogquist Åborg
 *
 * 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.d2ab.util;

import org.d2ab.function.Functions;
import org.d2ab.function.QuaternaryFunction;

import javax.annotation.Nullable;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.function.*;

import static java.util.Comparator.*;

public interface Pair extends Entry, Comparable> {
	static  Pair of(@Nullable T left, @Nullable U right) {
		return new Base() {
			@Override
			public T getLeft() {
				return left;
			}

			@Override
			public U getRight() {
				return right;
			}
		};
	}

	static  Pair from(Entry entry) {
		return new Base() {
			@Override
			public K getLeft() {
				return entry.getKey();
			}

			@Override
			public V getRight() {
				return entry.getValue();
			}
		};
	}

	static  Pair unary(@Nullable T item) {
		return new Base() {
			@Override
			public T getLeft() {
				return item;
			}

			@Override
			public T getRight() {
				return item;
			}
		};
	}

	static  boolean test(Entry entry, BiPredicate predicate) {
		return Entries.asPredicate(predicate).test(entry);
	}

	static  UnaryOperator> asUnaryOperator(BiFunction>
			                                                        op) {
		return entry -> op.apply(entry.getLeft(), entry.getRight());
	}

	static  UnaryOperator> asUnaryOperator(BiFunction> f,

	                                                                  BiFunction> g) {

		Function, ? extends Pair> f1 = asFunction(f);
		Function, ? extends Pair> g1 = asFunction(g);
		return Functions.toUnaryOperator(f1, g1);
	}

	static  BinaryOperator> asBinaryOperator(QuaternaryFunction> f) {
		return (e1, e2) -> f.apply(e1.getLeft(), e1.getRight(), e2.getLeft(), e2.getRight());
	}

	static  Function, ? extends R> asFunction(BiFunction
			                                                                      mapper) {
		return entry -> mapper.apply(entry.getLeft(), entry.getRight());
	}

	static  Predicate> asPredicate(BiPredicate predicate) {
		return entry -> predicate.test(entry.getLeft(), entry.getRight());
	}

	static  Consumer> asConsumer(BiConsumer action) {
		return entry -> action.accept(entry.getLeft(), entry.getRight());
	}

	L getLeft();

	R getRight();

	@Override
	default L getKey() {
		return getLeft();
	}

	@Override
	default R getValue() {
		return getRight();
	}

	@Override
	default R setValue(R value) {
		throw new UnsupportedOperationException();
	}

	default Pair swap() {
		return new Base() {
			@Override
			public R getLeft() {
				return Pair.this.getRight();
			}

			@Override
			public L getRight() {
				return Pair.this.getLeft();
			}
		};
	}

	default  Pair withLeft(LL left) {
		return new Base() {
			@Override
			public LL getLeft() {
				return left;
			}

			@Override
			public R getRight() {
				return Pair.this.getRight();
			}
		};
	}

	default  Pair withRight(RR right) {
		return new Base() {
			@Override
			public L getLeft() {
				return Pair.this.getLeft();
			}

			@Override
			public RR getRight() {
				return right;
			}
		};
	}

	default  Pair shiftRight(LL replacement) {
		return new Base() {
			@Override
			public LL getLeft() {
				return replacement;
			}

			@Override
			public L getRight() {
				return Pair.this.getLeft();
			}
		};
	}

	default  Pair shiftLeft(RR replacement) {
		return new Base() {
			@Override
			public R getLeft() {
				return Pair.this.getRight();
			}

			@Override
			public RR getRight() {
				return replacement;
			}
		};
	}

	default  Pair map(Function leftMapper,
	                                  Function rightMapper) {
		return new Base() {
			@Override
			public LL getLeft() {
				return leftMapper.apply(Pair.this.getLeft());
			}

			@Override
			public RR getRight() {
				return rightMapper.apply(Pair.this.getRight());
			}
		};
	}

	default  Pair map(BiFunction> mapper) {
		return mapper.apply(getLeft(), getRight());
	}

	default  T apply(BiFunction function) {
		return function.apply(getLeft(), getRight());
	}

	default boolean test(Predicate leftPredicate, Predicate rightPredicate) {
		return leftPredicate.test(getLeft()) && rightPredicate.test(getRight());
	}

	default boolean test(BiPredicate predicate) {
		return predicate.test(getLeft(), getRight());
	}

	default Map put(Map map) {
		map.put(getLeft(), getRight());
		return map;
	}

	default  Iterator iterator() {
		@SuppressWarnings("unchecked")
		PairIterator pairIterator = new PairIterator(this);
		return pairIterator;
	}

	abstract class Base implements Pair {
		@SuppressWarnings("unchecked")
		private static final Comparator NULLS_FIRST = nullsFirst((Comparator) naturalOrder());

		private static final Function GET_LEFT = (Function) Pair::getLeft;
		private static final Function GET_RIGHT = (Function) Pair::getRight;

		@SuppressWarnings("unchecked")
		private static final Comparator COMPARATOR =
				comparing(GET_LEFT, NULLS_FIRST).thenComparing(GET_RIGHT, NULLS_FIRST);

		public static String format(Object o) {
			if (o instanceof String) {
				return '"' + (String) o + '"';
			}
			return String.valueOf(o);
		}

		@Override
		public int hashCode() {
			int result = (getLeft() != null) ? getLeft().hashCode() : 0;
			result = (31 * result) + ((getRight() != null) ? getRight().hashCode() : 0);
			return result;
		}

		@Override
		public boolean equals(Object o) {
			if (this == o)
				return true;
			if (!(o instanceof Pair))
				return false;

			Pair that = (Pair) o;

			return ((getLeft() != null) ? getLeft().equals(that.getLeft()) : (that.getLeft() == null)) &&
			       ((getRight() != null) ? getRight().equals(that.getRight()) : (that.getRight() == null));
		}

		@Override
		public String toString() {
			return "(" + format(getLeft()) + ", " + format(getRight()) + ')';
		}

		@Override
		public int compareTo(Pair that) {
			return COMPARATOR.compare(this, that);
		}
	}

	class PairIterator implements Iterator {
		private final Pair pair;
		int index;

		public PairIterator(Pair pair) {
			this.pair = pair;
		}

		@Override
		public boolean hasNext() {
			return index < 2;
		}

		@Override
		public T next() {
			if (!hasNext())
				throw new NoSuchElementException();
			switch (++index) {
				case 1:
					return pair.getLeft();
				case 2:
					return pair.getRight();
				default:
					// Can't happen due to above check
					throw new IllegalStateException();
			}
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy