Skip to content

Commit f7fed31

Browse files
committed
refactor: Replace HashMap with Vec to slightly improve performance for large schematics
1 parent ab4f7c5 commit f7fed31

File tree

1 file changed

+19
-14
lines changed

1 file changed

+19
-14
lines changed

crates/pico_structures/src/chunk_processor.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ use crate::palette::Palette;
33
use crate::prelude::Schematic;
44
use blocks_report::InternalId;
55
use minecraft_protocol::prelude::Coordinates;
6-
use std::collections::HashMap;
76
use std::mem;
87
use thiserror::Error;
98

9+
const UNSEEN_ID_INDEX: u32 = u32::MAX;
10+
11+
const LOOKUP_TABLE_SIZE: usize = InternalId::MAX as usize + 1;
12+
1013
/// A helper struct to hold reusable buffers for palette generation.
1114
/// This avoids re-allocating the HashMap and palette Vec for every chunk.
1215
/// The main block data is now handled on the stack.
1316
pub struct ChunkProcessor {
1417
palette: Vec<InternalId>,
15-
id_to_palette_index: HashMap<InternalId, u32>,
18+
id_to_palette_index: Vec<u32>,
1619
}
1720

1821
#[derive(Debug, Error)]
@@ -27,17 +30,17 @@ impl ChunkProcessor {
2730
pub fn new() -> Self {
2831
Self {
2932
palette: Vec::with_capacity(Self::MAX_PALETTED_SIZE),
30-
id_to_palette_index: HashMap::with_capacity(Self::MAX_PALETTED_SIZE),
33+
id_to_palette_index: vec![UNSEEN_ID_INDEX; LOOKUP_TABLE_SIZE],
3134
}
3235
}
3336

34-
/// Resets the internal buffers to be ready for the next chunk.
3537
fn prepare_for_next_chunk(&mut self) {
3638
self.palette.clear();
37-
self.id_to_palette_index.clear();
39+
for &id in &self.palette {
40+
self.id_to_palette_index[id as usize] = UNSEEN_ID_INDEX;
41+
}
3842
}
3943

40-
/// Processes a 16x16x16 section using a stack-allocated array for block data.
4144
pub fn process_section(
4245
&mut self,
4346
schematic: &Schematic,
@@ -72,13 +75,13 @@ impl ChunkProcessor {
7275
first_id = Some(internal_id);
7376
}
7477

75-
self.id_to_palette_index
76-
.entry(internal_id)
77-
.or_insert_with(|| {
78-
let index = self.palette.len() as u32;
79-
self.palette.push(internal_id);
80-
index
81-
});
78+
let palette_index_slot = &mut self.id_to_palette_index[internal_id as usize];
79+
80+
if *palette_index_slot == UNSEEN_ID_INDEX {
81+
let new_index = self.palette.len() as u32;
82+
self.palette.push(internal_id);
83+
*palette_index_slot = new_index;
84+
}
8285
}
8386
}
8487
}
@@ -96,7 +99,9 @@ impl ChunkProcessor {
9699
if bits_per_entry <= 8 {
97100
let bits_per_entry = bits_per_entry.clamp(4, 8) as u8;
98101

99-
let paletted_data = block_ids.iter().map(|id| self.id_to_palette_index[id]);
102+
let paletted_data = block_ids
103+
.iter()
104+
.map(|&id| self.id_to_palette_index[id as usize]);
100105
let packed_data = pack_direct(paletted_data, bits_per_entry);
101106

102107
Ok(Palette::paletted(

0 commit comments

Comments
 (0)