001package org.clafer.collection;
002
003import java.lang.reflect.Array;
004import java.util.ArrayList;
005import java.util.List;
006import org.clafer.common.Check;
007
008/**
009 * A 3-tuple.
010 *
011 *
012 * @param <A> the type of fst
013 * @param <B> the type of snd
014 * @param <C> the type of thd
015 * @author jimmy
016 */
017public class Triple<A, B, C> {
018
019    private final A fst;
020    private final B snd;
021    private final C thd;
022
023    public Triple(A fst, B snd, C thd) {
024        this.fst = Check.notNull(fst);
025        this.snd = Check.notNull(snd);
026        this.thd = Check.notNull(thd);
027    }
028
029    public Triple(Pair<? extends A, ? extends B> pair, C thd) {
030        this(pair.getFst(), pair.getSnd(), thd);
031    }
032
033    public Triple(A fst, Pair<? extends B, ? extends C> pair) {
034        this(fst, pair.getFst(), pair.getSnd());
035    }
036
037    public Triple(Triple<? extends A, ? extends B, ? extends C> triple) {
038        this(triple.getFst(), triple.getSnd(), triple.getThd());
039    }
040
041    public A getFst() {
042        return fst;
043    }
044
045    public B getSnd() {
046        return snd;
047    }
048
049    public C getThd() {
050        return thd;
051    }
052
053    public Pair<A, B> getFstSnd() {
054        return new Pair<>(fst, snd);
055    }
056
057    public Pair<B, C> getSndThd() {
058        return new Pair<>(snd, thd);
059    }
060
061    /**
062     * Returns the first element of the tuples in the same order. Equivalent to
063     * the Haskell code {@code map fst}.
064     *
065     * @param <A> the type of first element in the pairs
066     * @param <B> the type of second element in the pairs
067     * @param <C> the type of third element in the pairs
068     * @param triples the tuples
069     * @return the first element of the tuples
070     */
071    public static <A, B, C> List<A> mapFst(List<Triple<A, B, C>> triples) {
072        List<A> fsts = new ArrayList<>(triples.size());
073        for (Triple<A, B, C> triple : triples) {
074            fsts.add(triple.getFst());
075        }
076        return fsts;
077    }
078
079    /**
080     * Returns the first element of the tuples in the same order. Equivalent to
081     * the Haskell code {@code map fst}.
082     *
083     * @param <A> the type of first element in the pairs
084     * @param <B> the type of second element in the pairs
085     * @param <C> the type of third element in the pairs
086     * @param triples the tuples
087     * @param array the array to write to if the size is correct
088     * @return the first element of the tuples
089     */
090    @SafeVarargs
091    public static <A, B, C> A[] mapFst(Triple<A, B, C>[] triples, A... array) {
092        @SuppressWarnings("unchecked")
093        A[] to = array.length == triples.length
094                ? array
095                : (A[]) Array.newInstance(array.getClass().getComponentType(), triples.length);
096        for (int i = 0; i < to.length; i++) {
097            to[i] = triples[i].getFst();
098        }
099        return to;
100    }
101
102    /**
103     * Returns the second element of the tuples in the same order. Equivalent to
104     * the Haskell code {@code map snd}.
105     *
106     * @param <A> the type of first element in the pairs
107     * @param <B> the type of second element in the pairs
108     * @param <C> the type of third element in the pairs
109     * @param triples the tuples
110     * @return the second element of the tuples
111     */
112    public static <A, B, C> List<B> mapSnd(List<Triple<A, B, C>> triples) {
113        List<B> snds = new ArrayList<>(triples.size());
114        for (Triple<A, B, C> triple : triples) {
115            snds.add(triple.getSnd());
116        }
117        return snds;
118    }
119
120    /**
121     * Returns the second element of the tuples in the same order. Equivalent to
122     * the Haskell code {@code map snd}.
123     *
124     * @param <A> the type of first element in the pairs
125     * @param <B> the type of second element in the pairs
126     * @param <C> the type of third element in the pairs
127     * @param triples the tuples
128     * @param array the array to write to if the size is correct
129     * @return the second element of the tuples
130     */
131    @SafeVarargs
132    public static <A, B, C> B[] mapSnd(Triple<A, B, C>[] triples, B... array) {
133        @SuppressWarnings("unchecked")
134        B[] to = array.length == triples.length
135                ? array
136                : (B[]) Array.newInstance(array.getClass().getComponentType(), triples.length);
137        for (int i = 0; i < to.length; i++) {
138            to[i] = triples[i].getSnd();
139        }
140        return to;
141    }
142
143    /**
144     * Returns the third element of the tuples in the same order. Equivalent to
145     * the Haskell code {@code map thd}.
146     *
147     * @param <A> the type of first element in the pairs
148     * @param <B> the type of second element in the pairs
149     * @param <C> the type of third element in the pairs
150     * @param triples the tuples
151     * @return the third element of the tuples
152     */
153    public static <A, B, C> List<C> mapThd(List<Triple<A, B, C>> triples) {
154        List<C> thds = new ArrayList<>(triples.size());
155        for (Triple<A, B, C> triple : triples) {
156            thds.add(triple.getThd());
157        }
158        return thds;
159    }
160
161    /**
162     * Returns the third element of the tuples in the same order. Equivalent to
163     * the Haskell code {@code map thd}.
164     *
165     * @param <A> the type of first element in the pairs
166     * @param <B> the type of second element in the pairs
167     * @param <C> the type of third element in the pairs
168     * @param triples the tuples
169     * @param array the array to write to if the size is correct
170     * @return the third element of the tuples
171     */
172    @SafeVarargs
173    public static <A, B, C> C[] mapThd(Triple<A, B, C>[] triples, C... array) {
174        @SuppressWarnings("unchecked")
175        C[] to = array.length == triples.length
176                ? array
177                : (C[]) Array.newInstance(array.getClass().getComponentType(), triples.length);
178        for (int i = 0; i < to.length; i++) {
179            to[i] = triples[i].getThd();
180        }
181        return to;
182    }
183
184    @Override
185    public boolean equals(Object obj) {
186        if (obj instanceof Triple<?, ?, ?>) {
187            Triple<?, ?, ?> other = (Triple<?, ?, ?>) obj;
188            return fst.equals(other.fst) && snd.equals(other.snd) && thd.equals(other.thd);
189        }
190        return false;
191    }
192
193    @Override
194    public int hashCode() {
195        return fst.hashCode() ^ snd.hashCode() ^ thd.hashCode();
196    }
197
198    @Override
199    public String toString() {
200        return "(" + fst + ", " + snd + ", " + thd + ")";
201    }
202}