blob: b28d46062a913238e2326ff7fa4b5ed02235fba5 [file] [log] [blame]
/*
*******************************************************************************
* Copyright (C) 1996-2010, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.test.util;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.ibm.icu.impl.Row;
import com.ibm.icu.impl.Row.R2;
/**
* Everything that maps to the same value is part of the same equivalence class
* @author davis
*
*/
public class XEquivalenceMap<K,V,R> implements Iterable<Set<K>> {
Map<K,Row.R2<V,Set<R>>> source_target_reasons = new HashMap<K,Row.R2<V,Set<R>>>();
Map<V,Set<K>> target_sourceSet;
Map<K,Set<K>> source_Set = new HashMap<K,Set<K>>(); // not really needed: could go source-target-sourceset
public XEquivalenceMap() {
this(new HashMap<V,Set<K>>());
}
public XEquivalenceMap(Map<V,Set<K>> storage) {
target_sourceSet = storage;
}
public XEquivalenceMap clear() {
source_target_reasons.clear();
target_sourceSet.clear();
source_Set.clear();
return this;
}
public XEquivalenceMap add(K source, V target) {
return add(source, target, null);
}
public XEquivalenceMap add(K source, V target, R reason) {
R2<V, Set<R>> target_reasons = source_target_reasons.get(source);
if (target_reasons == null) {
Set<R> reasons = new HashSet<R>();
if (reason != null) {
reasons.add(reason);
}
target_reasons = Row.of(target, reasons);
source_target_reasons.put(source, target_reasons);
} else {
V otherTarget = target_reasons.get0();
Set<R> reasons = target_reasons.get1();
if (otherTarget.equals(target)) {
if (reason != null) {
reasons.add(reason);
}
return this;
}
throw new IllegalArgumentException("Same source mapping to different targets: "
+ source + " => " + otherTarget + " & " + target);
}
Set<K> s = target_sourceSet.get(target);
if (s == null) target_sourceSet.put(target, s = new HashSet<K>());
s.add(source);
source_Set.put(source, s);
return this;
}
public Set<K> getEquivalences (K source) {
Set<K> s = source_Set.get(source);
if (s == null) return null;
return Collections.unmodifiableSet(s);
}
public boolean areEquivalent (K source1, K source2) {
Set<K> s = (Set) source_Set.get(source1);
if (s == null) return false;
return s.contains(source2);
}
public V getTarget(K source) {
return source_target_reasons.get(source).get0();
}
public Set<R> getReasons(K source) {
return Collections.unmodifiableSet(source_target_reasons.get(source).get1());
}
public Set<K> getSources(V target) {
Set<K> s = target_sourceSet.get(target);
return Collections.unmodifiableSet(s);
}
public Iterator<Set<K>> iterator() {
return UnmodifiableIterator.from(target_sourceSet.values());
}
public int size() {
return target_sourceSet.size();
}
public boolean isEmpty() {
return target_sourceSet.isEmpty();
}
// Should be moved out on its own
public static class UnmodifiableIterator<T> implements Iterator<T> {
private Iterator<T> source;
public static <T> UnmodifiableIterator<T> from(Iterator<T> source) {
UnmodifiableIterator<T> result = new UnmodifiableIterator<T>();
result.source = source;
return result;
}
public static <T> UnmodifiableIterator<T> from(Iterable<T> source) {
return from(source.iterator());
}
public void remove() {
throw new UnsupportedOperationException();
}
public boolean hasNext() {
return source.hasNext();
}
public T next() {
return source.next();
}
}
}