|
|
@@ -15,6 +15,7 @@ import net.ranides.assira.collection.sets.ASortedSet;
|
|
|
import net.ranides.assira.collection.IntCollection;
|
|
|
import net.ranides.assira.collection.iterators.IntIterator;
|
|
|
import net.ranides.assira.collection.iterators.IntListIterator;
|
|
|
+import net.ranides.assira.generic.ValueUtils;
|
|
|
|
|
|
/**
|
|
|
* An abstract class for sorted maps with primitive int values.
|
|
|
@@ -23,8 +24,7 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
|
|
|
private static final long serialVersionUID = 2L;
|
|
|
|
|
|
- // @todo (assira # 1) acmp
|
|
|
- protected Comparator<? super K> acmp;
|
|
|
+ private final Comparator<? super K> acmp;
|
|
|
|
|
|
/**
|
|
|
* The value of this variable remembers, after a
|
|
|
@@ -34,53 +34,51 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
*/
|
|
|
protected transient boolean modified;
|
|
|
|
|
|
- protected SortedLookup() {
|
|
|
- // do nothing
|
|
|
+ protected SortedLookup(Comparator<? super K> comparator) {
|
|
|
+ this.acmp = comparator;
|
|
|
}
|
|
|
|
|
|
- protected SortedLookup(Comparator<? super K> comparator) {
|
|
|
- this.acmp = comparator;
|
|
|
- }
|
|
|
+ protected abstract LookupEntry<K> findEntry(K key);
|
|
|
|
|
|
- @Override
|
|
|
- public final Integer put(K key, Integer value) {
|
|
|
- int oldValue = put(key, value.intValue());
|
|
|
- return modified ? null : oldValue;
|
|
|
- }
|
|
|
+ protected abstract LookupEntry<K> locateEntry(K key);
|
|
|
|
|
|
- @Override
|
|
|
- public final Integer remove(Object key) {
|
|
|
- int oldValue = removeInt(key);
|
|
|
- return modified ? oldValue : null;
|
|
|
+ protected abstract LookupEntry<K> firstEntry();
|
|
|
+
|
|
|
+ protected abstract LookupEntry<K> lastEntry();
|
|
|
+
|
|
|
+ protected abstract ListIterator<LookupEntry<K>> entryIterator();
|
|
|
+
|
|
|
+ protected abstract ListIterator<LookupEntry<K>> entryIterator(K begin);
|
|
|
+
|
|
|
+ protected abstract SortedLookup<K> submap(K begin, boolean bottom, K end, boolean top);
|
|
|
+
|
|
|
+ protected final int compare(K key1, K key2) {
|
|
|
+ return ValueUtils.cmp(acmp, key1, key2);
|
|
|
}
|
|
|
-
|
|
|
- @Override
|
|
|
- public final boolean containsValue(int value) {
|
|
|
- ValueIterator iterator = new ValueIterator(fastEntryIterator());
|
|
|
- int max = size();
|
|
|
- while (max-- != 0) {
|
|
|
- if (iterator.nextInt() == value) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
+
|
|
|
+ protected final K lower(K key1, K key2) {
|
|
|
+ return ValueUtils.lower(acmp, key1, key2);
|
|
|
}
|
|
|
-
|
|
|
- @Override
|
|
|
- public final ASortedSet<K> keySet() {
|
|
|
- return new KeySet();
|
|
|
+
|
|
|
+ protected final K higher(K key1, K key2) {
|
|
|
+ return ValueUtils.higher(acmp, key1, key2);
|
|
|
}
|
|
|
-
|
|
|
- /**
|
|
|
- * Returns a type-specific sorted collection.
|
|
|
- * @return a type-specific collection view of the values contained in this map
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Returns the comparator associated with this sorted set, or null if it
|
|
|
+ * uses its keys' natural ordering.
|
|
|
+ *
|
|
|
+ * <P>Note that this specification strengthens the one given in
|
|
|
+ * {@link SortedMap#comparator()}.
|
|
|
+ *
|
|
|
+ * @see SortedMap#comparator()
|
|
|
*/
|
|
|
@Override
|
|
|
- public final IntCollection values() {
|
|
|
- return new ValuesCollection();
|
|
|
- }
|
|
|
-
|
|
|
- @SuppressWarnings({"unchecked", "rawtypes"})
|
|
|
+ public final Comparator<? super K> comparator() {
|
|
|
+ return acmp;
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings({"unchecked", "rawtypes"})
|
|
|
@Override
|
|
|
public final ASortedSet<Entry<K, Integer>> entrySet() {
|
|
|
return (ASortedSet)fastEntrySet();
|
|
|
@@ -100,19 +98,20 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
return new EntrySet();
|
|
|
}
|
|
|
|
|
|
- // @todo (assira # 1) move to parent
|
|
|
- protected abstract ListIterator<LookupEntry<K>> fastEntryIterator();
|
|
|
-
|
|
|
- protected abstract ListIterator<LookupEntry<K>> fastEntryIterator(K begin);
|
|
|
+ @Override
|
|
|
+ public final ASortedSet<K> keySet() {
|
|
|
+ return new KeySet();
|
|
|
+ }
|
|
|
|
|
|
- protected abstract boolean inside(K key);
|
|
|
-
|
|
|
- protected abstract LookupEntry<K> findEntry(K key);
|
|
|
-
|
|
|
- protected abstract LookupEntry<K> firstEntry();
|
|
|
+ /**
|
|
|
+ * Returns a type-specific sorted collection.
|
|
|
+ * @return a type-specific collection view of the values contained in this map
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public final IntCollection values() {
|
|
|
+ return new ValuesCollection();
|
|
|
+ }
|
|
|
|
|
|
- protected abstract LookupEntry<K> lastEntry();
|
|
|
-
|
|
|
@Override
|
|
|
public final K firstKey() {
|
|
|
return firstEntry().getKey();
|
|
|
@@ -123,43 +122,27 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
return lastEntry().getKey();
|
|
|
}
|
|
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- @Override
|
|
|
- public final boolean containsKey(Object k) {
|
|
|
- return findEntry( (K)k) != null;
|
|
|
+ @Override
|
|
|
+ public final boolean containsValue(int value) {
|
|
|
+ ValueIterator iterator = new ValueIterator(SortedLookup.this.entryIterator());
|
|
|
+ int max = size();
|
|
|
+ while (max-- != 0) {
|
|
|
+ if (iterator.nextInt() == value) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
@Override
|
|
|
- public final int getInt(Object k) {
|
|
|
- LookupEntry<K> e = findEntry((K) k);
|
|
|
- return e == null ? defRetValue : e.getIntValue();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
- @Override
|
|
|
- public final Integer get(Object ok) {
|
|
|
- LookupEntry<K> e = findEntry((K) ok);
|
|
|
- return e == null ? (null) : e.getValue();
|
|
|
+ public final boolean containsKey(Object k) {
|
|
|
+ return findEntry( (K)k) != null;
|
|
|
}
|
|
|
-
|
|
|
|
|
|
- /**
|
|
|
- * Returns the comparator associated with this sorted set, or null if it
|
|
|
- * uses its keys' natural ordering.
|
|
|
- *
|
|
|
- * <P>Note that this specification strengthens the one given in
|
|
|
- * {@link SortedMap#comparator()}.
|
|
|
- *
|
|
|
- * @see SortedMap#comparator()
|
|
|
- */
|
|
|
- @Override
|
|
|
- public final Comparator<? super K> comparator() {
|
|
|
- return acmp;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
+ /**
|
|
|
* Returns a view of the portion of this sorted map whose keys range from
|
|
|
* <code>fromKey</code>, inclusive, to
|
|
|
* <code>toKey</code>, exclusive.
|
|
|
@@ -170,7 +153,9 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
* @see SortedMap#subMap(Object,Object)
|
|
|
*/
|
|
|
@Override
|
|
|
- public abstract SortedLookup<K> subMap(K begin, K end);
|
|
|
+ public SortedLookup<K> subMap(K begin, K end) {
|
|
|
+ return submap(begin, false, end, false);
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Returns a view of the portion of this sorted map whose keys are strictly
|
|
|
@@ -182,7 +167,9 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
* @see SortedMap#headMap(Object)
|
|
|
*/
|
|
|
@Override
|
|
|
- public abstract SortedLookup<K> headMap(K end);
|
|
|
+ public SortedLookup<K> headMap(K end) {
|
|
|
+ return submap(null, true, end, false);
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* Returns a view of the portion of this sorted map whose keys are greater
|
|
|
@@ -195,8 +182,44 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
* @see SortedMap#tailMap(Object)
|
|
|
*/
|
|
|
@Override
|
|
|
- public abstract SortedLookup<K> tailMap(K begin);
|
|
|
+ public SortedLookup<K> tailMap(K begin) {
|
|
|
+ return submap(begin, false, null, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Override
|
|
|
+ public final int getInt(Object k) {
|
|
|
+ LookupEntry<K> e = findEntry((K) k);
|
|
|
+ return e == null ? defRetValue : e.getIntValue();
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Override
|
|
|
+ public final Integer get(Object ok) {
|
|
|
+ LookupEntry<K> e = findEntry((K) ok);
|
|
|
+ return e == null ? (null) : e.getValue();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final Integer put(K key, Integer value) {
|
|
|
+ int oldValue = put(key, value.intValue());
|
|
|
+ return modified ? null : oldValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final Integer remove(Object key) {
|
|
|
+ int oldValue = removeInt(key);
|
|
|
+ return modified ? oldValue : null;
|
|
|
+ }
|
|
|
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* A wrapper exhibiting the keys of a map.
|
|
|
@@ -251,12 +274,12 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
|
|
|
@Override
|
|
|
public Iterator<K> iterator(K from) {
|
|
|
- return new KeySetIterator<>(fastEntryIterator(from));
|
|
|
+ return new KeySetIterator<>(entryIterator(from));
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Iterator<K> iterator() {
|
|
|
- return new KeySetIterator<>(fastEntryIterator());
|
|
|
+ return new KeySetIterator<>(SortedLookup.this.entryIterator());
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -297,7 +320,7 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
|
|
|
@Override
|
|
|
public IntIterator iterator() {
|
|
|
- return new ValueIterator<>(fastEntryIterator());
|
|
|
+ return new ValueIterator<>(entryIterator());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -366,12 +389,12 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
|
|
|
@Override
|
|
|
public Iterator<LookupEntry<K>> iterator() {
|
|
|
- return fastEntryIterator();
|
|
|
+ return entryIterator();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public Iterator<LookupEntry<K>> iterator(LookupEntry<K> from) {
|
|
|
- return fastEntryIterator(from.getKey());
|
|
|
+ return entryIterator(from.getKey());
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -387,7 +410,7 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
}
|
|
|
Map.Entry<K, Integer> entry = (Map.Entry<K, Integer>) object;
|
|
|
LookupEntry<K> found = findEntry(entry.getKey());
|
|
|
- return found != null && inside(entry.getKey()) && entry.equals(found);
|
|
|
+ return found != null && entry.equals(found);
|
|
|
}
|
|
|
|
|
|
@SuppressWarnings("unchecked")
|
|
|
@@ -398,7 +421,7 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
}
|
|
|
Map.Entry<K, Integer> entry = (Map.Entry<K, Integer>) o;
|
|
|
LookupEntry<K> found = findEntry((entry.getKey()));
|
|
|
- if (found != null && inside(found.getKey())) {
|
|
|
+ if (found != null) {
|
|
|
SortedLookup.this.removeInt(found.getIntValue());
|
|
|
}
|
|
|
return found != null;
|
|
|
@@ -415,7 +438,7 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
|
|
|
@Override
|
|
|
public boolean isEmpty() {
|
|
|
- return !fastEntryIterator().hasNext();
|
|
|
+ return !entryIterator().hasNext();
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
@@ -448,5 +471,168 @@ public abstract class SortedLookup<K> extends Lookup<K> implements SortedMap<K,
|
|
|
return tailMap(from.getKey()).fastEntrySet();
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * A submap with given range.
|
|
|
+ *
|
|
|
+ * <P>This class represents a submap. One has to specify the left/right
|
|
|
+ * limits (which can be set to -∞ or ∞). Since the submap is a
|
|
|
+ * view on the map, at a given moment it could happen that the limits of the
|
|
|
+ * range are not any longer in the main map. Thus, things such as
|
|
|
+ * {@link java.util.SortedMap#firstKey()} or
|
|
|
+ * {@link java.util.Collection#size()} must be always computed on-the-fly.
|
|
|
+ */
|
|
|
+ protected abstract class ASubmap extends SortedLookup<K> implements java.io.Serializable {
|
|
|
+
|
|
|
+ private static final long serialVersionUID = 2L;
|
|
|
+ /**
|
|
|
+ * The start of the submap range, unless {@link #bottom} is true.
|
|
|
+ */
|
|
|
+ K from;
|
|
|
+ /**
|
|
|
+ * The end of the submap range, unless {@link #top} is true.
|
|
|
+ */
|
|
|
+ K to;
|
|
|
+ /**
|
|
|
+ * If true, the submap range starts from -∞.
|
|
|
+ */
|
|
|
+ boolean bottom;
|
|
|
+ /**
|
|
|
+ * If true, the submap range goes to ∞.
|
|
|
+ */
|
|
|
+ boolean top;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Creates a new submap with given key range.
|
|
|
+ *
|
|
|
+ * @param from the start of the submap range.
|
|
|
+ * @param bottom if true, the first parameter is ignored and the range
|
|
|
+ * starts from -∞.
|
|
|
+ * @param to the end of the submap range.
|
|
|
+ * @param top if true, the third parameter is ignored and the range goes
|
|
|
+ * to ∞.
|
|
|
+ */
|
|
|
+ public ASubmap(K from, boolean bottom, K to, boolean top) {
|
|
|
+ super(SortedLookup.this.acmp);
|
|
|
+ if (!bottom && !top && ValueUtils.cmp(acmp, from, to) > 0) {
|
|
|
+ throw new IllegalArgumentException("Start key (" + from + ") is larger than end key (" + to + ")");
|
|
|
+ }
|
|
|
+ this.from = from;
|
|
|
+ this.bottom = bottom;
|
|
|
+ this.to = to;
|
|
|
+ this.top = top;
|
|
|
+ this.defRetValue = SortedLookup.this.defRetValue;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final void clear() {
|
|
|
+ ListIterator<LookupEntry<K>> i = entryIterator();
|
|
|
+ while (i.hasNext()) {
|
|
|
+ i.next();
|
|
|
+ i.remove();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Checks whether a key is in the submap range.
|
|
|
+ *
|
|
|
+ * @param k a key.
|
|
|
+ * @return true if is the key is in the submap range.
|
|
|
+ */
|
|
|
+ protected final boolean inside(K k) {
|
|
|
+ return (bottom || ValueUtils.cmp(acmp, k, from) >= 0)
|
|
|
+ && (top || ValueUtils.cmp(acmp, k, to) < 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract ListIterator<LookupEntry<K>> entryIterator();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract ListIterator<LookupEntry<K>> entryIterator(K begin);
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract LookupEntry<K> findEntry(K key);
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract LookupEntry<K> locateEntry(K key);
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract LookupEntry<K> firstEntry();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected abstract LookupEntry<K> lastEntry();
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int put(K k, int v) {
|
|
|
+ if (!inside(k)) {
|
|
|
+ SortedLookup.this.modified = false;
|
|
|
+ throw new IllegalArgumentException("Key (" + k + ") out of range [" + (bottom ? "-" : String.valueOf(from)) + ", " + (top ? "-" : String.valueOf(to)) + ")");
|
|
|
+ }
|
|
|
+ return super.put(k, v);
|
|
|
+ }
|
|
|
+
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ @Override
|
|
|
+ public final int removeInt(Object k) {
|
|
|
+ if (!inside((K) k)) {
|
|
|
+ SortedLookup.this.modified = false;
|
|
|
+ return this.defRetValue;
|
|
|
+ }
|
|
|
+ return SortedLookup.this.removeInt(k);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final int size() {
|
|
|
+ ListIterator<LookupEntry<K>> i = entryIterator();
|
|
|
+ int n = 0;
|
|
|
+ while (i.hasNext()) {
|
|
|
+ n++;
|
|
|
+ i.next();
|
|
|
+ }
|
|
|
+ return n;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final boolean isEmpty() {
|
|
|
+ return !entryIterator().hasNext();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final SortedLookup<K> headMap(K to) {
|
|
|
+ if (top) {
|
|
|
+ return submap(from, bottom, to, false);
|
|
|
+ }
|
|
|
+ return ValueUtils.cmp(acmp, to, this.to) < 0 ? submap(from, bottom, to, false) : this;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final SortedLookup<K> tailMap(K from) {
|
|
|
+ if (bottom) {
|
|
|
+ return submap(from, false, to, top);
|
|
|
+ }
|
|
|
+ return ValueUtils.cmp(acmp, from, this.from) > 0 ? submap(from, false, to, top) : this;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public final SortedLookup<K> subMap(K from, K to) {
|
|
|
+ if (top && bottom) {
|
|
|
+ return submap(from, false, to, false);
|
|
|
+ }
|
|
|
+ if (!top) {
|
|
|
+ to = ValueUtils.cmp(acmp, to, this.to) < 0 ? to : this.to;
|
|
|
+ }
|
|
|
+ if (!bottom) {
|
|
|
+ from = ValueUtils.cmp(acmp, from, this.from) > 0 ? from : this.from;
|
|
|
+ }
|
|
|
+ if (!top && !bottom && from == this.from && to == this.to) {
|
|
|
+ return this;
|
|
|
+ }
|
|
|
+ return submap(from, false, to, false);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected abstract SortedLookup<K> submap(K from, boolean bottom, K to, boolean top);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
}
|