perf(hash): swap std HashMap/HashSet for rustc-hash FxHash

Phase 4.1. Handle / u64 keys dominate the hot maps (block_defn,
hatch / image / mesh caches, draw-depth map, viewport wire caches);
the default SipHash is wasted work on integer keys. Alias the std
types to rustc_hash::FxHashMap / FxHashSet crate-wide so every map and
set — including the cross-module draw-depth map shared between scene
and the GPU pipelines — uses the faster hasher consistently.

Mechanical: no behavioural change. Constructors moved from ::new() to
::default() (Fx variants carry no RandomState). Build + 13 tests green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Hakan Seven 2026-06-05 00:35:53 +03:00
commit 70702d063f
30 changed files with 102 additions and 98 deletions

View file

@ -9,7 +9,7 @@
//! STB files follow the same format but use named styles instead of
//! ACI indices; they are read into a `Vec<NamedPlotStyle>`.
use std::collections::HashMap;
use rustc_hash::FxHashMap as HashMap;
use std::io::Read;
use std::path::Path;
@ -72,7 +72,7 @@ impl PlotStyleTable {
name: name.into(),
is_stb: false,
aci_entries: (0..=255).map(|_| PlotStyleEntry::default()).collect(),
named_entries: HashMap::new(),
named_entries: HashMap::default(),
}
}
@ -202,7 +202,7 @@ fn compress_ctb(text: &[u8]) -> Result<Vec<u8>, String> {
fn parse_plot_style_text(text: &str, name: String, is_stb: bool) -> Result<PlotStyleTable, String> {
let mut aci_entries: Vec<PlotStyleEntry> =
(0..=255).map(|_| PlotStyleEntry::default()).collect();
let mut named_entries: HashMap<String, PlotStyleEntry> = HashMap::new();
let mut named_entries: HashMap<String, PlotStyleEntry> = HashMap::default();
let mut style_index: usize = 1; // CTB: 1-based ACI index
let mut current: Option<PlotStyleEntry> = None;
let mut current_name: String = String::new();

View file

@ -5,7 +5,7 @@ use acadrust::entities::{Block, BlockEnd};
use acadrust::tables::TableEntry;
use acadrust::types::{Handle, Vector3};
use acadrust::{CadDocument, EntityType};
use std::collections::HashMap;
use rustc_hash::FxHashMap as HashMap;
use std::path::{Path, PathBuf};
/// Status of an external reference block.
@ -160,7 +160,7 @@ fn merge_xref_into_block(
// Prefix every xref layer (including "0"). Entity layer references are
// remapped below so the resolver finds the merged copy. Host layers
// (incl. its own "0") are untouched — no collisions.
let mut layer_map: HashMap<String, String> = HashMap::new();
let mut layer_map: HashMap<String, String> = HashMap::default();
for layer in xref_doc.layers.iter() {
let old = layer.name.clone();
let new = format!("{}|{}", prefix, old);
@ -174,7 +174,7 @@ fn merge_xref_into_block(
// ── Linetypes ───────────────────────────────────────────────────────
// Skip the three sentinel names — "ByLayer" / "ByBlock" / "Continuous"
// are magic strings the resolver matches verbatim in both docs.
let mut linetype_map: HashMap<String, String> = HashMap::new();
let mut linetype_map: HashMap<String, String> = HashMap::default();
for lt in xref_doc.line_types.iter() {
let old = lt.name.clone();
if is_sentinel_linetype(&old) {
@ -195,8 +195,8 @@ fn merge_xref_into_block(
//
// Tracks (xref-doc BR handle → host BR handle) so entities owned by
// a nested xref block can be routed to the right host block_record.
let mut br_handle_map: HashMap<Handle, Handle> = HashMap::new();
let mut block_name_map: HashMap<String, String> = HashMap::new();
let mut br_handle_map: HashMap<Handle, Handle> = HashMap::default();
let mut block_name_map: HashMap<String, String> = HashMap::default();
for br in xref_doc.block_records.iter() {
// Skip layout block records (*Model_Space, *Paper_Space, *Paper_Space0…)
// and any further-nested xrefs (we don't recurse into xref-of-xref).