package edu.stanford.nlp.util; import java.io.Serializable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; /** * A factory class for vending different sorts of Maps. * * @author Dan Klein (klein@cs.stanford.edu) * @author Kayur Patel (kdpatel@cs) */ public abstract class MapFactory<K,V> implements Serializable { // allow people to write subclasses protected MapFactory() { } private static final long serialVersionUID = 4529666940763477360L; @SuppressWarnings("unchecked") public static final MapFactory HASH_MAP_FACTORY = new HashMapFactory(); @SuppressWarnings("unchecked") public static final MapFactory IDENTITY_HASH_MAP_FACTORY = new IdentityHashMapFactory(); @SuppressWarnings("unchecked") private static final MapFactory WEAK_HASH_MAP_FACTORY = new WeakHashMapFactory(); @SuppressWarnings("unchecked") private static final MapFactory TREE_MAP_FACTORY = new TreeMapFactory(); @SuppressWarnings("unchecked") private static final MapFactory LINKED_HASH_MAP_FACTORY = new LinkedHashMapFactory(); @SuppressWarnings("unchecked") private static final MapFactory ARRAY_MAP_FACTORY = new ArrayMapFactory(); public static final MapFactory CONCURRENT_MAP_FACTORY = new ConcurrentMapFactory(); /** Return a MapFactory that returns a HashMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes a HashMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> hashMapFactory() { return HASH_MAP_FACTORY; } /** Return a MapFactory that returns an IdentityHashMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes a HashMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> identityHashMapFactory() { return IDENTITY_HASH_MAP_FACTORY; } /** Return a MapFactory that returns a WeakHashMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes a WeakHashMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> weakHashMapFactory() { return WEAK_HASH_MAP_FACTORY; } /** Return a MapFactory that returns a TreeMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes an TreeMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> treeMapFactory() { return TREE_MAP_FACTORY; } /** * Return a MapFactory that returns a TreeMap with the given Comparator. */ public static <K,V> MapFactory<K,V> treeMapFactory(Comparator<? super K> comparator) { return new TreeMapFactory<>(comparator); } /** Return a MapFactory that returns an LinkedHashMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes an LinkedHashMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> linkedHashMapFactory() { return LINKED_HASH_MAP_FACTORY; } /** Return a MapFactory that returns an ArrayMap. * <i>Implementation note: This method uses the same trick as the methods * like emptyMap() introduced in the Collections class in JDK1.5 where * callers can call this method with apparent type safety because this * method takes the hit for the cast. * * @return A MapFactory that makes an ArrayMap. */ @SuppressWarnings("unchecked") public static <K,V> MapFactory<K,V> arrayMapFactory() { return ARRAY_MAP_FACTORY; } private static class HashMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -9222344631596580863L; @Override public Map<K,V> newMap() { return Generics.newHashMap(); } @Override public Map<K,V> newMap(int initCapacity) { return Generics.newHashMap(initCapacity); } @Override public Set<K> newSet() { return Generics.newHashSet(); } @Override public Set<K> newSet(Collection<K> init) { return Generics.newHashSet(init); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map) { map = Generics.newHashMap(); return map; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = Generics.newHashMap(initCapacity); return map; } } // end class HashMapFactory private static class IdentityHashMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -9222344631596580863L; @Override public Map<K,V> newMap() { return new IdentityHashMap<>(); } @Override public Map<K,V> newMap(int initCapacity) { return new IdentityHashMap<>(initCapacity); } @Override public Set<K> newSet() { return Collections.newSetFromMap(new IdentityHashMap<>()); } @Override public Set<K> newSet(Collection<K> init) { Set<K> set = Collections.newSetFromMap(new IdentityHashMap<>()); // nothing more efficient to be done here... set.addAll(init); return set; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map) { map = new IdentityHashMap<>(); return map; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = new IdentityHashMap<>(initCapacity); return map; } } // end class IdentityHashMapFactory private static class WeakHashMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = 4790014244304941000L; @Override public Map<K,V> newMap() { return new WeakHashMap<>(); } @Override public Map<K,V> newMap(int initCapacity) { return new WeakHashMap<>(initCapacity); } @Override public Set<K> newSet() { return Collections.newSetFromMap(new WeakHashMap<>()); } @Override public Set<K> newSet(Collection<K> init) { Set<K> set = Collections.newSetFromMap(new WeakHashMap<>()); set.addAll(init); return set; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map) { map = new WeakHashMap<>(); return map; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = new WeakHashMap<>(initCapacity); return map; } } // end class WeakHashMapFactory private static class TreeMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -9138736068025818670L; private final Comparator<? super K> comparator; public TreeMapFactory() { this.comparator = null; } public TreeMapFactory(Comparator<? super K> comparator) { this.comparator = comparator; } @Override public Map<K,V> newMap() { return comparator == null ? new TreeMap<>() : new TreeMap<>(comparator); } @Override public Map<K,V> newMap(int initCapacity) { return newMap(); } @Override public Set<K> newSet() { return comparator == null ? new TreeSet<>() : new TreeSet<>(comparator); } @Override public Set<K> newSet(Collection<K> init) { return new TreeSet<>(init); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map) { if (comparator == null) { throw new UnsupportedOperationException(); } map = new TreeMap<>(); return map; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { if (comparator == null) { throw new UnsupportedOperationException(); } map = new TreeMap<>(); return map; } } // end class TreeMapFactory private static class LinkedHashMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -9138736068025818671L; @Override public Map<K,V> newMap() { return new LinkedHashMap<>(); } @Override public Map<K,V> newMap(int initCapacity) { return newMap(); } @Override public Set<K> newSet() { return new LinkedHashSet<>(); } @Override public Set<K> newSet(Collection<K> init) { return new LinkedHashSet<>(init); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map) { map = new LinkedHashMap<>(); return map; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = new LinkedHashMap<>(); return map; } } // end class LinkedHashMapFactory private static class ArrayMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -5855812734715185523L; @Override public Map<K,V> newMap() { return new ArrayMap<>(); } @Override public Map<K,V> newMap(int initCapacity) { return new ArrayMap<>(initCapacity); } @Override public Set<K> newSet() { return new ArraySet<>(); } @Override public Set<K> newSet(Collection<K> init) { return new ArraySet<>(); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1, V1> map) { return new ArrayMap<>(); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = new ArrayMap<>(initCapacity); return map; } } // end class ArrayMapFactory private static class ConcurrentMapFactory<K,V> extends MapFactory<K,V> { private static final long serialVersionUID = -5855812734715185523L; @Override public Map<K,V> newMap() { return new ConcurrentHashMap<>(); } @Override public Map<K,V> newMap(int initCapacity) { return new ConcurrentHashMap<>(initCapacity); } @Override public Set<K> newSet() { return Collections.newSetFromMap(new ConcurrentHashMap<>()); } @Override public Set<K> newSet(Collection<K> init) { Set<K> set = Collections.newSetFromMap(new ConcurrentHashMap<>()); set.addAll(init); return set; } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1, V1> map) { return new ConcurrentHashMap<>(); } @Override public <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity) { map = new ConcurrentHashMap<>(initCapacity); return map; } } // end class ConcurrentMapFactory /** * Returns a new non-parameterized map of a particular sort. * * @return A new non-parameterized map of a particular sort */ public abstract Map<K,V> newMap(); /** * Returns a new non-parameterized map of a particular sort with an initial capacity. * * @param initCapacity initial capacity of the map * @return A new non-parameterized map of a particular sort with an initial capacity */ public abstract Map<K,V> newMap(int initCapacity); /** * A set with the same {@code K} parameterization of the Maps. */ public abstract Set<K> newSet(); /** * A set with the same {@code K} parameterization, but initialized to the given collection. */ public abstract Set<K> newSet(Collection<K> init); /** * A method to get a parameterized (genericized) map out. * * @param map A type-parameterized {@link Map} argument * @return A {@link Map} with type-parameterization identical to that of * the argument. */ public abstract <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map); public abstract <K1, V1> Map<K1, V1> setMap(Map<K1,V1> map, int initCapacity); }