001 /*--------------------------------------------------------------------------+
002 $Id: ImmutablePair.java 26268 2010-02-18 10:44:30Z juergens $
003 | |
004 | Copyright 2005-2010 Technische Universitaet Muenchen |
005 | |
006 | Licensed under the Apache License, Version 2.0 (the "License"); |
007 | you may not use this file except in compliance with the License. |
008 | You may obtain a copy of the License at |
009 | |
010 | http://www.apache.org/licenses/LICENSE-2.0 |
011 | |
012 | Unless required by applicable law or agreed to in writing, software |
013 | distributed under the License is distributed on an "AS IS" BASIS, |
014 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
015 | See the License for the specific language governing permissions and |
016 | limitations under the License. |
017 +--------------------------------------------------------------------------*/
018 package edu.tum.cs.commons.collections;
019
020 import edu.tum.cs.commons.clone.CloneUtils;
021 import edu.tum.cs.commons.clone.DeepCloneException;
022 import edu.tum.cs.commons.clone.IDeepCloneable;
023
024 /**
025 * Simple readonly pair class.
026 *
027 * @author hummelb
028 * @author $Author: juergens $
029 * @version $Rev: 26268 $
030 * @levd.rating GREEN Hash: 8C6F4981DA02F9D8D8CFF01534F52D67
031 */
032 public class ImmutablePair<S, T> implements Cloneable, IDeepCloneable,
033 Comparable<ImmutablePair<S, T>> {
034
035 /** The first element. */
036 protected S first;
037
038 /** The second element. */
039 protected T second;
040
041 /** Constructor. */
042 public ImmutablePair(S first, T second) {
043 this.first = first;
044 this.second = second;
045 }
046
047 /** Copy constructor. */
048 public ImmutablePair(ImmutablePair<S, T> p) {
049 this.first = p.first;
050 this.second = p.second;
051 }
052
053 /** Returns the first element of the pair. */
054 public S getFirst() {
055 return first;
056 }
057
058 /** Returns the second element of the pair. */
059 public T getSecond() {
060 return second;
061 }
062
063 /** {@inheritDoc} */
064 @Override
065 public boolean equals(Object obj) {
066 if (!(obj instanceof ImmutablePair<?, ?>)) {
067 return false;
068 }
069 ImmutablePair<?, ?> p = (ImmutablePair<?, ?>) obj;
070 return areEqual(first, p.first) && areEqual(second, p.second);
071 }
072
073 /** Returns true if either both are <code>null</code> or they are equal. */
074 private boolean areEqual(Object o1, Object o2) {
075 if (o1 == null) {
076 return o2 == null;
077 }
078 return o1.equals(o2);
079 }
080
081 /**
082 * {@inheritDoc}
083 * <p>
084 * The hash code is based on the hash code of the first and second members.
085 */
086 @Override
087 public int hashCode() {
088 int firstCode = 1;
089 if (first != null) {
090 firstCode = first.hashCode();
091 }
092
093 int secondCode = 1;
094 if (second != null) {
095 secondCode = second.hashCode();
096 }
097
098 return firstCode + 1013 * secondCode;
099 }
100
101 /** {@inheritDoc} */
102 @Override
103 public String toString() {
104 return "(" + first + "," + second + ")";
105 }
106
107 /** {@inheritDoc} */
108 @Override
109 protected ImmutablePair<S, T> clone() {
110 return new ImmutablePair<S, T>(this);
111 }
112
113 /** {@inheritDoc} */
114 @SuppressWarnings("unchecked")
115 public ImmutablePair<S, T> deepClone() throws DeepCloneException {
116 S newFirst = (S) CloneUtils.cloneAsDeepAsPossible(first);
117 T newSecond = (T) CloneUtils.cloneAsDeepAsPossible(second);
118 return new ImmutablePair<S, T>(newFirst, newSecond);
119 }
120
121 /**
122 * {@inheritDoc}
123 * <p>
124 * Compare based on first element. Use second element only if first elements
125 * are equal. Null entries are sorted to the top.
126 */
127 public int compareTo(ImmutablePair<S, T> pair) {
128 int cmp = objCompare(first, pair.first);
129 if (cmp != 0) {
130 return cmp;
131 }
132 return objCompare(second, pair.second);
133 }
134
135 /**
136 * Performs comparison on two arbitrary objects of the same type.
137 */
138 @SuppressWarnings("unchecked")
139 private <O> int objCompare(O o1, O o2) {
140 if (o1 == null) {
141 if (o2 == null) {
142 return 0;
143 }
144 return -1;
145 } else if (o2 == null) {
146 return 1;
147 }
148
149 if ((o1 instanceof Comparable) && (o2 instanceof Comparable)) {
150 try {
151 ((Comparable<Object>) o1).compareTo(o2);
152 } catch (ClassCastException e) {
153 // somehow failed, so continue and treat as if not comparable
154 }
155 }
156
157 // compare using hash code, so we get at least an approximation of an
158 // ordering
159 int h1 = o1.hashCode();
160 int h2 = o2.hashCode();
161
162 if (h1 == h2) {
163 return 0;
164 }
165 if (h1 < h2) {
166 return -1;
167 }
168 return 1;
169 }
170 }