Mercurial > hg > Members > tatsuki > functionaljava-master > core
view src/main/java/fj/data/HashMap.java @ 0:fe80c1edf1be
add getLoop
author | tatsuki |
---|---|
date | Fri, 20 Mar 2015 21:04:03 +0900 |
parents | |
children |
line wrap: on
line source
package fj.data; import fj.*; import fj.function.Effect1; import java.util.Collection; import java.util.Iterator; import static fj.P.p; import static fj.data.Option.fromNull; /** * A mutable hash map providing O(1) lookup. * * @version %build.number% * @see java.util.HashMap */ public final class HashMap<K, V> implements Iterable<K> { private final class Key<K> { private final K k; private final Equal<K> e; private final Hash<K> h; Key(final K k, final Equal<K> e, final Hash<K> h) { this.k = k; this.e = e; this.h = h; } K k() { return k; } @SuppressWarnings({"unchecked"}) public boolean equals(final Object o) { return o instanceof Key && e.eq(k, (K) ((Key<?>) o).k()); } public int hashCode() { return h.hash(k); } } /** * Returns an iterator for this map's keys. This method exists to permit the use in a <code>for</code>-each loop. * * @return A iterator for this map's keys. */ public Iterator<K> iterator() { return keys().iterator(); } private final java.util.HashMap<Key<K>, V> m; private final Equal<K> e; private final Hash<K> h; /** * Construct a hash map with the given equality and hashing strategy. * * @param e The equality strategy. * @param h The hashing strategy. */ public HashMap(final Equal<K> e, final Hash<K> h) { m = new java.util.HashMap<Key<K>, V>(); this.e = e; this.h = h; } public HashMap(java.util.Map<K, V> map, final Equal<K> e, final Hash<K> h) { this(e, h); for (K key : map.keySet()) { set(key, map.get(key)); } } /** * Construct a hash map with the given equality and hashing strategy. * * @param e The equality strategy. * @param h The hashing strategy. * @param initialCapacity The initial capacity. */ public HashMap(final Equal<K> e, final Hash<K> h, final int initialCapacity) { m = new java.util.HashMap<Key<K>, V>(initialCapacity); this.e = e; this.h = h; } public HashMap(java.util.Map<K, V> map) { this(map, Equal.<K>anyEqual(), Hash.<K>anyHash()); } /** * Construct a hash map with the given equality and hashing strategy. * * @param e The equality strategy. * @param h The hashing strategy. * @param initialCapacity The initial capacity. * @param loadFactor The load factor. */ public HashMap(final Equal<K> e, final Hash<K> h, final int initialCapacity, final float loadFactor) { m = new java.util.HashMap<Key<K>, V>(initialCapacity, loadFactor); this.e = e; this.h = h; } /** * Construct a hash map that uses {@link Object#equals} and {@link Object#hashCode}. * * @return A new hash map that uses {@link Object#equals} and {@link Object#hashCode}. */ public static <K, V> HashMap<K, V> hashMap() { final Equal<K> e = Equal.anyEqual(); final Hash<K> h = Hash.anyHash(); return new HashMap<K, V>(e, h); } /** * Compare two key values for equality using the underlying equality strategy. * * @param k1 One key value to compare. * @param k2 The other key value to compare. * @return <code>true</code> if the two key values are equal, <code>false</code> otherwise. */ public boolean eq(final K k1, final K k2) { return e.eq(k1, k2); } /** * Compute the hash of the given key value using the underlying hashing strategy. * * @param k The key value to computer the hash of. * @return The hash of the given key value. */ public int hash(final K k) { return h.hash(k); } /** * Returns a potential value that the given key maps to. * * @param k The key to look up in the hash map. * @return A potential value for the given key. */ public Option<V> get(final K k) { return fromNull(m.get(new Key<K>(k, e, h))); } /** * A curried version of {@link #get(Object)}. * * @return A curried version of {@link #get(Object)}. */ public F<K, Option<V>> get() { return new F<K, Option<V>>() { public Option<V> f(final K k) { return get(k); } }; } /** * Clear all entries from this hash map. */ public void clear() { m.clear(); } /** * Determines if the given key value exists in this hash map. * * @param k The key value to look for in this hash map. * @return <code>true</code> if this hash map contains the given key, <code>false</code> otherwise. */ public boolean contains(final K k) { return m.containsKey(new Key<K>(k, e, h)); } /** * Returns all key entries in this hash map. * * @return All key entries in this hash map. */ public List<K> keys() { final List.Buffer<K> b = new List.Buffer<K>(); for (final Key<K> k : m.keySet()) { b.snoc(k.k()); } return b.toList(); } /** * Returns all values in this hash map. * * @return All values in this hash map. */ public List<V> values() { return keys().map(new F<K, V>() { public V f(final K k) { return m.get(new Key<K>(k, e, h)); } }); } /** * Determines if this hash map has any entries. * * @return <code>true</code> if this hash map has no entries, <code>false</code> otherwise. */ public boolean isEmpty() { return m.isEmpty(); } /** * Returns the number of entries in this hash map. * * @return The number of entries in this hash map. */ public int size() { return m.size(); } /** * Inserts the given key and value association into the hash map. * * @param k The key to insert. * @param v The value to insert. */ public void set(final K k, final V v) { if (v != null) { m.put(new Key<K>(k, e, h), v); } } /** * Deletes the entry in the hash map that corresponds to the given key. * * @param k The key to delete from this hash map. */ public void delete(final K k) { m.remove(new Key<K>(k, e, h)); } /** * Deletes the entry in the hash map that corresponds to the given key and returns any associated value. * * @param k The key to delete from this hash map. * @return The value that was associated with the given key, if there was one. */ public Option<V> getDelete(final K k) { return fromNull(m.remove(new Key<K>(k, e, h))); } public <A, B> HashMap<A, B> map(F<K, A> keyFunction, F<V, B> valueFunction, Equal<A> equal, Hash<A> hash) { final HashMap<A, B> hashMap = new HashMap<A, B>(equal, hash); for (K key : keys()) { final A newKey = keyFunction.f(key); final B newValue = valueFunction.f(get(key).some()); hashMap.set(newKey, newValue); } return hashMap; } public <A, B> HashMap<A, B> map(F<K, A> keyFunction, F<V, B> valueFunction) { return map(keyFunction, valueFunction, Equal.<A>anyEqual(), Hash.<A>anyHash()); } public <A, B> HashMap<A, B> map(F<P2<K, V>, P2<A, B>> function, Equal<A> equal, Hash<A> hash) { return from(toStream().map(function), equal, hash); } public <A, B> HashMap<A, B> map(F<P2<K, V>, P2<A, B>> function) { return from(toStream().map(function)); } public <A> HashMap<A, V> mapKeys(F<K, A> keyFunction, Equal<A> equal, Hash<A> hash) { return map(keyFunction, Function.<V>identity(), equal, hash); } public <A> HashMap<A, V> mapKeys(F<K, A> function) { return mapKeys(function, Equal.<A>anyEqual(), Hash.<A>anyHash()); } public <B> HashMap<K, B> mapValues(F<V, B> function) { return map(Function.<K>identity(), function, e, h); } public void foreachDoEffect(Effect1<P2<K, V>> effect) { toStream().foreachDoEffect(effect); } public void foreach(F<P2<K, V>, Unit> function) { toStream().foreach(function); } public List<P2<K, V>> toList() { return keys().map(new F<K, P2<K, V>>() { public P2<K, V> f(final K k) { return p(k, get(k).some()); } }); } /** * Projects an immutable collection of this hash map. * * @return An immutable collection of this hash map. */ public Collection<P2<K, V>> toCollection() { return toList().toCollection(); } public Stream<P2<K, V>> toStream() { return toList().toStream(); } public Option<P2<K, V>> toOption() { return toList().toOption(); } public Array<P2<K, V>> toArray() { return toList().toArray(); } public java.util.Map<K, V> toMap() { final java.util.HashMap<K,V> result = new java.util.HashMap<K, V>(); for (K key : keys()) { result.put(key, get(key).some()); } return result; } public static <K, V> HashMap<K, V> from(Iterable<P2<K, V>> entries) { return from(entries, Equal.<K>anyEqual(), Hash.<K>anyHash()); } public static <K, V> HashMap<K, V> from(Iterable<P2<K, V>> entries, Equal<K> equal, Hash<K> hash) { final HashMap<K, V> map = new HashMap<K, V>(equal, hash); for (P2<K, V> entry : entries) { map.set(entry._1(), entry._2()); } return map; } }