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.commons.lang3.tuple;
018
019import java.io.Serializable;
020import java.util.Objects;
021
022import org.apache.commons.lang3.builder.CompareToBuilder;
023
024/**
025 * <p>A triple consisting of three elements.</p>
026 *
027 * <p>This class is an abstract implementation defining the basic API.
028 * It refers to the elements as 'left', 'middle' and 'right'.</p>
029 *
030 * <p>Subclass implementations may be mutable or immutable.
031 * However, there is no restriction on the type of the stored objects that may be stored.
032 * If mutable objects are stored in the triple, then the triple itself effectively becomes mutable.</p>
033 *
034 * @param <L> the left element type
035 * @param <M> the middle element type
036 * @param <R> the right element type
037 *
038 * @since 3.2
039 */
040public abstract class Triple<L, M, R> implements Comparable<Triple<L, M, R>>, Serializable {
041
042    private static final class TripleAdapter<L, M, R> extends Triple<L, M, R> {
043
044        private static final long serialVersionUID = 1L;
045
046        @Override
047        public L getLeft() {
048            return null;
049        }
050
051        @Override
052        public M getMiddle() {
053            return null;
054        }
055
056        @Override
057        public R getRight() {
058            return null;
059        }
060
061    }
062
063    /** Serialization version */
064    private static final long serialVersionUID = 1L;
065
066    /**
067     * An empty array.
068     * <p>
069     * Consider using {@link #emptyArray()} to avoid generics warnings.
070     * </p>
071     *
072     * @since 3.10.
073     */
074    public static final Triple<?, ?, ?>[] EMPTY_ARRAY = new TripleAdapter[0];
075
076    /**
077     * Returns the empty array singleton that can be assigned without compiler warning.
078     *
079     * @param <L> the left element type
080     * @param <M> the middle element type
081     * @param <R> the right element type
082     * @return the empty array singleton that can be assigned without compiler warning.
083     *
084     * @since 3.10.
085     */
086    @SuppressWarnings("unchecked")
087    public static <L, M, R> Triple<L, M, R>[] emptyArray() {
088        return (Triple<L, M, R>[]) EMPTY_ARRAY;
089    }
090
091    /**
092     * <p>Obtains an immutable triple of three objects inferring the generic types.</p>
093     *
094     * <p>This factory allows the triple to be created using inference to
095     * obtain the generic types.</p>
096     *
097     * @param <L> the left element type
098     * @param <M> the middle element type
099     * @param <R> the right element type
100     * @param left  the left element, may be null
101     * @param middle the middle element, may be null
102     * @param right  the right element, may be null
103     * @return a triple formed from the three parameters, not null
104     */
105    public static <L, M, R> Triple<L, M, R> of(final L left, final M middle, final R right) {
106        return new ImmutableTriple<>(left, middle, right);
107    }
108
109    //-----------------------------------------------------------------------
110    /**
111     * <p>Compares the triple based on the left element, followed by the middle element,
112     * finally the right element.
113     * The types must be {@code Comparable}.</p>
114     *
115     * @param other  the other triple, not null
116     * @return negative if this is less, zero if equal, positive if greater
117     */
118    @Override
119    public int compareTo(final Triple<L, M, R> other) {
120      return new CompareToBuilder().append(getLeft(), other.getLeft())
121          .append(getMiddle(), other.getMiddle())
122          .append(getRight(), other.getRight()).toComparison();
123    }
124
125    /**
126     * <p>Compares this triple to another based on the three elements.</p>
127     *
128     * @param obj  the object to compare to, null returns false
129     * @return true if the elements of the triple are equal
130     */
131    @Override
132    public boolean equals(final Object obj) {
133        if (obj == this) {
134            return true;
135        }
136        if (obj instanceof Triple<?, ?, ?>) {
137            final Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
138            return Objects.equals(getLeft(), other.getLeft())
139                && Objects.equals(getMiddle(), other.getMiddle())
140                && Objects.equals(getRight(), other.getRight());
141        }
142        return false;
143    }
144
145    //-----------------------------------------------------------------------
146    /**
147     * <p>Gets the left element from this triple.</p>
148     *
149     * @return the left element, may be null
150     */
151    public abstract L getLeft();
152
153    /**
154     * <p>Gets the middle element from this triple.</p>
155     *
156     * @return the middle element, may be null
157     */
158    public abstract M getMiddle();
159
160    /**
161     * <p>Gets the right element from this triple.</p>
162     *
163     * @return the right element, may be null
164     */
165    public abstract R getRight();
166
167    /**
168     * <p>Returns a suitable hash code.</p>
169     *
170     * @return the hash code
171     */
172    @Override
173    public int hashCode() {
174        return (getLeft() == null ? 0 : getLeft().hashCode()) ^
175            (getMiddle() == null ? 0 : getMiddle().hashCode()) ^
176            (getRight() == null ? 0 : getRight().hashCode());
177    }
178
179    /**
180     * <p>Returns a String representation of this triple using the format {@code ($left,$middle,$right)}.</p>
181     *
182     * @return a string describing this object, not null
183     */
184    @Override
185    public String toString() {
186        return "(" + getLeft() + "," + getMiddle() + "," + getRight() + ")";
187    }
188
189    /**
190     * <p>Formats the receiver using the given format.</p>
191     *
192     * <p>This uses {@link java.util.Formattable} to perform the formatting. Three variables may
193     * be used to embed the left and right elements. Use {@code %1$s} for the left
194     * element, {@code %2$s} for the middle and {@code %3$s} for the right element.
195     * The default format used by {@code toString()} is {@code (%1$s,%2$s,%3$s)}.</p>
196     *
197     * @param format  the format string, optionally containing {@code %1$s}, {@code %2$s} and {@code %3$s}, not null
198     * @return the formatted string, not null
199     */
200    public String toString(final String format) {
201        return String.format(format, getLeft(), getMiddle(), getRight());
202    }
203
204}
205