/************************************************************************* * Copyright 2009-2013 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. ************************************************************************/ package com.eucalyptus.util; import static org.hamcrest.Matchers.notNullValue; import static com.eucalyptus.util.Parameters.checkParam; import javax.annotation.Nonnull; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.base.Optional; import com.google.common.collect.Iterables; /** * @see com.google.common.base.Optional Optional - for null support */ public class Pair<L,R> { private final L left; private final R right; /** * @see #of(Object, Object) * @see #pair(Object, Object) * @see #opair(Object, Object) * @see #lopair(Object, Object) * @see #ropair(Object, Object) */ public Pair( @Nonnull final L left, @Nonnull final R right ) { this.left = checkParam( "left", left, notNullValue() ); this.right = checkParam( "right", right, notNullValue() ); } /** * Curried pair constructor function. * * @param <L> The left type * @param <R> The right type * @return The pair function */ @Nonnull public static <L,R> NonNullFunction<L,Function<R, Pair<L,R>>> pair( ) { return new NonNullFunction<L,Function<R, Pair<L,R>>>( ){ @Override public Function<R, Pair<L, R>> apply( final L left ) { return new Function<R, Pair<L, R>>( ){ @Override public Pair<L, R> apply( final R right ) { return pair( left, right ); } }; } }; } /** * Convenience constructor * * @param left The left value * @param right The right value * @param <L> The left type * @param <R> The right type * @return The new pair */ public static <L,R> Pair<L,R> of( @Nonnull final L left, @Nonnull final R right ) { return new Pair<>( left, right ); } /** * Convenience constructor * * @param left The left value * @param right The right value * @param <L> The left type * @param <R> The right type * @return The new pair */ public static <L,R> Pair<L,R> pair( @Nonnull final L left, @Nonnull final R right ) { return new Pair<>( left, right ); } /** * Convenience constructor for an optional pair. * * @param left The left value * @param right The right value * @param <L> The left type * @param <R> The right type * @return The new pair */ public static <L,R> Pair<Optional<L>,Optional<R>> opair( @Nullable final L left, @Nullable final R right ) { return new Pair<>( Optional.fromNullable( left ), Optional.fromNullable( right ) ); } /** * Convenience constructor for a left optional pair. * * @param left The left value * @param right The right value * @param <L> The left type * @param <R> The right type * @return The new pair */ public static <L,R> Pair<Optional<L>,R> lopair( @Nullable final L left, @Nonnull final R right ) { return new Pair<>( Optional.fromNullable( left ), right ); } /** * Convenience constructor for a right optional pair. * * @param left The left value * @param right The right value * @param <L> The left type * @param <R> The right type * @return The new pair */ public static <L,R> Pair<L,Optional<R>> ropair( @Nonnull final L left, @Nullable final R right ) { return new Pair<>( left, Optional.fromNullable( right ) ); } @Nonnull public L getLeft( ) { return left; } @Nonnull public R getRight( ) { return right; } @Nonnull public static <L,R> Function<Pair<L,R>,L> left( ) { return new PairLeftExtractor<>( ); } @Nonnull public static <L,R> Function<Pair<L,R>,R> right( ) { return new PairRightExtractor<>( ); } @Nonnull public static <T,L,R> NonNullFunction<T,Pair<L,R>> builder( @Nonnull final Function<? super T, L> leftFunction, @Nonnull final Function<? super T, R> rightFunction ) { return new NonNullFunction<T,Pair<L,R>>( ) { @SuppressWarnings( "ConstantConditions" ) @Nonnull @Override public Pair<L,R> apply( final T value ) { return Pair.pair( leftFunction.apply( value ), rightFunction.apply( value ) ); } }; } @Nonnull public static <T,L,R> NonNullFunction<T,Pair<L,Optional<R>>> robuilder( @Nonnull final Function<? super T, L> leftFunction, @Nonnull final Function<? super T, R> rightFunction ) { return new NonNullFunction<T,Pair<L,Optional<R>>>( ) { @SuppressWarnings( "ConstantConditions" ) @Nonnull @Override public Pair<L,Optional<R>> apply( final T value ) { return Pair.pair( leftFunction.apply( value ), Optional.fromNullable( rightFunction.apply( value ) ) ); } }; } public static <L,R> NonNullFunction<R,Iterable<Pair<L,R>>> explodeLeft( final Iterable<L> leftValues ) { return new NonNullFunction<R,Iterable<Pair<L,R>>>( ) { @SuppressWarnings( "ConstantConditions" ) @Nonnull @Override public Iterable<Pair<L,R>> apply( final R rightValue ) { return Iterables.transform( leftValues, CollectionUtils.flipCurried( Pair.<L,R>pair( ) ).apply( rightValue ) ); } }; } public static <L,R> NonNullFunction<L,Iterable<Pair<L,R>>> explodeRight( final Iterable<R> rightValues ) { return new NonNullFunction<L,Iterable<Pair<L,R>>>( ) { @SuppressWarnings( "ConstantConditions" ) @Nonnull @Override public Iterable<Pair<L,R>> apply( final L leftValue ) { return Iterables.transform( rightValues, Pair.<L,R>pair().apply( leftValue ) ); } }; } public static <L,R,V> NonNullFunction<Pair<L,R>,V> transformer( final Function<L,? extends Function<R,V>> pairTransform ) { return new NonNullFunction<Pair<L, R>, V>( ) { @SuppressWarnings( "ConstantConditions" ) @Nonnull @Override public V apply( final Pair<L, R> pair ) { return pairTransform.apply( pair.getLeft( ) ).apply( pair.getRight( ) ); } }; } @Override public boolean equals( final Object o ) { if ( this == o ) return true; if ( o == null || getClass() != o.getClass() ) return false; final Pair pair = (Pair) o; if ( !left.equals( pair.left ) ) return false; if ( !right.equals( pair.right ) ) return false; return true; } @Override public int hashCode() { int result = left.hashCode(); result = 31 * result + right.hashCode(); return result; } @Override public String toString( ) { return Objects.toStringHelper( this ) .add( "left", left ) .add( "right", right ) .toString( ); } private static class PairLeftExtractor<L,R> implements Function<Pair<L,R>,L> { @Override public L apply( final Pair<L, R> pair ) { return pair.getLeft(); } } private static class PairRightExtractor<L,R> implements Function<Pair<L,R>,R> { @Override public R apply( final Pair<L, R> pair ) { return pair.getRight( ); } } }