You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Instead of wasting a bunch of memory and CPU time,
use vectors to save memory on larger sizes, and
a map to lookup IDs instead of bruteforce searching
them. 16 bpb benefits a crazy amount by this, with
write operations becoming 100x faster. 8 bpb gets 20x
faster, and to my surprise, 6 bpb gets 4x faster.
throwstd::length_error("palette size should be at most " + std::to_string(MAX_PALETTE_SIZE) + " entries, but received " + std::to_string(size) + " entries");
10
+
}
11
+
if (size == 0) {
12
+
throwstd::length_error("palette cannot have a zero size");
13
+
}
14
+
}
15
+
};
16
+
17
+
/*
18
+
* Small palettes use fixed arrays to avoid vector indirections and allocations
19
+
* Performance is more important here because the amount of wasted memory is insignificant
20
+
* regardless of the number of elements in the palette.
21
+
*
22
+
* Lookups are done with a linear search, which is faster than using a hash map for small
throwstd::length_error("word array size should be exactly " + std::to_string(sizeof(words)) + " bytes for a " + std::to_string(BITS_PER_BLOCK_INT) + "bpb block array, got " + std::to_string(wordArray.size()) + " bytes");
206
214
}
207
-
if (paletteEntries.size() > MAX_PALETTE_SIZE) {
208
-
throwstd::length_error("palette size should be at most " + std::to_string(MAX_PALETTE_SIZE) + " entries for a " + std::to_string(BITS_PER_BLOCK_INT) + "bpb block array, got " + std::to_string(paletteEntries.size()) + " entries");
209
-
}
210
-
if (paletteEntries.size() == 0) {
211
-
throwstd::length_error("palette cannot have a zero size");
@@ -249,8 +246,8 @@ class PalettedBlockArray final : public IPalettedBlockArray<Block> {
249
246
for (Coord x = 0; x < Base::ARRAY_DIM; ++x) {
250
247
for (Coord z = 0; z < Base::ARRAY_DIM; ++z) {
251
248
for (Coord y = 0; y < Base::ARRAY_DIM; ++y) {
252
-
auto inserted = hasFound.insert(palette[_getPaletteOffset(x, y, z)]).second;
253
-
if (inserted && hasFound.size() == getPaletteSize()) {
249
+
auto inserted = hasFound.insert(palette.get(_getPaletteOffset(x, y, z))).second;
250
+
if (inserted && hasFound.size() == palette.size()) {
254
251
break;
255
252
}
256
253
}
@@ -266,37 +263,25 @@ class PalettedBlockArray final : public IPalettedBlockArray<Block> {
266
263
267
264
Block get(Coord x, Coord y, Coord z) const {
268
265
unsignedshort offset = _getPaletteOffset(x, y, z);
269
-
assert(offset < nextPaletteIndex);
270
-
return palette[offset];
266
+
assert(offset < palette.size());
267
+
return palette.get(offset);
271
268
}
272
269
273
270
boolset(Coord x, Coord y, Coord z, Block val) {
274
-
//TODO (suggested by sandertv): check performance when recording last written block and palette offset - might improve performance for repetetive writes
275
-
276
-
short offset = -1;
271
+
int offset = palette.addOrLookup(val);
277
272
bool needGC = true;
278
-
for (short i = 0; i < nextPaletteIndex; ++i) {
279
-
if (palette[i] == val) {
280
-
offset = i;
281
-
break;
282
-
}
283
-
}
284
273
285
274
if (offset == -1) {
286
-
if (nextPaletteIndex >= MAX_PALETTE_SIZE) {
287
-
if (MAX_PALETTE_SIZE < Base::ARRAY_CAPACITY || this->mayNeedGC) {
288
-
returnfalse;
289
-
}
290
-
//overwrite existing offset on fully used, non-dirty palette
291
-
offset = _getPaletteOffset(x, y, z);
292
-
//we skip GC because:
293
-
//- we know this block isn't already in the palette
294
-
//- we know every block in the array has its own palette entry (palette full and not dirty), therefore we must be overwriting an entry that's only used by 1 block anyway.
295
-
needGC = false;
296
-
} else {
297
-
offset = (short)nextPaletteIndex++;
275
+
if (MAX_PALETTE_SIZE < Base::ARRAY_CAPACITY || this->mayNeedGC) {
276
+
returnfalse;
298
277
}
299
-
palette[offset] = val;
278
+
//overwrite existing offset on fully used, non-dirty palette
279
+
offset = _getPaletteOffset(x, y, z);
280
+
//we skip GC because:
281
+
//- we know this block isn't already in the palette
282
+
//- we know every block in the array has its own palette entry (palette full and not dirty), therefore we must be overwriting an entry that's only used by 1 block anyway.
283
+
needGC = false;
284
+
palette.set(offset, val);
300
285
}
301
286
302
287
_setPaletteOffset(x, y, z, offset);
@@ -310,9 +295,9 @@ class PalettedBlockArray final : public IPalettedBlockArray<Block> {
310
295
311
296
voidreplaceAll(Block from, Block to) {
312
297
//TODO: clean up any duplicates
313
-
for (short i = 0; i < nextPaletteIndex; ++i) {
314
-
if (palette[i] == from) {
315
-
palette[i] = to;
298
+
for (short i = 0; i < palette.size(); ++i) {
299
+
if (palette.get(i) == from) {
300
+
palette.set(i, to);
316
301
317
302
//don't return here, because there might be duplicated block states from previous replace operations
318
303
}
@@ -335,8 +320,10 @@ class PalettedBlockArray final : public IPalettedBlockArray<Block> {
0 commit comments