taiko: micro optimizations

This commit is contained in:
MaxOhn
2021-04-29 01:33:08 +02:00
parent 2c913d5f3b
commit 9f984ac4e2
7 changed files with 103 additions and 51 deletions
+11 -2
View File
@@ -4,38 +4,47 @@ use std::cmp::Ordering;
static COMMON_RHYTHMS: [HitObjectRhythm; 9] = [
HitObjectRhythm {
id: 0,
ratio: 1.0,
difficulty: 0.0,
},
HitObjectRhythm {
id: 1,
ratio: 2.0 / 1.0,
difficulty: 0.3,
},
HitObjectRhythm {
id: 2,
ratio: 1.0 / 2.0,
difficulty: 0.5,
},
HitObjectRhythm {
id: 3,
ratio: 3.0 / 1.0,
difficulty: 0.3,
},
HitObjectRhythm {
id: 4,
ratio: 1.0 / 3.0,
difficulty: 0.35,
},
HitObjectRhythm {
id: 5,
ratio: 3.0 / 2.0,
difficulty: 0.6,
},
HitObjectRhythm {
id: 6,
ratio: 2.0 / 3.0,
difficulty: 0.4,
},
HitObjectRhythm {
id: 7,
ratio: 5.0 / 4.0,
difficulty: 0.5,
},
HitObjectRhythm {
id: 8,
ratio: 4.0 / 5.0,
difficulty: 0.7,
},
@@ -43,6 +52,7 @@ static COMMON_RHYTHMS: [HitObjectRhythm; 9] = [
#[derive(Copy, Clone, Debug)]
pub(crate) struct HitObjectRhythm {
id: u8,
ratio: f32,
pub(crate) difficulty: f32,
}
@@ -50,8 +60,7 @@ pub(crate) struct HitObjectRhythm {
impl PartialEq for HitObjectRhythm {
#[inline]
fn eq(&self, other: &Self) -> bool {
(self.ratio - other.ratio).abs() <= f32::EPSILON
&& (self.difficulty - other.difficulty).abs() <= f32::EPSILON
self.id == other.id
}
}
+44 -14
View File
@@ -1,5 +1,7 @@
use std::cmp::Ordering;
use std::iter::{Cycle, Skip, Take};
use std::ops::Index;
use std::slice::Iter;
pub(crate) struct LimitedQueue<T> {
queue: Vec<T>,
@@ -8,7 +10,6 @@ pub(crate) struct LimitedQueue<T> {
}
impl<T> LimitedQueue<T> {
/// Panics if `capacity` is zero.
#[inline]
pub(crate) fn new(capacity: usize) -> Self {
Self {
@@ -25,7 +26,7 @@ impl<T> LimitedQueue<T> {
if self.queue.len() == capacity {
self.start = (self.start + 1) % capacity;
self.queue[self.end as usize] = elem;
self.queue[self.end] = elem;
} else {
self.queue.push(elem);
}
@@ -38,7 +39,7 @@ impl<T> LimitedQueue<T> {
#[inline]
pub(crate) fn last(&self) -> Option<&T> {
self.queue.get(self.end as usize)
self.queue.get(self.end)
}
#[inline]
@@ -52,21 +53,30 @@ impl<T> LimitedQueue<T> {
pub(crate) fn full(&self) -> bool {
self.queue.len() == self.queue.capacity()
}
#[inline]
pub(crate) fn iter(&self) -> LimitedQueueIter<T> {
let iter = self
.queue
.iter()
.cycle()
.skip(self.start)
.take(self.queue.len());
LimitedQueueIter { iter }
}
}
impl<T: PartialOrd> LimitedQueue<T> {
pub(crate) fn min(&self) -> Option<&T> {
let mut iter = self.queue.iter();
let first = iter.next()?;
let min = iter.fold(first, |min, next| match min.partial_cmp(next) {
Some(Ordering::Less) => min,
Some(Ordering::Equal) => min,
Some(Ordering::Greater) => next,
None => min,
});
Some(min)
self.queue
.iter()
.reduce(|min, next| match min.partial_cmp(next) {
Some(Ordering::Less) => min,
Some(Ordering::Equal) => min,
Some(Ordering::Greater) => next,
None => min,
})
}
}
@@ -78,3 +88,23 @@ impl<T> Index<usize> for LimitedQueue<T> {
&self.queue[(self.start + idx) % self.queue.capacity()]
}
}
pub(crate) struct LimitedQueueIter<'a, T> {
iter: Take<Skip<Cycle<Iter<'a, T>>>>,
}
impl<'a, T> Iterator for LimitedQueueIter<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
impl<'a, T> ExactSizeIterator for LimitedQueueIter<'a, T> {}
+12 -8
View File
@@ -1,5 +1,7 @@
use super::{DifficultyObject, HitObjectRhythm, LimitedQueue, Rim};
use std::ops::Index;
const RHYTHM_STRAIN_DECAY: f32 = 0.96;
const MOST_RECENT_PATTERNS_TO_COMPARE: usize = 2;
@@ -102,9 +104,10 @@ impl SkillKind {
for start in iter {
let different_pattern = (0..MOST_RECENT_PATTERNS_TO_COMPARE).any(|i| {
mono_history[start + i]
!= mono_history
[mono_history.len() + i - MOST_RECENT_PATTERNS_TO_COMPARE]
let to_compare =
mono_history.len() + i - MOST_RECENT_PATTERNS_TO_COMPARE;
mono_history.index(start + i) != mono_history.index(to_compare)
});
if different_pattern {
@@ -168,17 +171,18 @@ impl SkillKind {
for start in iter {
let different_pattern = (0..most_recent_patterns_to_compare).any(|i| {
rhythm_history[start + i].1
!= rhythm_history
[rhythm_history.len() + i - most_recent_patterns_to_compare]
.1
let to_compare =
rhythm_history.len() + i - most_recent_patterns_to_compare;
rhythm_history.index(start + i).1 != rhythm_history.index(to_compare).1
});
if different_pattern {
continue;
}
reps_penalty *= repetition_penalty(current.idx - rhythm_history[start].0);
reps_penalty *=
repetition_penalty(current.idx - rhythm_history.index(start).0);
break;
}
+7 -8
View File
@@ -1,5 +1,4 @@
use super::{LimitedQueue, Rim};
use crate::{parse::HitObject, Beatmap};
const ROLL_MIN_REPETITIONS: usize = 12;
@@ -12,7 +11,6 @@ pub(crate) trait StaminaCheeseDetector {
}
impl StaminaCheeseDetector for Beatmap {
// TODO: Optimize
fn find_cheese(&self) -> Vec<bool> {
let mut cheese = vec![false; self.hit_objects.len()];
@@ -33,8 +31,8 @@ impl StaminaCheeseDetector for Beatmap {
let mut index_before_last_repeat = -1;
let mut last_mark_end = 0;
for i in 0..self.hit_objects.len() {
history.push(&self.hit_objects[i]);
for (i, h) in self.hit_objects.iter().enumerate() {
history.push(h);
if !history.full() {
continue;
@@ -44,6 +42,7 @@ impl StaminaCheeseDetector for Beatmap {
if !contains {
index_before_last_repeat = (i + 1 - history.len()) as isize;
continue;
}
@@ -63,8 +62,8 @@ impl StaminaCheeseDetector for Beatmap {
let mut tl_len = -2;
let mut last_mark_end = 0;
for i in (parity..self.hit_objects.len()).step_by(2) {
if self.hit_objects[i].is_rim() == is_rin {
for (i, h) in self.hit_objects.iter().enumerate().skip(parity).step_by(2) {
if h.is_rim() == is_rin {
tl_len += 2;
} else {
tl_len = -2;
@@ -96,8 +95,8 @@ fn mark_as_cheese(start: usize, end: usize, cheese: &mut [bool]) {
#[inline]
fn contains_pattern_repeat(history: &LimitedQueue<&HitObject>, pattern_len: usize) -> bool {
for j in 0..pattern_len {
if history[j].is_rim() != history[j + pattern_len].is_rim() {
for (&curr, &to_compare) in history.iter().zip(history.iter().skip(pattern_len)) {
if curr.is_rim() != to_compare.is_rim() {
return false;
}
}