reduce Difficulty struct size

This commit is contained in:
MaxOhn
2024-03-03 10:21:26 +01:00
parent 733066afd7
commit 38e072a1dc
2 changed files with 29 additions and 21 deletions
+4 -5
View File
@@ -35,7 +35,7 @@ impl<M> ConvertedDifficulty<M> {
}
/// Cast from generic mode `M` to `N`.
pub fn cast<N: IGameMode>(self) -> ConvertedDifficulty<N> {
pub const fn cast<N: IGameMode>(self) -> ConvertedDifficulty<N> {
ConvertedDifficulty {
inner: self.inner,
_mode: PhantomData,
@@ -108,12 +108,11 @@ impl<M> AsRef<Difficulty> for ConvertedDifficulty<M> {
}
}
impl<M> Copy for ConvertedDifficulty<M> {}
impl<M> Clone for ConvertedDifficulty<M> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
_mode: PhantomData,
}
*self
}
}
+25 -16
View File
@@ -1,4 +1,4 @@
use std::borrow::Cow;
use std::{borrow::Cow, num::NonZeroU32};
use rosu_map::section::general::GameMode;
@@ -23,12 +23,20 @@ pub mod skills;
use crate::{model::mode::IGameMode, util::mods::Mods};
/// Difficulty calculator on maps of any mode.
#[derive(Clone, Debug, Default, PartialEq)]
#[derive(Copy, Clone, Debug, Default, PartialEq)]
#[must_use]
pub struct Difficulty {
mods: u32,
passed_objects: Option<u32>,
clock_rate: Option<f64>,
/// Clock rate will be clamped internally between 0.01 and 100.0.
///
/// Since its minimum value is 0.01, its bits are never zero.
/// Additionally, values between 0.01 and 100 are represented sufficiently
/// precise with 32 bits.
///
/// This allows for an optimization to reduce the struct size by storing its
/// bits as a [`NonZeroU32`].
clock_rate: Option<NonZeroU32>,
}
impl Difficulty {
@@ -41,17 +49,9 @@ impl Difficulty {
}
}
/// Use this [`&Difficulty`] as a calculator for a specific [`IGameMode`].
///
/// [`&Difficulty`]: Difficulty
pub const fn with_mode<M: IGameMode>(&self) -> ConvertedDifficulty<M> {
let this = Self {
mods: self.mods,
passed_objects: self.passed_objects,
clock_rate: self.clock_rate,
};
ConvertedDifficulty::from_difficulty(this)
/// Use this [`Difficulty`] as a calculator for a specific [`IGameMode`].
pub const fn with_mode<M: IGameMode>(self) -> ConvertedDifficulty<M> {
ConvertedDifficulty::from_difficulty(self)
}
/// Specify mods through their bit values.
@@ -74,8 +74,14 @@ impl Difficulty {
/// If none is specified, it will take the clock rate based on the mods
/// i.e. 1.5 for DT, 0.75 for HT and 1.0 otherwise.
pub fn clock_rate(self, clock_rate: f64) -> Self {
let clock_rate = (clock_rate as f32).clamp(0.01, 100.0).to_bits();
// SAFETY: The minimum value is 0.01 so its bits can never be fully
// zero.
let non_zero = unsafe { NonZeroU32::new_unchecked(clock_rate) };
Self {
clock_rate: Some(clock_rate.clamp(0.01, 100.0)),
clock_rate: Some(non_zero),
..self
}
}
@@ -130,7 +136,10 @@ impl Difficulty {
}
pub(crate) fn get_clock_rate(&self) -> f64 {
self.clock_rate.unwrap_or_else(|| self.mods.clock_rate())
self.clock_rate
.map(NonZeroU32::get)
.map(u64::from)
.map_or_else(|| self.mods.clock_rate(), f64::from_bits)
}
pub(crate) fn get_passed_objects(&self) -> usize {