Optimization: introduce IdMap

This commit is contained in:
Emil Ernerfeldt 2021-10-09 14:10:38 +02:00
parent 5799758c2b
commit 4dcdd014d6
6 changed files with 63 additions and 18 deletions

View file

@ -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<Id, BoolAnim>,
bools: IdMap<BoolAnim>,
}
#[derive(Clone, Debug)]

View file

@ -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<Id, Rect>,
pub(crate) used_ids: IdMap<Rect>,
/// Starts off as the screen_rect, shrinks as panels are added.
/// The `CentralPanel` does not change this.

View file

@ -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<IdHasher>;
/// `IdMap<V>` is a `HashMap<Id, V>` optimized by knowing that `Id` has good entropy, and doesn't need more hashing.
pub type IdMap<V> = std::collections::HashMap<Id, V, BuilIdHasher>;

View file

@ -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<Id, Arc<Mutex<PaintList>>>; Order::COUNT]);
pub(crate) struct GraphicLayers([IdMap<Arc<Mutex<PaintList>>>; Order::COUNT]);
impl GraphicLayers {
pub fn list(&mut self, layer_id: LayerId) -> &Arc<Mutex<PaintList>> {

View file

@ -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::*,

View file

@ -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<Id, Rect>) {
pub(crate) fn end_frame(&mut self, used_ids: &IdMap<Rect>) {
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<Id, Rect>,
) {
pub(crate) fn end_frame(&mut self, input: &InputState, used_ids: &IdMap<Rect>) {
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<Id, area::State>,
areas: IdMap<area::State>,
/// Back-to-front. Top is last.
order: Vec<LayerId>,
visible_last_frame: HashSet<LayerId>,