Skip to content

Commit

Permalink
More HashMap improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Oct 8, 2024
1 parent 6abd138 commit 20be455
Show file tree
Hide file tree
Showing 8 changed files with 55 additions and 44 deletions.
32 changes: 11 additions & 21 deletions convex-core/src/main/java/convex/core/data/AHashMap.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package convex.core.data;

import java.util.HashSet;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;

Expand All @@ -20,22 +18,22 @@ public AHashMap<K, V> empty() {
return Maps.empty();
}

/**
* Dissoc given a Ref to the key value.
* @param key Ref of key to remove
* @return Map with specified key removed.
*/
public abstract AHashMap<K, V> dissocRef(Ref<K> key);

public abstract AHashMap<K, V> assocRef(Ref<K> keyRef, V value);

@Override
public abstract AHashMap<K, V> assoc(ACell key, ACell value);

public abstract AHashMap<K, V> assocRef(Ref<K> keyRef, V value);

public abstract AHashMap<K, V> assocEntry(MapEntry<K, V> e);

@Override
public abstract AHashMap<K, V> dissoc(ACell key);

public abstract AHashMap<K, V> assocEntry(MapEntry<K, V> e);

/**
* Dissoc given a Hash for the key value.
* @param key Hash of key to remove
* @return Map with specified key removed.
*/
public abstract AHashMap<K, V> dissocHash(Hash key);

/**
* Merge another map into this map. Replaces existing entries if they are
Expand Down Expand Up @@ -171,14 +169,6 @@ public AVector<K> getKeys() {
*/
protected abstract Hash getFirstHash();

@Override
public HashSet<Entry<K, V>> entrySet() {
int len = size();
HashSet<Map.Entry<K, V>> h = new HashSet<Map.Entry<K, V>>(len);
accumulateEntrySet(h);
return h;
}

@Override
public AHashMap<K,V> slice(long start) {
return slice(start,count);
Expand Down
14 changes: 12 additions & 2 deletions convex-core/src/main/java/convex/core/data/AMap.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package convex.core.data;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -100,11 +102,11 @@ public final boolean containsValue(Object value) {
public abstract MapEntry<K, V> getKeyRefEntry(Ref<ACell> ref);

/**
* Accumulate all entries from this map in the given mutable Set.
* Accumulate all entries from this map in the given collection
*
* @param h HashSet in which to accumulate entries
*/
protected abstract void accumulateEntrySet(Set<Entry<K, V>> h);
protected abstract void accumulateEntries(Collection<Entry<K, V>> h);

/**
* Accumulate all keys from this map in the given mutable Set.
Expand Down Expand Up @@ -267,6 +269,14 @@ public Set<K> keySet() {
return ks;
}

@Override
public Set<Entry<K, V>> entrySet() {
int len = size();
HashSet<Map.Entry<K, V>> h = new HashSet<Map.Entry<K, V>>(len);
accumulateEntries(h);
return h;
}

/**
* Gets the map entry with the specified hash
*
Expand Down
3 changes: 2 additions & 1 deletion convex-core/src/main/java/convex/core/data/ARecord.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package convex.core.data;

import java.util.Collection;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
Expand Down Expand Up @@ -153,7 +154,7 @@ public MapEntry<Keyword, ACell> getKeyRefEntry(Ref<ACell> keyRef) {
}

@Override
protected void accumulateEntrySet(Set<Entry<Keyword, ACell>> h) {
protected void accumulateEntries(Collection<Entry<Keyword, ACell>> h) {
for (long i=0; i<count; i++) {
h.add(entryAt(i));
}
Expand Down
3 changes: 2 additions & 1 deletion convex-core/src/main/java/convex/core/data/Cells.java
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,8 @@ public static <T extends ACell> T announce(T a, Consumer<Ref<ACell>> noveltyHand
*/
public static Hash getHash(ACell a) {
if (a==null) return Hash.NULL_HASH;
return a.getHash();
// this picks up a hash in the Ref if available, otherwise populates it for future use
return a.getRef().getHash();
}

public static Blob getEncoding(ACell a) {
Expand Down
5 changes: 3 additions & 2 deletions convex-core/src/main/java/convex/core/data/Index.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package convex.core.data;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -283,9 +284,9 @@ private ABlobLike<?> getPrefix() {
}

@Override
protected void accumulateEntrySet(Set<Entry<K, V>> h) {
protected void accumulateEntries(Collection<Entry<K, V>> h) {
for (int i = 0; i < children.length; i++) {
children[i].getValue().accumulateEntrySet(h);
children[i].getValue().accumulateEntries(h);
}
if (entry != null) h.add(entry);
}
Expand Down
9 changes: 5 additions & 4 deletions convex-core/src/main/java/convex/core/data/MapLeaf.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -161,10 +162,10 @@ private int seek(K key) {
return -1;
}

private int seekKeyRef(Ref<K> key) {
private int seekKeyRef(Hash keyHash) {
int len = size();
for (int i = 0; i < len; i++) {
if (Utils.equals(key, entries[i].getKeyRef())) return i;
if (Utils.equals(keyHash, entries[i].getKeyHash())) return i;
}
return -1;
}
Expand All @@ -178,7 +179,7 @@ public MapLeaf<K, V> dissoc(ACell key) {
}

@Override
public MapLeaf<K, V> dissocRef(Ref<K> key) {
public MapLeaf<K, V> dissocHash(Hash key) {
int i = seekKeyRef(key);
if (i < 0) return this; // not found
return dissocEntry(i);
Expand Down Expand Up @@ -300,7 +301,7 @@ protected void accumulateValues(java.util.List<V> al) {
}

@Override
protected void accumulateEntrySet(Set<Entry<K, V>> h) {
protected void accumulateEntries(Collection<Entry<K, V>> h) {
for (int i = 0; i < entries.length; i++) {
MapEntry<K, V> me = entries[i];
h.add(me);
Expand Down
31 changes: 20 additions & 11 deletions convex-core/src/main/java/convex/core/data/MapTree.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package convex.core.data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
Expand Down Expand Up @@ -289,29 +291,33 @@ protected MapEntry<K, V> getEntryByHash(Hash hash) {
return children[i].getValue().getEntryByHash(hash);
}

@SuppressWarnings("unchecked")
@Override
public AHashMap<K, V> dissoc(ACell key) {
return dissocRef((Ref<K>) Ref.get(key));
return dissocHash(Cells.getHash(key));
}

@Override
@SuppressWarnings("unchecked")
public AHashMap<K, V> dissocRef(Ref<K> keyRef) {
int digit = keyRef.getHash().getHexDigit(shift);
public AHashMap<K, V> dissocHash(Hash keyHash) {
int digit = keyHash.getHexDigit(shift);
int i = Bits.indexForDigit(digit, mask);
if (i < 0) return this; // not present

// dissoc entry from child
AHashMap<K, V> child = children[i].getValue();
AHashMap<K, V> newChild = child.dissocRef(keyRef);
AHashMap<K, V> newChild = child.dissocHash(keyHash);
if (child == newChild) return this; // no removal, no change

if (count - 1 == MapLeaf.MAX_ENTRIES) {
// reduce to a ListMap
HashSet<Entry<K, V>> eset = entrySet();
boolean removed = eset.removeIf(e -> Utils.equals(((MapEntry<K, V>) e).getKeyRef(), keyRef));
if (!removed) throw new Panic("Expected to remove at least one entry!");
ArrayList<Entry<K, V>> eset = new ArrayList<>();
for (int j=0; j<children.length; j++) {
AHashMap<K, V> c = (i==j)?newChild:children[j].getValue();
c.accumulateEntries(eset);
}
if (!(eset.size()==MapLeaf.MAX_ENTRIES)) {
throw new Panic("Expected to remove at least one entry!");
}
return MapLeaf.create(eset.toArray((MapEntry<K, V>[]) MapLeaf.EMPTY_ENTRIES));
} else {
// replace child
Expand Down Expand Up @@ -461,9 +467,9 @@ protected void accumulateValues(java.util.List<V> al) {
}

@Override
protected void accumulateEntrySet(Set<Entry<K, V>> h) {
protected void accumulateEntries(Collection<Entry<K, V>> h) {
for (Ref<AHashMap<K, V>> mr : children) {
mr.getValue().accumulateEntrySet(h);
mr.getValue().accumulateEntries(h);
}
}

Expand Down Expand Up @@ -839,6 +845,9 @@ public void validate() throws InvalidDataException {
protected void validateWithPrefix(Hash prefix, int shift) throws InvalidDataException {
if (mask == 0) throw new InvalidDataException("TreeMap must have children!", this);
int bsize = children.length;
if (bsize<2) {
throw new InvalidDataException("Non-canonical MapTree with child count "+bsize,this);
}

long childCount=0;;
for (int i = 0; i < bsize; i++) {
Expand All @@ -848,7 +857,7 @@ protected void validateWithPrefix(Hash prefix, int shift) throws InvalidDataExce
ACell o = children[i].getValue();
if (!(o instanceof AHashMap)) {
throw new InvalidDataException(
"Expected map child at " + prefix + Utils.toHexChar(digitForIndex(i, mask)), this);
"Expected AHashMap child at " + prefix + Utils.toHexChar(digitForIndex(i, mask)), this);
}
@SuppressWarnings("unchecked")
AHashMap<K, V> child = (AHashMap<K, V>) o;
Expand Down
2 changes: 0 additions & 2 deletions convex-core/src/test/java/convex/core/data/MapsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -287,8 +287,6 @@ public void testBigMapChild() {

@Test
public void testBigMapSlice() {


AHashMap<CVMLong,CVMLong> bm=Samples.LONG_MAP_100;
AHashMap<CVMLong,CVMLong> bm1=bm.slice(0,18);
assertEquals(18,bm1.count());
Expand Down

0 comments on commit 20be455

Please sign in to comment.