001/*
002// This software is subject to the terms of the Eclipse Public License v1.0
003// Agreement, available at the following URL:
004// http://www.eclipse.org/legal/epl-v10.html.
005// You must accept the terms of that agreement to use this software.
006//
007// Copyright (C) 2011-2012 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.util;
011
012import mondrian.olap.Util;
013
014import java.util.Iterator;
015
016/**
017 * Tuple of three values.
018 *
019 * <p>Because a triple implements {@link #equals(Object)}, {@link #hashCode()}
020 * and {@link #compareTo(mondrian.util.Triple)}, it can be used in any kind of
021 * {@link java.util.Collection}.
022 *
023 * @author jhyde
024 */
025public class Triple<T0, T1, T2>
026    implements Comparable<Triple<T0, T1, T2>>
027{
028    public T0 v0;
029    public T1 v1;
030    public T2 v2;
031
032    /**
033     * Creates a Triple.
034     *
035     * @param v0 Value #0
036     * @param v1 Value #1
037     * @param v2 Value #2
038     */
039    public Triple(T0 v0, T1 v1, T2 v2) {
040        this.v0 = v0;
041        this.v1 = v1;
042        this.v2 = v2;
043    }
044
045    /**
046     * Creates a Triple.
047     *
048     * @param v0 Value #0
049     * @param v1 Value #1
050     * @param v2 Value #2
051     * @return a new Triple
052     */
053    public static <T0, T1, T2> Triple<T0, T1, T2> of(T0 v0, T1 v1, T2 v2) {
054        return new Triple<T0, T1, T2>(v0, v1, v2);
055    }
056
057    public boolean equals(Object obj) {
058        if (obj instanceof Triple) {
059            //noinspection unchecked
060            Triple<T0, T1, T2> pair = (Triple) obj;
061            return Util.equals(this.v0, pair.v0)
062                && Util.equals(this.v1, pair.v1)
063                && Util.equals(this.v2, pair.v2);
064        }
065        return false;
066    }
067
068    public int hashCode() {
069        int k0 = (v0 == null) ? 0 : v0.hashCode();
070        int k1 = (v1 == null) ? 0 : v1.hashCode();
071        int k2 = (v2 == null) ? 0 : v2.hashCode();
072        return ((k0 << 8) | k0) ^ (k1 << 4 | k1) ^ k2;
073    }
074
075
076    public int compareTo(Triple<T0, T1, T2> that) {
077        int c = compare((Comparable) this.v0, (Comparable)that.v0);
078        if (c == 0) {
079            c = compare((Comparable) this.v1, (Comparable)that.v1);
080        }
081        if (c == 0) {
082            c = compare((Comparable) this.v2, (Comparable)that.v2);
083        }
084        return c;
085    }
086
087    public String toString() {
088        return "<" + v0 + ", " + v1 + ", " + v2 + ">";
089    }
090
091    /**
092     * Compares a pair of comparable values of the same type. Null collates
093     * less than everything else, but equal to itself.
094     *
095     * @param c1 First value
096     * @param c2 Second value
097     * @return  a negative integer, zero, or a positive integer if c1
098     *          is less than, equal to, or greater than c2.
099     */
100    private static <C extends Comparable<C>> int compare(C c1, C c2) {
101        if (c1 == null) {
102            if (c2 == null) {
103                return 0;
104            } else {
105                return -1;
106            }
107        } else if (c2 == null) {
108            return 1;
109        } else {
110            return c1.compareTo(c2);
111        }
112    }
113
114    /**
115     * Returns an iterable over the slice #0 of an iterable.
116     *
117     * @param iterable Iterable over triples
118     * @param <T0> Type #0
119     * @param <T1> Type #1
120     * @param <T2> Type #2
121     * @return Iterable over the 0'th elements of each triple
122     */
123    public static <T0, T1, T2> Iterable<T0> iter0(
124        final Iterable<Triple<T0, T1, T2>> iterable)
125    {
126        return new Iterable<T0>() {
127            public Iterator<T0> iterator() {
128                final Iterator<Triple<T0, T1, T2>> iterator =
129                    iterable.iterator();
130                return new Iterator<T0>() {
131                    public boolean hasNext() {
132                        return iterator.hasNext();
133                    }
134
135                    public T0 next() {
136                        return iterator.next().v0;
137                    }
138
139                    public void remove() {
140                        iterator.remove();
141                    }
142                };
143            }
144        };
145    }
146
147    /**
148     * Returns an iterable over the slice #1 of an iterable.
149     *
150     * @param iterable Iterable over triples
151     * @param <T0> Type #0
152     * @param <T1> Type #1
153     * @param <T2> Type #2
154     * @return Iterable over the 1'th elements of each triple
155     */
156    public static <T0, T1, T2> Iterable<T1> iter1(
157        final Iterable<Triple<T0, T1, T2>> iterable)
158    {
159        return new Iterable<T1>() {
160            public Iterator<T1> iterator() {
161                final Iterator<Triple<T0, T1, T2>> iterator =
162                    iterable.iterator();
163                return new Iterator<T1>() {
164                    public boolean hasNext() {
165                        return iterator.hasNext();
166                    }
167
168                    public T1 next() {
169                        return iterator.next().v1;
170                    }
171
172                    public void remove() {
173                        iterator.remove();
174                    }
175                };
176            }
177        };
178    }
179    /**
180     * Returns an iterable over the slice #2 of an iterable.
181     *
182     * @param iterable Iterable over triples
183     * @param <T0> Type #0
184     * @param <T1> Type #1
185     * @param <T2> Type #2
186     * @return Iterable over the 2'th elements of each triple
187     */
188    public static <T0, T1, T2> Iterable<T2> iter2(
189        final Iterable<Triple<T0, T1, T2>> iterable)
190    {
191        return new Iterable<T2>() {
192            public Iterator<T2> iterator() {
193                final Iterator<Triple<T0, T1, T2>> iterator =
194                    iterable.iterator();
195                return new Iterator<T2>() {
196                    public boolean hasNext() {
197                        return iterator.hasNext();
198                    }
199
200                    public T2 next() {
201                        return iterator.next().v2;
202                    }
203
204                    public void remove() {
205                        iterator.remove();
206                    }
207                };
208            }
209        };
210    }
211}
212
213// End Triple.java