package ninja.bytecode.iris.util; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class KMap extends ConcurrentHashMap { private static final long serialVersionUID = 7288942695300448163L; public KMap() { super(); } public KMap(KMap gMap) { this(); put(gMap); } /** * Puts a value into a map-value-list based on the key such that if GMap> where V is GList * * @param * the list type in the value type * @param k * the key to look for * @param vs * the values to put into the list of the given key * @return the same list (builder) */ @SuppressWarnings("unchecked") public KMap putValueList(K k, S... vs) { try { KMap> s = (KMap>) this; if(!s.containsKey(k)) { s.put(k, new KList()); } s.get(k).add(vs); } catch(Throwable e) { } return this; } /** * Returns a sorted list of keys from this map, based on the sorting order of * the values. * * @return the value-sorted key list */ public KList sortK() { KList k = new KList(); KList v = v(); Collections.sort(v, new Comparator() { @Override public int compare(V v, V t1) { return v.toString().compareTo(t1.toString()); } }); for(V i : v) { for(K j : k()) { if(get(j).equals(i)) { k.add(j); } } } k.dedupe(); return k; } /** * Returns a sorted list of keys from this map, based on the sorting order of * the values. Sorting is based on numerical values * * @return the value-sorted key list */ public KList sortKNumber() { KList k = new KList(); KList v = v(); Collections.sort(v, new Comparator() { @Override public int compare(V v, V t1) { Number n1 = (Number) v; Number n2 = (Number) t1; return (int) ((n1.doubleValue() - n2.doubleValue()) * 1000); } }); for(V i : v) { for(K j : k()) { if(get(j).equals(i)) { k.add(j); } } } k.dedupe(); return k; } /** * Put another map's values into this map * * @param m * the map to insert * @return this map (builder) */ public KMap put(Map m) { putAll(m); return this; } /** * Return a copy of this map * * @return the copied map */ public KMap copy() { return new KMap(this); } /** * Loop through each keyvalue set (copy of it) with the map parameter * * @param f * the function * @return the same gmap */ public KMap rewrite(Consumer3> f) { KMap m = copy(); for(K i : m.k()) { f.accept(i, get(i), this); } return this; } /** * Loop through each keyvalue set (copy of it) * * @param f * the function * @return the same gmap */ public KMap each(Consumer2 f) { for(K i : k()) { f.accept(i, get(i)); } return this; } /** * Flip the hashmap and flatten the value list even if there are multiple keys * * @return the flipped and flattened hashmap */ public KMap flipFlatten() { KMap> f = flip(); KMap m = new KMap<>(); for(V i : f.k()) { m.putNonNull(i, m.isEmpty() ? null : m.get(0)); } return m; } /** * Flip the hashmap so keys are now list-keys in the value position * * @return the flipped hashmap */ public KMap> flip() { KMap> flipped = new KMap>(); for(K i : keySet()) { if(i == null) { continue; } if(!flipped.containsKey(get(i))) { flipped.put(get(i), new KList()); } flipped.get(get(i)).add(i); } return flipped; } /** * Sort values based on the keys sorting order * * @return the values (sorted) */ public KList sortV() { KList v = new KList(); KList k = k(); Collections.sort(k, new Comparator() { @Override public int compare(K v, K t1) { return v.toString().compareTo(t1.toString()); } }); for(K i : k) { for(V j : v()) { if(get(i).equals(j)) { v.add(j); } } } v.dedupe(); return v; } public KList sortVNoDedupe() { KList v = new KList(); KList k = k(); Collections.sort(k, new Comparator() { @Override public int compare(K v, K t1) { return v.toString().compareTo(t1.toString()); } }); for(K i : k) { for(V j : v()) { if(get(i).equals(j)) { v.add(j); } } } return v; } /** * Get a copy of this maps keys * * @return the keys */ public KList k() { KList k = new KList(); Enumeration kk = keys(); while(kk.hasMoreElements()) { K kkk = kk.nextElement(); k.add(kkk); } return k; } /** * Get a copy of this maps values * * @return the values */ public KList v() { return new KList(values()); } /** * Still works as it normally should except it returns itself (builder) * * @param key * the key * @param value * the value (single only supported) * @return */ public KMap qput(K key, V value) { super.put(key, value); return this; } /** * Works just like put, except it wont put anything unless the key and value are * nonnull * * @param key * the nonnull key * @param value * the nonnull value * @return the same map */ public KMap putNonNull(K key, V value) { if(key != null || value != null) { put(key, value); } return this; } public V putThen(K key, V valueIfKeyNotPresent) { if(!containsKey(key)) { put(key, valueIfKeyNotPresent); } return get(key); } /** * Clear this map and return it * * @return the cleared map */ public KMap qclear() { super.clear(); return this; } /** * Convert this map to keypairs * * @return the keypair list */ public KList> keypair() { KList> g = new KList<>(); each((k, v) -> g.add(new KeyPair(k, v))); return g; } /** * Create a keypair queue * * @return the queue */ public Queue> enqueue() { return Queue.create(keypair()); } /** * Create a key queue * * @return the queue */ public Queue enqueueKeys() { return Queue.create(k()); } /** * Create a value queue * * @return the queue */ public Queue enqueueValues() { return Queue.create(v()); } }