1 11 package org.eclipse.jdt.apt.core.internal.util; 12 13 import java.util.Collections ; 14 import java.util.HashMap ; 15 import java.util.HashSet ; 16 import java.util.Map ; 17 import java.util.Set ; 18 19 38 public class ManyToMany<T1, T2> { 39 40 private final Map <T1, Set <T2>> _forward = new HashMap <T1, Set <T2>>(); 41 private final Map <T2, Set <T1>> _reverse = new HashMap <T2, Set <T1>>(); 42 private boolean _dirty = false; 43 44 49 public synchronized boolean clear() { 50 boolean hadContent = !_forward.isEmpty() || !_reverse.isEmpty(); 51 _reverse.clear(); 52 _forward.clear(); 53 _dirty |= hadContent; 54 return hadContent; 55 } 56 57 63 public synchronized void clearDirtyBit() { 64 _dirty = false; 65 } 66 67 71 public synchronized boolean containsKey(T1 key) { 72 return _forward.containsKey(key); 73 } 74 75 80 public synchronized boolean containsKeyValuePair(T1 key, T2 value) { 81 Set <T2> values = _forward.get(key); 82 if (null == values) { 83 return false; 84 } 85 return values.contains(value); 86 } 87 88 93 public synchronized boolean containsValue(T2 value) { 94 return _reverse.containsKey(value); 95 } 96 97 103 public synchronized Set <T1> getKeys(T2 value) { 104 Set <T1> keys = _reverse.get(value); 105 if (null == keys) { 106 return Collections.emptySet(); 107 } 108 return new HashSet <T1>(keys); 109 } 110 111 117 public synchronized Set <T2> getValues(T1 key) { 118 Set <T2> values = _forward.get(key); 119 if (null == values) { 120 return Collections.emptySet(); 121 } 122 return new HashSet <T2>(values); 123 } 124 125 131 public synchronized Set <T1> getKeySet() { 132 Set <T1> keys = new HashSet <T1>(_forward.keySet()); 133 return keys; 134 } 135 136 142 public synchronized Set <T2> getValueSet() { 143 Set <T2> values = new HashSet <T2>(_reverse.keySet()); 144 return values; 145 } 146 147 155 public synchronized boolean isDirty() { 156 return _dirty; 157 } 158 159 169 public synchronized boolean keyHasOtherValues(T1 key, T2 value) { 170 Set <T2> values = _forward.get(key); 171 if (values == null) 172 return false; 173 int size = values.size(); 174 if (size == 0) 175 return false; 176 else if (size > 1) 177 return true; 178 else return !values.contains(value); 180 } 181 182 192 public synchronized boolean put(T1 key, T2 value) { 193 Set <T2> values = _forward.get(key); 195 if (null == values) { 196 values = new HashSet <T2>(); 197 _forward.put(key, values); 198 } 199 boolean added = values.add(value); 200 _dirty |= added; 201 202 Set <T1> keys = _reverse.get(value); 204 if (null == keys) { 205 keys = new HashSet <T1>(); 206 _reverse.put(value, keys); 207 } 208 keys.add(key); 209 210 assert checkIntegrity(); 211 return added; 212 } 213 214 221 public synchronized boolean remove(T1 key, T2 value) { 222 Set <T2> values = _forward.get(key); 223 if (values == null) { 224 assert checkIntegrity(); 225 return false; 226 } 227 boolean removed = values.remove(value); 228 if (values.isEmpty()) { 229 _forward.remove(key); 230 } 231 if (removed) { 232 _dirty = true; 233 Set <T1> keys = _reverse.get(value); 235 keys.remove(key); 236 if (keys.isEmpty()) { 237 _reverse.remove(value); 238 } 239 } 240 assert checkIntegrity(); 241 return removed; 242 } 243 244 250 public synchronized boolean removeKey(T1 key) { 251 Set <T2> values = _forward.get(key); 253 if (null == values) { 254 assert checkIntegrity(); 256 return false; 257 } 258 for (T2 value : values) { 259 Set <T1> keys = _reverse.get(value); 260 if (null != keys) { 261 keys.remove(key); 262 if (keys.isEmpty()) { 263 _reverse.remove(value); 264 } 265 } 266 } 267 _forward.remove(key); 269 _dirty = true; 270 assert checkIntegrity(); 271 return true; 272 } 273 274 280 public synchronized boolean removeValue(T2 value) { 281 Set <T1> keys = _reverse.get(value); 283 if (null == keys) { 284 assert checkIntegrity(); 286 return false; 287 } 288 for (T1 key : keys) { 289 Set <T2> values = _forward.get(key); 290 if (null != values) { 291 values.remove(value); 292 if (values.isEmpty()) { 293 _forward.remove(key); 294 } 295 } 296 } 297 _reverse.remove(value); 299 _dirty = true; 300 assert checkIntegrity(); 301 return true; 302 } 303 304 314 public synchronized boolean valueHasOtherKeys(T2 value, T1 key) { 315 Set <T1> keys = _reverse.get(key); 316 if (keys == null) 317 return false; 318 int size = keys.size(); 319 if (size == 0) 320 return false; 321 else if (size > 1) 322 return true; 323 else return !keys.contains(key); 325 } 326 327 334 private boolean checkIntegrity() { 335 for (Map.Entry <T1, Set <T2>> entry : _forward.entrySet()) { 338 Set <T2> values = entry.getValue(); 339 if (values.isEmpty()) { 340 throw new IllegalStateException ("Integrity compromised: forward map contains an empty set"); } 342 for (T2 value : values) { 343 Set <T1> keys = _reverse.get(value); 344 if (null == keys || !keys.contains(entry.getKey())) { 345 throw new IllegalStateException ("Integrity compromised: forward map contains an entry missing from reverse map: " + value); } 347 } 348 } 349 for (Map.Entry <T2, Set <T1>> entry : _reverse.entrySet()) { 351 Set <T1> keys = entry.getValue(); 352 if (keys.isEmpty()) { 353 throw new IllegalStateException ("Integrity compromised: reverse map contains an empty set"); } 355 for (T1 key : keys) { 356 Set <T2> values = _forward.get(key); 357 if (null == values || !values.contains(entry.getKey())) { 358 throw new IllegalStateException ("Integrity compromised: reverse map contains an entry missing from forward map: " + key); } 360 } 361 } 362 return true; 363 } 364 365 } 366 | Popular Tags |