Skip to content

Commit 2711aed

Browse files
committed
LargePalette: avoid paying upfront performance penalty for cache population
This made the creation of large palettes 100x slower. By harnessing the scans that we would've done on writes previously anyway, we can lazily populate the map when the element isn't found in the map. Performance of write is therefore no worse than previous for the first write, and for subsequent ones will always be faster. Since many palettes go their entire lifespan without being modified, it doesn't make much sense to pay an up-front performance penalty.
1 parent 3a50408 commit 2711aed

File tree

1 file changed

+16
-3
lines changed

1 file changed

+16
-3
lines changed

lib/Palette.h

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,12 @@ class LargePalette final {
9999
private:
100100
std::vector<Block> palette;
101101
std::unordered_map<Block, unsigned int> blockToOffset;
102+
unsigned int lowestUnscanned = 0;
102103

103104
void initFromData(const gsl::span<const Block> paletteEntries) {
104105
PaletteUtils<MAX_PALETTE_SIZE>::checkSize(paletteEntries.size());
105106

106107
palette = std::vector<Block>(paletteEntries.begin(), paletteEntries.end());
107-
for (unsigned int i = 0; i < palette.size(); ++i) {
108-
blockToOffset[palette[i]] = i;
109-
}
110108
}
111109

112110
public:
@@ -150,6 +148,21 @@ class LargePalette final {
150148
return it->second;
151149
}
152150

151+
//Lookup map is lazily populated to avoid a performance penalty on data load
152+
//Since it's possible for an array to go its whole lifespan without any writes,
153+
//there's little sense paying a performance penalty on load to pre-populate it
154+
//Previously we would've had to do a scan like this anyway, but with the offset
155+
//map cache we can get more mileage out of it by avoiding such large scans on
156+
//subsequent writes
157+
for (unsigned int offset = lowestUnscanned; offset < palette.size(); ++offset) {
158+
blockToOffset[palette[offset]] = offset;
159+
if (palette[offset] == val) {
160+
lowestUnscanned = offset + 1;
161+
return offset;
162+
}
163+
}
164+
lowestUnscanned = palette.size();
165+
153166
if (palette.size() >= MAX_PALETTE_SIZE) {
154167
return -1;
155168
}

0 commit comments

Comments
 (0)