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) 2007-2012 Pentaho
008// All Rights Reserved.
009*/
010package mondrian.util;
011
012import mondrian.olap.Util;
013
014import java.util.*;
015
016/**
017 * Pair of values.
018 *
019 * <p>Because a pair implements {@link #equals(Object)}, {@link #hashCode()} and
020 * {@link #compareTo(Pair)}, it can be used in any kind of
021 * {@link java.util.Collection}.
022 *
023 * @author jhyde
024 * @since Apr 19, 2007
025 */
026public class Pair <L, R>
027    implements Comparable<Pair<L, R>>, Map.Entry<L, R>
028{
029    public L left;
030    public R right;
031
032    /**
033     * Creates a pair.
034     *
035     * @param left Left value
036     * @param right Right value
037     */
038    public Pair(L left, R right) {
039        this.left = left;
040        this.right = right;
041    }
042
043    /**
044     * Creates a pair representing the same mapping as the
045     * specified entry.
046     *
047     * @param entry the entry to copy
048     */
049    public Pair(Map.Entry<? extends L, ? extends R> entry) {
050        this.left = entry.getKey();
051        this.right = entry.getValue();
052    }
053
054    /**
055     * Creates a Pair.
056     *
057     * @param left Left value
058     * @param right Right value
059     * @return a new Pair
060     */
061    public static <L, R> Pair<L, R> of(L left, R right) {
062        return new Pair<L, R>(left, right);
063    }
064
065    public boolean equals(Object obj) {
066        if (obj instanceof Pair) {
067            //noinspection unchecked
068            Pair<L, R> pair = (Pair) obj;
069            return Util.equals(this.left, pair.left)
070                && Util.equals(this.right, pair.right);
071        }
072        return false;
073    }
074
075    public int hashCode() {
076        int k = (left == null) ? 0 : left.hashCode();
077        int k1 = (right == null) ? 0 : right.hashCode();
078        return ((k << 4) | k) ^ k1;
079    }
080
081
082    public int compareTo(Pair<L, R> that) {
083        int c = compare((Comparable) this.left, (Comparable)that.left);
084        if (c == 0) {
085            c = compare((Comparable) this.right, (Comparable)that.right);
086        }
087        return c;
088    }
089
090    public String toString() {
091        return "<" + left + ", " + right + ">";
092    }
093
094    // implement Map.Entry
095    public L getKey() {
096        return left;
097    }
098
099    // implement Map.Entry
100    public R getValue() {
101        return right;
102    }
103
104    // implement Map.Entry
105    public R setValue(R value) {
106        R previous = right;
107        right = value;
108        return previous;
109    }
110
111    /**
112     * Compares a pair of comparable values of the same type. Null collates
113     * less than everything else, but equal to itself.
114     *
115     * @param c1 First value
116     * @param c2 Second value
117     * @return  a negative integer, zero, or a positive integer if c1
118     *          is less than, equal to, or greater than c2.
119     */
120    private static <C extends Comparable<C>> int compare(C c1, C c2) {
121        if (c1 == null) {
122            if (c2 == null) {
123                return 0;
124            } else {
125                return -1;
126            }
127        } else if (c2 == null) {
128            return 1;
129        } else {
130            return c1.compareTo(c2);
131        }
132    }
133
134    /**
135     * Returns an iterable over the left slice of an iterable.
136     *
137     * @param iterable Iterable over pairs
138     * @param <L> Left type
139     * @param <R> Right type
140     * @return Iterable over the left elements
141     */
142    public static <L, R> Iterable<L> leftIter(
143        final Iterable<Pair<L, R>> iterable)
144    {
145        return new Iterable<L>() {
146            public Iterator<L> iterator() {
147                final Iterator<Pair<L, R>> iterator = iterable.iterator();
148                return new Iterator<L>() {
149                    public boolean hasNext() {
150                        return iterator.hasNext();
151                    }
152
153                    public L next() {
154                        return iterator.next().left;
155                    }
156
157                    public void remove() {
158                        iterator.remove();
159                    }
160                };
161            }
162        };
163    }
164
165    /**
166     * Returns an iterable over the right slice of an iterable.
167     *
168     * @param iterable Iterable over pairs
169     * @param <L> right type
170     * @param <R> Right type
171     * @return Iterable over the right elements
172     */
173    public static <L, R> Iterable<R> rightIter(
174        final Iterable<Pair<L, R>> iterable)
175    {
176        return new Iterable<R>() {
177            public Iterator<R> iterator() {
178                final Iterator<Pair<L, R>> iterator = iterable.iterator();
179                return new Iterator<R>() {
180                    public boolean hasNext() {
181                        return iterator.hasNext();
182                    }
183
184                    public R next() {
185                        return iterator.next().right;
186                    }
187
188                    public void remove() {
189                        iterator.remove();
190                    }
191                };
192            }
193        };
194    }
195
196    /**
197     * Returns a list of the left elements of a list of pairs.
198     */
199    public static <L, R> List<L> left(final List<Pair<L, R>> list) {
200        return new AbstractList<L>() {
201            public L get(int index) {
202                return list.get(index).left;
203            }
204
205            public int size() {
206                return list.size();
207            }
208
209            public L remove(int index) {
210                Pair<L, R> pair = list.remove(index);
211                return pair == null ? null : pair.left;
212            }
213        };
214    }
215
216    /**
217     * Returns a list of the right elements of a list of pairs.
218     */
219    public static <L, R> List<R> right(final List<Pair<L, R>> list) {
220        return new AbstractList<R>() {
221            public R get(int index) {
222                return list.get(index).right;
223            }
224
225            public int size() {
226                return list.size();
227            }
228
229            public R remove(int index) {
230                Pair<L, R> pair = list.remove(index);
231                return pair == null ? null : pair.right;
232            }
233        };
234    }
235}
236
237// End Pair.java