Caching pattern angles signature for high-frequency matches and else - #1260
Caching pattern angles signature for high-frequency matches and else#1260YukkuriC wants to merge 2 commits into
Conversation
|
I think the answer for the better design here may be an immutable Additionally, if |
|
If we wanted to go super crazy, pattern building and checking could be a lot more optimized. I don't know Kotlin off the top of my head so I'll write the Java equivalents: public final class HexSignature {
// array of integers that pack in angles
// each int is split into bits:
// ?? jjj iii hhh ggg fff eee ddd ccc bbb aaa
// 000 → path ends before a multiple of 10 steps
// 001 → forward
// 010 → right
// etc
// this is so new int[n] initializes everything to "end of path" i.e. it doesn't have to be set manually
// `10` should probably be put in a constant somewhere
// keep in mind that arrays are mutable, so don't expose any setters
private final int[] packedTurns;
// memoized hashcode for fast lookup
private final int memoizedHash;
private HexShape(int[] packedTurns) {
this.packedTurns = packedTurns;
this.memoizedHash = Arrays.hashCode(packedTurns);
}
// override equals to use Arrays.equals
// override hashCode to just return the memoizedHash
}
public final class HexPattern {
private final HexSignature sig;
private final HexAngle orientation;
public static final class Builder {
private final HexAngle startDirection;
private final IntArrayList turnsBuilder;
public Builder(HexAngle startDirection) { /* implementation omitted */ }
HexPattern build() { /* implementation omitted */ }
}
}Calling If we can assume that a vertex coordinate in a pattern will never exceed [-32768, 32767], then constructing a pattern while checking its angles can also be made a lot more efficient. Essentially you pack vertices into // a long[] actually may be more performant here!
// LongArraySet provides a convenient wrapper for something that can grow, but...
// new long[1 + (packedTurns.length * 10)] is guaranteed to be enough space to hold all the edges
LongOpenHashSet edgeSet = new LongOpenHashSet(1 + (packedTurns.length * 10));
// (q, r) coordinates for our current vertex
short fromQ = ...;
short fromR = ...;
// (q, r) coordinates for our next vertex
short toQ = ...;
short toR = ...;
int from = (fromQ << 16) | fromR;
int to = (toQ << 16) | toR;
// `if(to < from) /* swap */` is "technically" faster but definitely not worth the readability loss
int lesser = Math.min(from, to);
int greater = Math.max(from, to);
long edge = ((long) lesser << 32L) | (long) greater;
if(edgeSet.add(edge)) // idk |
|
maybe someone else will continue this one ;w; |
tried my best to make its exposed interface stable, and relevant files change minimized ;w;