1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-29 12:50:04 -04:00

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
14 changed files with 57 additions and 90 deletions

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?

View File

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

View File

@@ -8,7 +8,7 @@ use crate::{
},
TextureAtlas,
};
use emath::NumExt as _;
use emath::{NumExt as _, OrderedFloat};
// ----------------------------------------------------------------------------
@@ -56,7 +56,7 @@ impl std::hash::Hash for FontId {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
let Self { size, family } = self;
crate::f32_hash(state, *size);
emath::OrderedFloat(*size).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`.
///
/// Required in order to paint text.
@@ -591,7 +576,7 @@ pub struct FontsImpl {
definitions: FontDefinitions,
atlas: Arc<Mutex<TextureAtlas>>,
font_impl_cache: FontImplCache,
sized_family: ahash::HashMap<(HashableF32, FontFamily), Font>,
sized_family: ahash::HashMap<(OrderedFloat<f32>, FontFamily), Font>,
}
impl FontsImpl {
@@ -641,7 +626,7 @@ impl FontsImpl {
let FontId { size, family } = font_id;
self.sized_family
.entry((HashableF32(*size), family.clone()))
.entry((OrderedFloat(*size), family.clone()))
.or_insert_with(|| {
let fonts = &self.definitions.families.get(family);
let fonts = fonts

View File

@@ -185,7 +185,7 @@ impl std::hash::Hash for LayoutJob {
text.hash(state);
sections.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);
halign.hash(state);
justify.hash(state);
@@ -214,7 +214,7 @@ impl std::hash::Hash for LayoutSection {
byte_range,
format,
} = self;
crate::f32_hash(state, *leading_space);
OrderedFloat(*leading_space).hash(state);
byte_range.hash(state);
format.hash(state);
}
@@ -293,9 +293,9 @@ impl std::hash::Hash for TextFormat {
valign,
} = self;
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 {
crate::f32_hash(state, line_height);
emath::OrderedFloat(line_height).hash(state);
}
color.hash(state);
background.hash(state);
@@ -375,7 +375,7 @@ impl std::hash::Hash for TextWrapping {
break_anywhere,
overflow_character,
} = self;
crate::f32_hash(state, *max_width);
emath::OrderedFloat(*max_width).hash(state);
max_rows.hash(state);
break_anywhere.hash(state);
overflow_character.hash(state);

View File

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

View File

@@ -1,142 +0,0 @@
//! Total order on floating point types.
//! Can be used for sorting, min/max computation, and other collection algorithms.
use std::cmp::Ordering;
use std::hash::{Hash, Hasher};
/// Wraps a floating-point value to add total order and hash.
/// Possible types for `T` are `f32` and `f64`.
///
/// See also [`FloatOrd`].
#[derive(Clone, Copy)]
pub struct OrderedFloat<T>(T);
impl<T: Float + Copy> OrderedFloat<T> {
#[inline]
pub fn into_inner(self) -> T {
self.0
}
}
impl<T: Float> Eq for OrderedFloat<T> {}
impl<T: Float> PartialEq<Self> for OrderedFloat<T> {
#[inline]
fn eq(&self, other: &Self) -> bool {
// NaNs are considered equal (equivalent) when it comes to ordering
if self.0.is_nan() {
other.0.is_nan()
} else {
self.0 == other.0
}
}
}
impl<T: Float> PartialOrd<Self> for OrderedFloat<T> {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<T: Float> Ord for OrderedFloat<T> {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match self.0.partial_cmp(&other.0) {
Some(ord) => ord,
None => self.0.is_nan().cmp(&other.0.is_nan()),
}
}
}
impl<T: Float> Hash for OrderedFloat<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> From<T> for OrderedFloat<T> {
#[inline]
fn from(val: T) -> Self {
Self(val)
}
}
// ----------------------------------------------------------------------------
/// Extension trait to provide `ord()` method.
///
/// Example with `f64`:
/// ```
/// use epaint::util::FloatOrd;
///
/// let array = [1.0, 2.5, 2.0];
/// let max = array.iter().max_by_key(|val| val.ord());
///
/// assert_eq!(max, Some(&2.5));
/// ```
pub trait FloatOrd {
/// Type to provide total order, useful as key in sorted contexts.
fn ord(self) -> OrderedFloat<Self>
where
Self: Sized;
}
impl FloatOrd for f32 {
#[inline]
fn ord(self) -> OrderedFloat<Self> {
OrderedFloat(self)
}
}
impl FloatOrd for f64 {
#[inline]
fn ord(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
mod private {
use super::*;
pub trait FloatImpl {
fn is_nan(&self) -> bool;
fn hash<H: Hasher>(&self, state: &mut H);
}
impl FloatImpl for f32 {
#[inline]
fn is_nan(&self) -> bool {
Self::is_nan(*self)
}
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
crate::f32_hash(state, *self);
}
}
impl FloatImpl for f64 {
#[inline]
fn is_nan(&self) -> bool {
Self::is_nan(*self)
}
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
crate::f64_hash(state, *self);
}
}
}