diff --git a/egui/src/animation_manager.rs b/egui/src/animation_manager.rs index 97e1bbfb..8a6795f5 100644 --- a/egui/src/animation_manager.rs +++ b/egui/src/animation_manager.rs @@ -1,10 +1,8 @@ -use epaint::ahash::AHashMap; - -use crate::{emath::remap_clamp, Id, InputState}; +use crate::{emath::remap_clamp, Id, IdMap, InputState}; #[derive(Clone, Default)] pub(crate) struct AnimationManager { - bools: AHashMap, + bools: IdMap, } #[derive(Clone, Debug)] diff --git a/egui/src/frame_state.rs b/egui/src/frame_state.rs index dc08674a..843e32c5 100644 --- a/egui/src/frame_state.rs +++ b/egui/src/frame_state.rs @@ -1,5 +1,4 @@ use crate::*; -use epaint::ahash; /// State that is collected during a frame and then cleared. /// Short-term (single frame) memory. @@ -7,7 +6,7 @@ use epaint::ahash; pub(crate) struct FrameState { /// All `Id`s that were used this frame. /// Used to debug `Id` clashes of widgets. - pub(crate) used_ids: ahash::AHashMap, + pub(crate) used_ids: IdMap, /// Starts off as the screen_rect, shrinks as panels are added. /// The `CentralPanel` does not change this. diff --git a/egui/src/id.rs b/egui/src/id.rs index 407b8101..a5822cc6 100644 --- a/egui/src/id.rs +++ b/egui/src/id.rs @@ -67,3 +67,56 @@ impl std::fmt::Debug for Id { write!(f, "{:X}", self.0) } } + +// ---------------------------------------------------------------------------- + +// Idea taken from the `nohash_hasher` crate. +#[derive(Default)] +pub struct IdHasher(u64); + +impl std::hash::Hasher for IdHasher { + fn write(&mut self, _: &[u8]) { + unreachable!("Invalid use of IdHasher") + } + + fn write_u8(&mut self, _n: u8) { + unreachable!("Invalid use of IdHasher") + } + fn write_u16(&mut self, _n: u16) { + unreachable!("Invalid use of IdHasher") + } + fn write_u32(&mut self, _n: u32) { + unreachable!("Invalid use of IdHasher") + } + fn write_u64(&mut self, n: u64) { + self.0 = n + } + fn write_usize(&mut self, _n: usize) { + unreachable!("Invalid use of IdHasher") + } + + fn write_i8(&mut self, _n: i8) { + unreachable!("Invalid use of IdHasher") + } + fn write_i16(&mut self, _n: i16) { + unreachable!("Invalid use of IdHasher") + } + fn write_i32(&mut self, _n: i32) { + unreachable!("Invalid use of IdHasher") + } + fn write_i64(&mut self, _n: i64) { + unreachable!("Invalid use of IdHasher") + } + fn write_isize(&mut self, _n: isize) { + unreachable!("Invalid use of IdHasher") + } + + fn finish(&self) -> u64 { + self.0 + } +} + +pub type BuilIdHasher = std::hash::BuildHasherDefault; + +/// `IdMap` is a `HashMap` optimized by knowing that `Id` has good entropy, and doesn't need more hashing. +pub type IdMap = std::collections::HashMap; diff --git a/egui/src/layers.rs b/egui/src/layers.rs index a0e44ccc..7c179a2c 100644 --- a/egui/src/layers.rs +++ b/egui/src/layers.rs @@ -2,7 +2,6 @@ //! are sometimes painted behind or in front of other things. use crate::{Id, *}; -use epaint::ahash::AHashMap; use epaint::mutex::Mutex; use epaint::{ClippedShape, Shape}; use std::sync::Arc; @@ -154,7 +153,7 @@ impl PaintList { } #[derive(Clone, Default)] -pub(crate) struct GraphicLayers([AHashMap>>; Order::COUNT]); +pub(crate) struct GraphicLayers([IdMap>>; Order::COUNT]); impl GraphicLayers { pub fn list(&mut self, layer_id: LayerId) -> &Arc> { diff --git a/egui/src/lib.rs b/egui/src/lib.rs index bc08d18c..63d945a4 100644 --- a/egui/src/lib.rs +++ b/egui/src/lib.rs @@ -387,7 +387,7 @@ pub use { output::{self, CursorIcon, Output, WidgetInfo}, }, grid::Grid, - id::Id, + id::{Id, IdMap}, input_state::{InputState, MultiTouchInfo, PointerState}, layers::{LayerId, Order}, layout::*, diff --git a/egui/src/memory.rs b/egui/src/memory.rs index 198a7bc9..a646e631 100644 --- a/egui/src/memory.rs +++ b/egui/src/memory.rs @@ -1,6 +1,6 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; -use crate::{any, area, window, Id, InputState, LayerId, Pos2, Rect, Style}; +use crate::{any, area, window, Id, IdMap, InputState, LayerId, Pos2, Rect, Style}; // ---------------------------------------------------------------------------- @@ -259,7 +259,7 @@ impl Focus { } } - pub(crate) fn end_frame(&mut self, used_ids: &epaint::ahash::AHashMap) { + pub(crate) fn end_frame(&mut self, used_ids: &IdMap) { if let Some(id) = self.id { // Allow calling `request_focus` one frame and not using it until next frame let recently_gained_focus = self.id_previous_frame != Some(id); @@ -310,11 +310,7 @@ impl Memory { } } - pub(crate) fn end_frame( - &mut self, - input: &InputState, - used_ids: &epaint::ahash::AHashMap, - ) { + pub(crate) fn end_frame(&mut self, input: &InputState, used_ids: &IdMap) { self.caches.update(); self.areas.end_frame(); self.interaction.focus.end_frame(used_ids); @@ -465,7 +461,7 @@ impl Memory { #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] pub struct Areas { - areas: HashMap, + areas: IdMap, /// Back-to-front. Top is last. order: Vec, visible_last_frame: HashSet,