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 }