Skip to content

Commit

Permalink
Minor optimisation to Index encoding (save a byte in leaf entries)
Browse files Browse the repository at this point in the history
  • Loading branch information
mikera committed Oct 2, 2024
1 parent e30c49b commit 1018f3e
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 31 deletions.
42 changes: 32 additions & 10 deletions convex-core/src/main/java/convex/core/data/Index.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public final class Index<K extends ABlobLike<?>, V extends ACell> extends AIndex

/**
* Entry for this node of the radix tree. Invariant assumption that the prefix
* is correct. May be null if there is no entry at this node.
* is correct. Will be null if there is no entry at this node.
*/
private final MapEntry<K, V> entry;

Expand Down Expand Up @@ -518,14 +518,28 @@ public int encodeRaw(byte[] bs, int pos) {
pos = Format.writeVLCCount(bs,pos, count);
if (count == 0) return pos; // nothing more to know... this must be the empty singleton

pos = MapEntry.encodeCompressed(entry,bs,pos); // entry may be null
if (count == 1) return pos; // must be a single entry
if (count == 1) {
// directly encode single entry
pos=entry.getKeyRef().encode(bs,pos);
pos=entry.getValueRef().encode(bs,pos);
return pos; // must be a single entry, exit early
} else {
if (entry==null) {
bs[pos++]=Tag.NULL; // no entry present
} else {
bs[pos++]=Tag.VECTOR;
pos=entry.getKeyRef().encode(bs,pos);
pos=entry.getValueRef().encode(bs,pos);
}
}

// We only have a meaningful depth if more than one entry
bs[pos++] = (byte)depth;

// write mask
pos = Utils.writeShort(bs,pos,mask);

// finally write children
pos = Utils.writeShort(bs,pos,mask);
int n = children.length;
for (int i = 0; i < n; i++) {
pos = encodeChild(bs,pos,i);
Expand Down Expand Up @@ -559,14 +573,22 @@ public static <K extends ABlobLike<?>, V extends ACell> Index<K, V> read(Blob b,
if (count < 0) throw new BadFormatException("Negative count!");
if (count == 0) return (Index<K, V>) EMPTY;

// index for reading
int epos=pos+1+Format.getVLCCountLength(count);


byte etype=b.byteAt(epos++);
MapEntry<K,V> me;
if (etype==Tag.NULL) {
me=null;
} else if (etype==Tag.VECTOR){
boolean hasEntry;
if (count==1) {
hasEntry=true;
} else {
byte c=b.byteAt(epos++); // Read byte
switch (c) {
case Tag.NULL: hasEntry=false; break;
case Tag.VECTOR: hasEntry=true; break;
default: throw new BadFormatException("Invalid MapEntry tag in Index: "+c);
}
}
if (hasEntry) {
Ref<K> kr=Format.readRef(b,epos);
epos+=kr.getEncodingLength();
Ref<V> vr=Format.readRef(b,epos);
Expand All @@ -581,7 +603,7 @@ public static <K extends ABlobLike<?>, V extends ACell> Index<K, V> read(Blob b,
return result;
}
} else {
throw new BadFormatException("Invalid MapEntry tag in Index: "+etype);
me=null;
}

Index<K,V> result;
Expand Down
19 changes: 0 additions & 19 deletions convex-core/src/main/java/convex/core/data/MapEntry.java
Original file line number Diff line number Diff line change
Expand Up @@ -258,25 +258,6 @@ int encodeRefs(byte[] bs, int pos) {
pos = valueRef.encode(bs,pos);
return pos;
}

/**
* Writes a MapEntry or null content in compressed format (no count). Useful for
* embedding an optional MapEntry inside a larger Encoding
*
* @param me MapEntry to encode
* @param bs Byte array to write to
* @param pos Starting position for encoding in byte array
* @return Updated position after writing
*/
public static int encodeCompressed(MapEntry<?,?> me,byte[] bs, int pos) {
if (me==null) {
bs[pos++]=Tag.NULL;
} else {
bs[pos++]=Tag.VECTOR;
pos = me.encodeRefs(bs,pos);
}
return pos;
}

@Override
public int estimatedEncodingSize() {
Expand Down
4 changes: 2 additions & 2 deletions convex-core/src/test/java/convex/core/TokenomicsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ public void testTransferFail() {
Invoke t=Invoke.create(HERO, SEQ, Reader.read("(do (set-memory 0) (def a 0x12345678123456781234567812345678))"));
ResultContext rc=runTransaction(t);

// memory of more than 16 bytes should be used, but not more than 100
// memory of more than 16 bytes should be used, but not more than 200
assertGreater(rc.memUsed,16);
assertLess(rc.memUsed,100);
assertLess(rc.memUsed,200);

assertEquals(rc.totalFees,rc.getJuiceFees()+rc.getMemoryFees());

Expand Down

0 comments on commit 1018f3e

Please sign in to comment.