001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.commons.function;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import java.util.*;
022
023import org.apache.juneau.commons.lang.*;
024import org.apache.juneau.commons.utils.*;
025
026/**
027 * Represents an immutable tuple containing two values.
028 *
029 * <p>
030 * This class provides a simple wrapper for two values that properly implements
031 * {@link #equals(Object)} and {@link #hashCode()} based on content rather than identity.
032 * This is particularly useful for HashMap composite keys when you need to combine multiple
033 * values into a single key.
034 *
035 * <h5 class='section'>Features:</h5>
036 * <ul class='spaced-list'>
037 *    <li>Immutable - values cannot be changed after construction
038 *    <li>Content-based equality - uses {@link Shorts#eq(Object, Object)} for comparison
039 *    <li>Content-based hashing - uses {@link HashCode#of(Object...)} for hash code computation
040 *    <li>Array support - properly handles arrays with content-based equality and hashing
041 * </ul>
042 *
043 * <h5 class='section'>Array Support:</h5>
044 * <p>
045 * Unlike using arrays directly as HashMap keys (which use identity-based equality), this class properly
046 * handles arrays by using content-based equality and hashing via {@link HashCode#of(Object...)} which
047 * internally uses {@link Arrays#hashCode(Object[])} for arrays. This means two Tuple2 instances
048 * containing arrays with the same content will be considered equal.
049 *
050 * <h5 class='section'>Use Cases:</h5>
051 * <ul class='spaced-list'>
052 *    <li>Composite keys for HashMap lookups (e.g., combining two identifiers)
053 *    <li>Using arrays in composite keys with proper content-based equality
054 *    <li>Returning multiple values from methods (alternative to creating a custom class)
055 *    <li>Grouping related values together for processing
056 * </ul>
057 *
058 * <h5 class='section'>Usage:</h5>
059 * <p class='bjava'>
060 *    <jc>// Using arrays in composite keys</jc>
061 *    Map&lt;Tuple2&lt;String,int[]&gt;,Result&gt; <jv>map</jv> = <jk>new</jk> HashMap&lt;&gt;();
062 *    <jv>map</jv>.put(Tuple2.<jsm>of</jsm>(<js>"key"</js>, <jk>new</jk> <jk>int</jk>[]{1,2,3}), <jv>result1</jv>);
063 *    Result <jv>r</jv> = <jv>map</jv>.get(Tuple2.<jsm>of</jsm>(<js>"key"</js>, <jk>new</jk> <jk>int</jk>[]{1,2,3}));  <jc>// Works correctly!</jc>
064 *
065 *    <jc>// Simple composite key</jc>
066 *    Map&lt;Tuple2&lt;String,Integer&gt;,String&gt; <jv>cache</jv> = <jk>new</jk> HashMap&lt;&gt;();
067 *    <jv>cache</jv>.put(Tuple2.<jsm>of</jsm>(<js>"user"</js>, 12345), <js>"John Doe"</js>);
068 *    String <jv>name</jv> = <jv>cache</jv>.get(Tuple2.<jsm>of</jsm>(<js>"user"</js>, 12345));  <jc>// Returns "John Doe"</jc>
069 * </p>
070 *
071 * <h5 class='section'>Thread Safety:</h5>
072 * <p>
073 * This class is immutable and therefore thread-safe. Multiple threads can safely access a Tuple2 instance
074 * concurrently without synchronization.
075 *
076 * <h5 class='section'>See Also:</h5><ul>
077 *    <li class='jc'>{@link Tuple1} - Single-value tuple
078 *    <li class='jc'>{@link Tuple3} - Three-value tuple
079 *    <li class='jc'>{@link Tuple4} - Four-value tuple
080 *    <li class='jc'>{@link Tuple5} - Five-value tuple
081 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauCommons">juneau-commons</a>
082 * </ul>
083 *
084 * @param <A> The type of the first value in this tuple.
085 * @param <B> The type of the second value in this tuple.
086 */
087public class Tuple2<A,B> {
088
089   /**
090    * Creates a new tuple containing the specified two values.
091    *
092    * <h5 class='section'>Example:</h5>
093    * <p class='bjava'>
094    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"name"</js>, 42);
095    *    Tuple2&lt;String[],int[]&gt; <jv>arrayTuple</jv> = Tuple2.<jsm>of</jsm>(
096    *       <jk>new</jk> String[]{<js>"a"</js>, <js>"b"</js>},
097    *       <jk>new</jk> <jk>int</jk>[]{1, 2}
098    *    );
099    * </p>
100    *
101    * @param <A> The type of the first value.
102    * @param <B> The type of the second value.
103    * @param a The first value.  Can be <jk>null</jk>.
104    * @param b The second value.  Can be <jk>null</jk>.
105    * @return A new tuple containing the specified values.
106    */
107   public static <A,B> Tuple2<A,B> of(A a, B b) {
108      return new Tuple2<>(a, b);
109   }
110
111   private final A a;
112   private final B b;
113   private final int hashCode;
114
115   /**
116    * Constructor.
117    *
118    * @param a Object 1.  Can be <jk>null</jk>.
119    * @param b Object 2.  Can be <jk>null</jk>.
120    */
121   public Tuple2(A a, B b) {
122      this.a = a;
123      this.b = b;
124      this.hashCode = h(a, b);
125   }
126
127   @Override /* Overridden from Object */
128   public boolean equals(Object o) {
129      return o instanceof Tuple2<?,?> o2 && eq(this, o2, (x, y) -> eq(x.a, y.a) && eq(x.b, y.b));
130   }
131
132   /**
133    * Returns the first value in this tuple.
134    *
135    * <h5 class='section'>Example:</h5>
136    * <p class='bjava'>
137    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
138    *    String <jv>first</jv> = <jv>tuple</jv>.getA();  <jc>// Returns "hello"</jc>
139    * </p>
140    *
141    * @return The first value in this tuple.
142    */
143   public A getA() { return a; }
144
145   /**
146    * Returns the second value in this tuple.
147    *
148    * <h5 class='section'>Example:</h5>
149    * <p class='bjava'>
150    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
151    *    Integer <jv>second</jv> = <jv>tuple</jv>.getB();  <jc>// Returns 42</jc>
152    * </p>
153    *
154    * @return The second value in this tuple.
155    */
156   public B getB() { return b; }
157
158   /**
159    * Returns the first value in this tuple wrapped in an {@link Optional}.
160    *
161    * <h5 class='section'>Example:</h5>
162    * <p class='bjava'>
163    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
164    *    Optional&lt;String&gt; <jv>first</jv> = <jv>tuple</jv>.optA();  <jc>// Returns Optional.of("hello")</jc>
165    *
166    *    Tuple2&lt;String,Integer&gt; <jv>tuple2</jv> = Tuple2.<jsm>of</jsm>(<jk>null</jk>, 42);
167    *    Optional&lt;String&gt; <jv>first2</jv> = <jv>tuple2</jv>.optA();  <jc>// Returns Optional.empty()</jc>
168    * </p>
169    *
170    * @return The first value wrapped in an Optional, or Optional.empty() if the value is null.
171    */
172   public Optional<A> optA() {
173      return o(a);
174   }
175
176   /**
177    * Returns the second value in this tuple wrapped in an {@link Optional}.
178    *
179    * <h5 class='section'>Example:</h5>
180    * <p class='bjava'>
181    *    Tuple2&lt;String,Integer&gt; <jv>tuple</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, 42);
182    *    Optional&lt;Integer&gt; <jv>second</jv> = <jv>tuple</jv>.optB();  <jc>// Returns Optional.of(42)</jc>
183    *
184    *    Tuple2&lt;String,Integer&gt; <jv>tuple2</jv> = Tuple2.<jsm>of</jsm>(<js>"hello"</js>, <jk>null</jk>);
185    *    Optional&lt;Integer&gt; <jv>second2</jv> = <jv>tuple2</jv>.optB();  <jc>// Returns Optional.empty()</jc>
186    * </p>
187    *
188    * @return The second value wrapped in an Optional, or Optional.empty() if the value is null.
189    */
190   public Optional<B> optB() {
191      return o(b);
192   }
193
194   @Override /* Overridden from Object */
195   public int hashCode() {
196      return hashCode;
197   }
198}