2 *******************************************************************************
3 * Copyright (C) 1996-2012, International Business Machines Corporation and *
4 * others. All Rights Reserved. *
5 *******************************************************************************
7 package com.ibm.icu.dev.util;
9 import java.util.Collections;
10 import java.util.HashMap;
11 import java.util.HashSet;
12 import java.util.Iterator;
16 import com.ibm.icu.impl.Row;
17 import com.ibm.icu.impl.Row.R2;
20 * Everything that maps to the same value is part of the same equivalence class
24 public class XEquivalenceMap<K,V,R> implements Iterable<Set<K>> {
26 Map<K,Row.R2<V,Set<R>>> source_target_reasons = new HashMap<K,Row.R2<V,Set<R>>>();
28 Map<V,Set<K>> target_sourceSet;
29 Map<K,Set<K>> source_Set = new HashMap<K,Set<K>>(); // not really needed: could go source-target-sourceset
31 public XEquivalenceMap() {
32 this(new HashMap<V,Set<K>>());
35 public XEquivalenceMap(Map<V,Set<K>> storage) {
36 target_sourceSet = storage;
39 public XEquivalenceMap clear() {
40 source_target_reasons.clear();
41 target_sourceSet.clear();
46 public XEquivalenceMap add(K source, V target) {
47 return add(source, target, null);
50 public XEquivalenceMap add(K source, V target, R reason) {
51 R2<V, Set<R>> target_reasons = source_target_reasons.get(source);
52 if (target_reasons == null) {
53 Set<R> reasons = new HashSet<R>();
57 target_reasons = Row.of(target, reasons);
58 source_target_reasons.put(source, target_reasons);
60 V otherTarget = target_reasons.get0();
61 Set<R> reasons = target_reasons.get1();
62 if (otherTarget.equals(target)) {
68 throw new IllegalArgumentException("Same source mapping to different targets: "
69 + source + " => " + otherTarget + " & " + target);
72 Set<K> s = target_sourceSet.get(target);
73 if (s == null) target_sourceSet.put(target, s = new HashSet<K>());
75 source_Set.put(source, s);
79 public Set<K> getEquivalences (K source) {
80 Set<K> s = source_Set.get(source);
81 if (s == null) return null;
82 return Collections.unmodifiableSet(s);
85 public boolean areEquivalent (K source1, K source2) {
86 Set<K> s = (Set) source_Set.get(source1);
87 if (s == null) return false;
88 return s.contains(source2);
91 public V getTarget(K source) {
92 return source_target_reasons.get(source).get0();
95 public Set<R> getReasons(K source) {
96 return Collections.unmodifiableSet(source_target_reasons.get(source).get1());
99 public Set<K> getSources(V target) {
100 Set<K> s = target_sourceSet.get(target);
101 return Collections.unmodifiableSet(s);
104 public Iterator<Set<K>> iterator() {
105 return UnmodifiableIterator.from(target_sourceSet.values());
109 return target_sourceSet.size();
112 public boolean isEmpty() {
113 return target_sourceSet.isEmpty();
116 // Should be moved out on its own
117 public static class UnmodifiableIterator<T> implements Iterator<T> {
118 private Iterator<T> source;
120 public static <T> UnmodifiableIterator<T> from(Iterator<T> source) {
121 UnmodifiableIterator<T> result = new UnmodifiableIterator<T>();
122 result.source = source;
126 public static <T> UnmodifiableIterator<T> from(Iterable<T> source) {
127 return from(source.iterator());
130 public void remove() {
131 throw new UnsupportedOperationException();
134 public boolean hasNext() {
135 return source.hasNext();
139 return source.next();