001package components.map; 002 003/** 004 * Layered implementations of secondary methods for {@code Map}. 005 * 006 * @param <K> 007 * type of {@code Map} domain (key) entries 008 * @param <V> 009 * type of {@code Map} range (associated value) entries 010 */ 011public abstract class MapSecondary<K, V> implements Map<K, V> { 012 013 /* 014 * Protected members ------------------------------------------------------ 015 */ 016 017 /** 018 * Straightforward implementation of {@code Pair} interface. 019 * 020 * @param <K> 021 * type of {@code Pair} first entry ({@code Map} key entry) 022 * @param <V> 023 * type of {@code Pair} second entry ({@code Map} value entry) 024 */ 025 protected static final class SimplePair<K, V> implements Pair<K, V> { 026 027 /** 028 * The key. 029 */ 030 private final K key; 031 /** 032 * The value. 033 */ 034 private final V value; 035 036 /** 037 * Constructor. 038 * 039 * @param key 040 * the key 041 * @param value 042 * the value 043 */ 044 public SimplePair(K key, V value) { 045 this.key = key; 046 this.value = value; 047 } 048 049 @Override 050 public K key() { 051 return this.key; 052 } 053 054 @Override 055 public V value() { 056 return this.value; 057 } 058 059 @Override 060 public boolean equals(Object obj) { 061 if (obj == this) { 062 return true; 063 } 064 if (obj == null) { 065 return false; 066 } 067 if (!(obj instanceof Pair<?, ?>)) { 068 return false; 069 } 070 Pair<?, ?> pair = (Pair<?, ?>) obj; 071 return this.key.equals(pair.key()) && this.value.equals(pair.value()); 072 } 073 074 @Override 075 public int hashCode() { 076 return this.key.hashCode() + this.value.hashCode(); 077 } 078 079 @Override 080 public String toString() { 081 return "(" + this.key + "," + this.value + ")"; 082 } 083 084 } 085 086 /* 087 * Private members -------------------------------------------------------- 088 */ 089 090 /** 091 * Reports a key associated with {@code value} in {@code m} if such a key 092 * exists, or {@code null} otherwise. 093 * 094 * @param <K> 095 * type of {@code Map} domain (key) entries 096 * @param <V> 097 * type of {@code Map} range (associated value) entries 098 * @param m 099 * the map in which to look for the given value 100 * @param value 101 * the value whose associated key is to be reported 102 * @return a key associated with value 103 * @aliases reference returned by {@code keyForMap}, if such a key exists 104 * @ensures <pre> 105 * if value is in RANGE(m) 106 * then (keyForMap, value) is in m 107 * else [keyForMap is null] 108 * </pre> 109 */ 110 private static <K, V> K keyForMap(Map<K, V> m, V value) { 111 assert m != null : "Violation of: m is not null"; 112 assert value != null : "Violation of: value is not null"; 113 K foundKey = null; 114 /** 115 * @maintains <pre> 116 * value is not in 117 * {key: K, val: V 118 * where ((key, val) is in m and key is in entries(~m.seen)) 119 * (val)} 120 * </pre> 121 */ 122 for (Pair<K, V> pair : m) { 123 if (pair.value().equals(value)) { 124 foundKey = pair.key(); 125 break; 126 } 127 } 128 return foundKey; 129 } 130 131 /* 132 * Public members --------------------------------------------------------- 133 */ 134 135 /* 136 * Common methods (from Object) ------------------------------------------- 137 */ 138 139 @Override 140 public final boolean equals(Object obj) { 141 if (obj == this) { 142 return true; 143 } 144 if (obj == null) { 145 return false; 146 } 147 if (!(obj instanceof Map<?, ?>)) { 148 return false; 149 } 150 /* 151 * This feels like it can't be the right way to do this, but it compiles 152 * with only an "unchecked cast" warning (and the cast cannot fail 153 * because of type erasure). Using wildcard parameters prevents the loop 154 * from compiling. So, it's still a question how it should be done! 155 * Also, there is the technical question of whether it is possible to 156 * tell whether two empty Maps (with different K and V) are equal; seems 157 * not. 158 */ 159 @SuppressWarnings("unchecked") 160 Map<K, V> m = (Map<K, V>) obj; 161 if (this.size() != m.size()) { 162 return false; 163 } 164 /* 165 * |this| = |m|, so every (key, value) pair in this is also in m iff 166 * this = m. 167 */ 168 for (Pair<K, V> pair : this) { 169 if (!m.hasKey(pair.key())) { 170 return false; 171 } else if (!pair.value().equals(m.value(pair.key()))) { 172 return false; 173 } 174 } 175 return true; 176 } 177 178 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 179 @Override 180 public int hashCode() { 181 final int a = 37; 182 final int b = 17; 183 int result = 0; 184 /* 185 * This code does not run in O(1) time. Perhaps a better hash function 186 * would be to return the size; there just doesn't seem to be anything 187 * in between! 188 */ 189 for (Pair<K, V> pair : this) { 190 result += a * pair.key().hashCode() + b * pair.value().hashCode(); 191 } 192 return result; 193 } 194 195 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 196 @Override 197 public String toString() { 198 StringBuilder result = new StringBuilder("{"); 199 boolean first = true; 200 for (Pair<K, V> pair : this) { 201 if (first) { 202 first = false; 203 } else { 204 result.append(","); 205 } 206 result.append(pair.toString()); 207 } 208 result.append("}"); 209 return result.toString(); 210 } 211 212 /* 213 * Other non-kernel methods ----------------------------------------------- 214 */ 215 216 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 217 @Override 218 public V replaceValue(K key, V value) { 219 assert key != null : "Violation of: key is not null"; 220 assert value != null : "Violation of: value is not null"; 221 assert this.hasKey(key) : "Violation of: key is in DOMAIN(this)"; 222 MapSecondary.Pair<K, V> p = this.remove(key); 223 this.add(p.key(), value); 224 return p.value(); 225 } 226 227 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 228 @Override 229 public K key(V value) { 230 assert value != null : "Violation of: value is not null"; 231 K foundKey = keyForMap(this, value); 232 assert foundKey != null : "Violation of: value is in RANGE(this)"; 233 return foundKey; 234 } 235 236 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 237 @Override 238 public boolean hasValue(V value) { 239 assert value != null : "Violation of: value is not null"; 240 K foundKey = keyForMap(this, value); 241 return foundKey != null; 242 } 243 244 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 245 @Override 246 public boolean sharesKeyWith(Map<K, V> m) { 247 assert m != null : "Violation of: m is not null"; 248 assert m != this : "Violation of: m is not this"; 249 boolean found = false; 250 /** 251 * @maintains <pre> 252 * if key is in entries(~this.seen) 253 * then key is not in DOMAIN(m) 254 * </pre> 255 */ 256 for (Pair<K, V> pair : this) { 257 if (m.hasKey(pair.key())) { 258 found = true; 259 break; 260 } 261 } 262 return found; 263 } 264 265 // CHECKSTYLE: ALLOW THIS METHOD TO BE OVERRIDDEN 266 @Override 267 public void combineWith(Map<K, V> m) { 268 assert m != null : "Violation of: m is not null"; 269 assert m != this : "Violation of: m is not this"; 270 assert !this.sharesKeyWith(m) 271 : "Violation of: " + "DOMAIN(this) intersection DOMAIN(m) = {}"; 272 /** 273 * @updates this 274 * @maintains <pre> 275 * this = #this union 276 * {key: K, value: V 277 * where ((key, value) is in m and 278 * key is in entries(~m.seen)) 279 * ((key, value))} 280 * </pre> 281 * @decreases |~m.unseen| 282 */ 283 for (Pair<K, V> pair : m) { 284 this.add(pair.key(), pair.value()); 285 } 286 m.clear(); 287 } 288 289}