View Javadoc
1   /*
2      Copyright 2011 Atlassian
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package io.atlassian.fugue;
17  
18  import java.io.Serializable;
19  import java.util.Optional;
20  import java.util.function.BiFunction;
21  import java.util.function.Function;
22  
23  import static java.util.Objects.requireNonNull;
24  
25  /**
26   * Represents a pair of objects.
27   *
28   * @since 1.0
29   */
30  public final class Pair<A, B> implements Serializable {
31    private static final long serialVersionUID = 3054071035067921893L;
32  
33    private static final int HALF_WORD = 16;
34  
35    /**
36     * Factory method for static Pair growth.
37     *
38     * @param <A> the left value type
39     * @param <B> the right value type
40     * @param left value, cannot be null
41     * @param right value, cannot be null
42     * @return the Pair containing the passed values
43     */
44    public static <A, B> Pair<A, B> pair(final A left, final B right) {
45      return new Pair<>(left, right);
46    }
47  
48    /**
49     * Factory method for a Pair factory function.
50     *
51     * @param <A> the left value type
52     * @param <B> the right value type
53     * @return a function that constructs Pairs
54     */
55    public static <A, B> BiFunction<A, B, Pair<A, B>> pairs() {
56      return Pair::pair;
57    }
58  
59    /**
60     * Function for accessing the left value of {@link Pair pairs}.
61     *
62     * @param <A> the left value type
63     * @return a Function that given a {@link io.atlassian.fugue.Pair} returns the
64     * left side value
65     * @since 1.1
66     */
67    public static <A> Function<Pair<A, ?>, A> leftValue() {
68      return Pair::left;
69    }
70  
71    /**
72     * Function for accessing the right value of {@link Pair pairs}.
73     *
74     * @param <B> the right value type
75     * @return a Function that given a {@link io.atlassian.fugue.Pair} returns the
76     * right side value
77     * @since 1.1
78     */
79    public static <B> Function<Pair<?, B>, B> rightValue() {
80      return Pair::right;
81    }
82  
83    /**
84     * Performs function application within an homogeneous pair (applicative
85     * functor pattern).
86     *
87     * @param aa an homogeneous pair
88     * @param ff The pair of functions to apply.
89     * @return A new pair after applying the given pair of functions through aa.
90     */
91    public static <A, B> Pair<B, B> ap(final Pair<A, A> aa, final Pair<Function<A, B>, Function<A, B>> ff) {
92      return Pair.pair(ff.left().apply(aa.left()), ff.right().apply(aa.right()));
93    }
94  
95    /**
96     * Apply a function to both elements of an homogeneous pair.
97     *
98     * @param aa an homogeneous pair
99     * @param f function to apply to both elements of aa
100    * @return A new pair after applying the function to aa elements.
101    */
102   public static <A, B> Pair<B, B> map(final Pair<A, A> aa, final Function<A, B> f) {
103     return Pair.pair(f.apply(aa.left()), f.apply(aa.right()));
104   }
105 
106   /**
107    * Zips two iterables into a single iterable that produces {@link Pair pairs}.
108    *
109    * @param <A> LHS type
110    * @param <B> RHS type
111    * @param as left values
112    * @param bs right values
113    * @return an {@link Iterable iterable} of pairs, only as long as the shortest
114    * input iterable.
115    * @since 1.1
116    */
117   public static <A, B> Iterable<Pair<A, B>> zip(final Iterable<A> as, final Iterable<B> bs) {
118     return Iterables.zip(as, bs);
119   }
120 
121   /**
122    * Zips the two given optionals into an optional of a pair.
123    *
124    * @param oA the first optional
125    * @param oB the second optional
126    * @param <A> the first type
127    * @param <B> the second type
128    * @return empty if either or both optionals are empty
129    * @since 4.6.0
130    */
131   @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static <A, B> Optional<Pair<A, B>> zip(final Optional<A> oA, final Optional<B> oB) {
132     if (oA.isPresent() && oB.isPresent()) {
133       return Optional.of(pair(oA.get(), oB.get()));
134     }
135     return Optional.empty();
136   }
137 
138   //
139   // members
140   //
141 
142   private final A left;
143   private final B right;
144 
145   /**
146    * Constructor for Pair.
147    *
148    * @param left value, cannot be null
149    * @param right value, cannot be null
150    */
151   public Pair(final A left, final B right) {
152     this.left = requireNonNull(left, "Left parameter must not be null.");
153     this.right = requireNonNull(right, "Right parameter must not be null.");
154   }
155 
156   /**
157    * Accessor method for the left value of the pair.
158    *
159    * @return a A object.
160    */
161   public A left() {
162     return left;
163   }
164 
165   /**
166    * Accessor method for the right value of the pair.q
167    *
168    * @return a B object.
169    */
170   public B right() {
171     return right;
172   }
173 
174   /** {@inheritDoc} */
175   @Override public String toString() {
176     return "Pair(" + left + ", " + right + ")";
177   }
178 
179   /** {@inheritDoc} */
180   @Override public boolean equals(final Object o) {
181     if (o == null) {
182       return false;
183     }
184     if (this == o) {
185       return true;
186     }
187 
188     if (!(o instanceof Pair<?, ?>)) {
189       return false;
190     }
191     final Pair<?, ?> that = (Pair<?, ?>) o;
192     return left.equals(that.left) && right.equals(that.right);
193   }
194 
195   /** {@inheritDoc} */
196   @Override public int hashCode() {
197     final int lh = left.hashCode();
198     final int rh = right.hashCode();
199     return (((lh >> HALF_WORD) ^ lh) << HALF_WORD) | (((rh << HALF_WORD) ^ rh) >> HALF_WORD);
200   }
201 }