Skip to content

Commit

Permalink
Add OrderedSet, some updates to related code
Browse files Browse the repository at this point in the history
Unlike LinkedHashSet, this does not use a Map internally to implement a
Set, and should be much more memory-efficient while still allowing the
nice indexing features that OrderedMap has.
  • Loading branch information
tommyettinger committed Jun 18, 2016
1 parent 42ab857 commit ff209d1
Show file tree
Hide file tree
Showing 5 changed files with 1,677 additions and 26 deletions.
3 changes: 2 additions & 1 deletion squidlib-util/src/main/java/squidpony/GwtCompatibility.java
Expand Up @@ -45,7 +45,8 @@ public static double IEEEremainder(double op, double d) {
/**
* Gets the first item in an Iterable of T, or null if it is empty. Meant for collections like LinkedHashSet, which
* can promise a stable first element but don't provide a way to access it. Not exactly a GWT compatibility method,
* but more of a Java standard library stand-in.
* but more of a Java standard library stand-in. Even though LinkedHashSet does not support this out-of-the-box,
* OrderedSet already provides a first() method.
* @param collection an Iterable of T; if collection is null or empty this returns null
* @param <T> any object type
* @return the first element in collection, or null if it is empty or null itself
Expand Down
31 changes: 22 additions & 9 deletions squidlib-util/src/main/java/squidpony/Maker.java
@@ -1,6 +1,7 @@
package squidpony;

import squidpony.squidmath.OrderedMap;
import squidpony.squidmath.OrderedSet;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -109,7 +110,7 @@ public static <T> LinkedHashSet<T> makeLHS(T... elements) {
return set;
}
/**
* Makes a LinkedHashMap (LHM) with key and value types inferred from the types of k0 and v0, and considers all
* Makes an OrderedMap (OM) with key and value types inferred from the types of k0 and v0, and considers all
* parameters key-value pairs, casting the Objects at positions 0, 2, 4... etc. to K and the objects at positions
* 1, 3, 5... etc. to V. If rest has an odd-number length, then it discards the last item. If any pair of items in
* rest cannot be cast to the correct type of K or V, then this inserts nothing for that pair and logs information
Expand All @@ -119,7 +120,7 @@ public static <T> LinkedHashSet<T> makeLHS(T... elements) {
* @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
* @param <K> the type of keys in the returned LinkedHashMap; if not specified, will be inferred from k0
* @param <V> the type of values in the returned LinkedHashMap; if not specified, will be inferred from v0
* @return a freshly-made LinkedHashMap with K keys and V values, using k0, v0, and the contents of rest to fill it
* @return a freshly-made OrderedMap with K keys and V values, using k0, v0, and the contents of rest to fill it
*/
@SuppressWarnings("unchecked")
public static <K, V> OrderedMap<K, V> makeOM(K k0, V v0, Object... rest)
Expand All @@ -133,7 +134,7 @@ public static <K, V> OrderedMap<K, V> makeOM(K k0, V v0, Object... rest)
try {
om.put((K) rest[i], (V) rest[i + 1]);
}catch (ClassCastException cce) {
issueLog.append("makeLHM call had a casting problem with pair at rest[");
issueLog.append("makeOM call had a casting problem with pair at rest[");
issueLog.append(i);
issueLog.append("] and/or rest[");
issueLog.append(i + 1);
Expand All @@ -155,17 +156,29 @@ public static <K, V> OrderedMap<K, V> makeOM(K k0, V v0, Object... rest)
}

/**
* Makes an empty LinkedHashMap (LHM); needs key and value types to be specified in order to work. For an empty
* LinkedHashMap with String keys and Coord values, you could use {@code Maker.<String, Coord>makeLHM();}. Using
* Makes an empty OrderedMap (OM); needs key and value types to be specified in order to work. For an empty
* OrderedMap with String keys and Coord values, you could use {@code Maker.<String, Coord>makeOM();}. Using
* the new keyword is probably just as easy in this case; this method is provided for completeness relative to
* makeLHM() with 2 or more parameters.
* @param <K> the type of keys in the returned LinkedHashMap; cannot be inferred and must be specified
* @param <V> the type of values in the returned LinkedHashMap; cannot be inferred and must be specified
* @return an empty LinkedHashMap with the given key and value types.
* makeOM() with 2 or more parameters.
* @param <K> the type of keys in the returned OrderedMap; cannot be inferred and must be specified
* @param <V> the type of values in the returned OrderedMap; cannot be inferred and must be specified
* @return an empty OrderedMap with the given key and value types.
*/
public static <K, V> OrderedMap<K, V> makeOM()
{
return new OrderedMap<>();
}

/**
* Makes a OrderedSet (OS) of T given an array or vararg of T elements. Duplicate items in elements will have
* all but one item discarded, using the later item in elements.
* @param elements an array or vararg of T
* @param <T> just about any non-primitive type
* @return a newly-allocated OrderedSet containing all of the non-duplicate items in elements, in order
*/
@SafeVarargs
public static <T> OrderedSet<T> makeOS(T... elements) {
if(elements == null) return null;
return new OrderedSet<T>(elements);
}
}
Expand Up @@ -19,7 +19,6 @@
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;
Expand Down Expand Up @@ -1414,8 +1413,7 @@ public Object[] toArray() {
public <T> T[] toArray(T[] a) {
final int size = size();
if (a.length < size)
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass()
.getComponentType(), size);
a = (T[]) new MapEntry[size];
objectUnwrap(iterator(), a);
if (size < a.length)
a[size] = null;
Expand Down Expand Up @@ -1526,7 +1524,7 @@ public String toString() {
}
public Set<Entry<Integer, Double>> toBoxed()
{
return new LinkedHashSet<Entry<Integer, Double>>(this);
return new OrderedSet<Entry<Integer, Double>>(this);
}
}

Expand All @@ -1535,6 +1533,7 @@ public Set<Entry<Integer, Double>> toBoxed()
* key and value types. Prefer {@code mapEntrySet()}!!!
* @return a Set of Map.Entry with Integer keys and Double values
* @see IntDoubleOrderedMap#mapEntrySet strongly preferred variant that allows primitive access
* @deprecated prefer {@link IntDoubleOrderedMap#mapEntrySet}
*/
@Override
public Set<Entry<Integer, Double>> entrySet() {
Expand Down Expand Up @@ -1773,8 +1772,6 @@ public Object[] toArray() {

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size())
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size());
objectUnwrap(iterator(), a);
return a;
}
Expand Down Expand Up @@ -2415,8 +2412,6 @@ public Object[] toArray() {

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
if (a.length < size())
a = (T[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size());
objectUnwrap(iterator(), a);
return a;
}
Expand Down
21 changes: 13 additions & 8 deletions squidlib-util/src/main/java/squidpony/squidmath/OrderedMap.java
Expand Up @@ -132,7 +132,7 @@ public class OrderedMap<K, V> implements SortedMap<K, V>, java.io.Serializable,
/**
* The default load factor of a hash table.
*/
public static final float DEFAULT_LOAD_FACTOR = .1875f; // .75f;
public static final float DEFAULT_LOAD_FACTOR = .375f; // .1875f; // .75f;
/**
* The load factor for a (usually small) table that is meant to be particularly fast.
*/
Expand Down Expand Up @@ -297,7 +297,8 @@ public void putAll(Map<? extends K, ? extends V> m) {
e = i.next();
put(e.getKey(), e.getValue());
}
} }
}
}
private int insert(final K k, final V v) {
int pos;
if (((k) == null)) {
Expand Down Expand Up @@ -360,6 +361,7 @@ protected final void shiftKeys(int pos) {
if (((curr = key[pos]) == null)) {
key[last] = (null);
value[last] = null;
order.removeValue(last);
return;
}
slot = (HashCommon.mix((curr).hashCode()))
Expand Down Expand Up @@ -767,6 +769,7 @@ public void clear() {
Arrays.fill(key, (null));
Arrays.fill(value, null);
first = last = -1;
order.clear();
}

public int size() {
Expand Down Expand Up @@ -888,7 +891,7 @@ protected void fixPointers(final int i) {
}

/**
* Modifies the link vector for a shift from s to d. <P>This method will complete in logarithmic time.
* Modifies the link vector for a shift from s to d. <P>This method will complete in logarithmic time or better.
*
* @param s the source position.
* @param d the destination position.
Expand All @@ -912,6 +915,10 @@ else if (last == s) {
//link[(int) (link[s] >>> 32)] ^= ((link[(int) (link[s] >>> 32)] ^ (d & 0xFFFFFFFFL)) & 0xFFFFFFFFL);
//link[d] = link[s];
}
else
{
order.set(order.indexOf(s), d);
}
/*
final long links = link[s];
final int prev = (int) (links >>> 32);
Expand Down Expand Up @@ -1038,7 +1045,6 @@ private void ensureIndexKnown() {
index = size;
return;
}
int pos = first;
index = 0;
/*while (pos != prev) {
pos = (int) link[pos];
Expand Down Expand Up @@ -1074,8 +1080,6 @@ public int previousEntry() {
prev = order.get(index - 1);
//prev = (int) (link[curr] >>> 32);
next = curr;
if (index >= 0)
index--;
return curr;
}
public void remove() {
Expand Down Expand Up @@ -1511,8 +1515,9 @@ public final SortedSet<K> subSet(K from, K to) {
}

@SuppressWarnings("unchecked")
public Object[] toArray(Object a[]) {
if (a == null || a.length < size()) a = new Object[size()];
@Override
public <T> T[] toArray(T[] a) {
if (a == null || a.length < size()) a = (T[]) new Object[size()];
unwrap(iterator(), a);
return a;
}
Expand Down

0 comments on commit ff209d1

Please sign in to comment.