Add `emath::OrderedFloat` (moved from `epaint::util::OrderedFloat`) (#4389)

It makes much more sense in `emath`
This commit is contained in:
Emil Ernerfeldt 2024-04-21 20:36:32 +02:00 committed by GitHub
parent 46b241eb94
commit 87b294534e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 57 additions and 90 deletions

1
Cargo.lock generated
View File

@ -1242,6 +1242,7 @@ dependencies = [
"ahash", "ahash",
"backtrace", "backtrace",
"document-features", "document-features",
"emath",
"epaint", "epaint",
"log", "log",
"nohash-hasher", "nohash-hasher",

View File

@ -26,6 +26,7 @@ impl std::ops::IndexMut<usize> for Rgba {
} }
} }
/// Deterministically hash an `f32`, treating all NANs as equal, and ignoring the sign of zero.
#[inline] #[inline]
pub(crate) fn f32_hash<H: std::hash::Hasher>(state: &mut H, f: f32) { pub(crate) fn f32_hash<H: std::hash::Hasher>(state: &mut H, f: f32) {
if f == 0.0 { if f == 0.0 {

View File

@ -81,6 +81,7 @@ unity = ["epaint/unity"]
[dependencies] [dependencies]
emath = { workspace = true, default-features = false }
epaint = { workspace = true, default-features = false } epaint = { workspace = true, default-features = false }
ahash.workspace = true ahash.workspace = true

View File

@ -55,23 +55,21 @@
mod bytes_loader; mod bytes_loader;
mod texture_loader; mod texture_loader;
use std::borrow::Cow; use std::{
use std::fmt::Debug; borrow::Cow,
use std::ops::Deref; fmt::{Debug, Display},
use std::{fmt::Display, sync::Arc}; ops::Deref,
sync::Arc,
};
use ahash::HashMap; use ahash::HashMap;
use epaint::mutex::Mutex; use emath::{Float, OrderedFloat};
use epaint::util::FloatOrd; use epaint::{mutex::Mutex, textures::TextureOptions, ColorImage, TextureHandle, TextureId, Vec2};
use epaint::util::OrderedFloat;
use epaint::TextureHandle;
use epaint::{textures::TextureOptions, ColorImage, TextureId, Vec2};
use crate::Context; use crate::Context;
pub use self::bytes_loader::DefaultBytesLoader; pub use self::{bytes_loader::DefaultBytesLoader, texture_loader::DefaultTextureLoader};
pub use self::texture_loader::DefaultTextureLoader;
/// Represents a failed attempt at loading an image. /// Represents a failed attempt at loading an image.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]

View File

@ -1,12 +1,12 @@
use std::borrow::Cow; use std::borrow::Cow;
use crate::load::TextureLoadResult; use emath::{Float as _, Rot2};
use epaint::RectShape;
use crate::{ use crate::{
load::{Bytes, SizeHint, SizedTexture, TexturePoll}, load::{Bytes, SizeHint, SizedTexture, TextureLoadResult, TexturePoll},
*, *,
}; };
use emath::Rot2;
use epaint::{util::FloatOrd, RectShape};
/// A widget which displays an image. /// A widget which displays an image.
/// ///

View File

@ -3,7 +3,7 @@
use std::ops::RangeInclusive; use std::ops::RangeInclusive;
use epaint::{emath::Rot2, util::FloatOrd, Mesh}; use epaint::{emath::Rot2, Mesh};
use crate::*; use crate::*;

View File

@ -17,7 +17,8 @@ use std::{cmp::Ordering, ops::RangeInclusive, sync::Arc};
use egui::ahash::HashMap; use egui::ahash::HashMap;
use egui::*; use egui::*;
use epaint::{util::FloatOrd, Hsva}; use emath::Float as _;
use epaint::Hsva;
pub use crate::{ pub use crate::{
axis::{Axis, AxisHints, HPlacement, Placement, VPlacement}, axis::{Axis, AxisHints, HPlacement, Placement, VPlacement},

View File

@ -30,6 +30,7 @@ use std::ops::{Add, Div, Mul, RangeInclusive, Sub};
pub mod align; pub mod align;
mod history; mod history;
mod numeric; mod numeric;
mod ordered_float;
mod pos2; mod pos2;
mod range; mod range;
mod rect; mod rect;
@ -40,10 +41,11 @@ mod ts_transform;
mod vec2; mod vec2;
mod vec2b; mod vec2b;
pub use { pub use self::{
align::{Align, Align2}, align::{Align, Align2},
history::History, history::History,
numeric::*, numeric::*,
ordered_float::*,
pos2::*, pos2::*,
range::Rangef, range::Rangef,
rect::*, rect::*,

View File

@ -7,9 +7,12 @@ use std::hash::{Hash, Hasher};
/// Wraps a floating-point value to add total order and hash. /// Wraps a floating-point value to add total order and hash.
/// Possible types for `T` are `f32` and `f64`. /// Possible types for `T` are `f32` and `f64`.
/// ///
/// See also [`FloatOrd`]. /// All NaNs are considered equal to each other.
/// The size of zero is ignored.
///
/// See also [`Float`].
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct OrderedFloat<T>(T); pub struct OrderedFloat<T>(pub T);
impl<T: Float + Copy> OrderedFloat<T> { impl<T: Float + Copy> OrderedFloat<T> {
#[inline] #[inline]
@ -68,44 +71,34 @@ impl<T> From<T> for OrderedFloat<T> {
/// ///
/// Example with `f64`: /// Example with `f64`:
/// ``` /// ```
/// use epaint::util::FloatOrd; /// use emath::Float as _;
/// ///
/// let array = [1.0, 2.5, 2.0]; /// let array = [1.0, 2.5, 2.0];
/// let max = array.iter().max_by_key(|val| val.ord()); /// let max = array.iter().max_by_key(|val| val.ord());
/// ///
/// assert_eq!(max, Some(&2.5)); /// assert_eq!(max, Some(&2.5));
/// ``` /// ```
pub trait FloatOrd { pub trait Float: PartialOrd + PartialEq + private::FloatImpl {
/// Type to provide total order, useful as key in sorted contexts. /// Type to provide total order, useful as key in sorted contexts.
fn ord(self) -> OrderedFloat<Self> fn ord(self) -> OrderedFloat<Self>
where where
Self: Sized; Self: Sized;
} }
impl FloatOrd for f32 { impl Float for f32 {
#[inline] #[inline]
fn ord(self) -> OrderedFloat<Self> { fn ord(self) -> OrderedFloat<Self> {
OrderedFloat(self) OrderedFloat(self)
} }
} }
impl FloatOrd for f64 { impl Float for f64 {
#[inline] #[inline]
fn ord(self) -> OrderedFloat<Self> { fn ord(self) -> OrderedFloat<Self> {
OrderedFloat(self) OrderedFloat(self)
} }
} }
// ----------------------------------------------------------------------------
/// Internal abstraction over floating point types
#[doc(hidden)]
pub trait Float: PartialOrd + PartialEq + private::FloatImpl {}
impl Float for f32 {}
impl Float for f64 {}
// Keep this trait in private module, to avoid exposing its methods as extensions in user code // Keep this trait in private module, to avoid exposing its methods as extensions in user code
mod private { mod private {
use super::*; use super::*;
@ -124,7 +117,13 @@ mod private {
#[inline] #[inline]
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
crate::f32_hash(state, *self); if *self == 0.0 {
state.write_u8(0);
} else if self.is_nan() {
state.write_u8(1);
} else {
self.to_bits().hash(state);
}
} }
} }
@ -136,7 +135,13 @@ mod private {
#[inline] #[inline]
fn hash<H: Hasher>(&self, state: &mut H) { fn hash<H: Hasher>(&self, state: &mut H) {
crate::f64_hash(state, *self); if *self == 0.0 {
state.write_u8(0);
} else if self.is_nan() {
state.write_u8(1);
} else {
self.to_bits().hash(state);
}
} }
} }
} }

View File

@ -152,32 +152,6 @@ macro_rules! epaint_assert {
} }
} }
// ----------------------------------------------------------------------------
#[inline(always)]
pub(crate) fn f32_hash<H: std::hash::Hasher>(state: &mut H, f: f32) {
if f == 0.0 {
state.write_u8(0);
} else if f.is_nan() {
state.write_u8(1);
} else {
use std::hash::Hash;
f.to_bits().hash(state);
}
}
#[inline(always)]
pub(crate) fn f64_hash<H: std::hash::Hasher>(state: &mut H, f: f64) {
if f == 0.0 {
state.write_u8(0);
} else if f.is_nan() {
state.write_u8(1);
} else {
use std::hash::Hash;
f.to_bits().hash(state);
}
}
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// Was epaint compiled with the `rayon` feature? /// Was epaint compiled with the `rayon` feature?

View File

@ -48,7 +48,7 @@ impl std::hash::Hash for Stroke {
#[inline(always)] #[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let Self { width, color } = *self; let Self { width, color } = *self;
crate::f32_hash(state, width); emath::OrderedFloat(width).hash(state);
color.hash(state); color.hash(state);
} }
} }

View File

@ -8,7 +8,7 @@ use crate::{
}, },
TextureAtlas, TextureAtlas,
}; };
use emath::NumExt as _; use emath::{NumExt as _, OrderedFloat};
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -56,7 +56,7 @@ impl std::hash::Hash for FontId {
#[inline(always)] #[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let Self { size, family } = self; let Self { size, family } = self;
crate::f32_hash(state, *size); emath::OrderedFloat(*size).hash(state);
family.hash(state); family.hash(state);
} }
} }
@ -567,21 +567,6 @@ impl FontsAndCache {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#[derive(Clone, Copy, Debug, PartialEq)]
struct HashableF32(f32);
#[allow(clippy::derived_hash_with_manual_eq)]
impl std::hash::Hash for HashableF32 {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
crate::f32_hash(state, self.0);
}
}
impl Eq for HashableF32 {}
// ----------------------------------------------------------------------------
/// The collection of fonts used by `epaint`. /// The collection of fonts used by `epaint`.
/// ///
/// Required in order to paint text. /// Required in order to paint text.
@ -591,7 +576,7 @@ pub struct FontsImpl {
definitions: FontDefinitions, definitions: FontDefinitions,
atlas: Arc<Mutex<TextureAtlas>>, atlas: Arc<Mutex<TextureAtlas>>,
font_impl_cache: FontImplCache, font_impl_cache: FontImplCache,
sized_family: ahash::HashMap<(HashableF32, FontFamily), Font>, sized_family: ahash::HashMap<(OrderedFloat<f32>, FontFamily), Font>,
} }
impl FontsImpl { impl FontsImpl {
@ -641,7 +626,7 @@ impl FontsImpl {
let FontId { size, family } = font_id; let FontId { size, family } = font_id;
self.sized_family self.sized_family
.entry((HashableF32(*size), family.clone())) .entry((OrderedFloat(*size), family.clone()))
.or_insert_with(|| { .or_insert_with(|| {
let fonts = &self.definitions.families.get(family); let fonts = &self.definitions.families.get(family);
let fonts = fonts let fonts = fonts

View File

@ -185,7 +185,7 @@ impl std::hash::Hash for LayoutJob {
text.hash(state); text.hash(state);
sections.hash(state); sections.hash(state);
wrap.hash(state); wrap.hash(state);
crate::f32_hash(state, *first_row_min_height); emath::OrderedFloat(*first_row_min_height).hash(state);
break_on_newline.hash(state); break_on_newline.hash(state);
halign.hash(state); halign.hash(state);
justify.hash(state); justify.hash(state);
@ -214,7 +214,7 @@ impl std::hash::Hash for LayoutSection {
byte_range, byte_range,
format, format,
} = self; } = self;
crate::f32_hash(state, *leading_space); OrderedFloat(*leading_space).hash(state);
byte_range.hash(state); byte_range.hash(state);
format.hash(state); format.hash(state);
} }
@ -293,9 +293,9 @@ impl std::hash::Hash for TextFormat {
valign, valign,
} = self; } = self;
font_id.hash(state); font_id.hash(state);
crate::f32_hash(state, *extra_letter_spacing); emath::OrderedFloat(*extra_letter_spacing).hash(state);
if let Some(line_height) = *line_height { if let Some(line_height) = *line_height {
crate::f32_hash(state, line_height); emath::OrderedFloat(line_height).hash(state);
} }
color.hash(state); color.hash(state);
background.hash(state); background.hash(state);
@ -375,7 +375,7 @@ impl std::hash::Hash for TextWrapping {
break_anywhere, break_anywhere,
overflow_character, overflow_character,
} = self; } = self;
crate::f32_hash(state, *max_width); emath::OrderedFloat(*max_width).hash(state);
max_rows.hash(state); max_rows.hash(state);
break_anywhere.hash(state); break_anywhere.hash(state);
overflow_character.hash(state); overflow_character.hash(state);

View File

@ -1,6 +1,5 @@
mod ordered_float; #[deprecated = "Use emath::OrderedFloat instead"]
pub use emath::OrderedFloat;
pub use ordered_float::*;
/// Hash the given value with a predictable hasher. /// Hash the given value with a predictable hasher.
#[inline] #[inline]