rosu_pp/util/
interval_grouping.rs1use crate::util::float_ext::FloatExt;
2
3use super::sync::{RefCount, Weak};
4
5pub trait HasInterval {
6 fn interval(&self) -> f64;
7}
8
9pub const fn group_by_interval<T: HasInterval>(
10 objects: &[RefCount<T>],
11) -> GroupedByIntervalIter<'_, T> {
12 GroupedByIntervalIter::new(objects)
13}
14
15pub struct GroupedByIntervalIter<'a, T> {
16 objects: &'a [RefCount<T>],
17 i: usize,
18}
19
20impl<'a, T> GroupedByIntervalIter<'a, T> {
21 const fn new(objects: &'a [RefCount<T>]) -> Self {
22 Self { objects, i: 0 }
23 }
24}
25
26impl<T: HasInterval> Iterator for GroupedByIntervalIter<'_, T> {
27 type Item = Vec<Weak<T>>;
28
29 fn next(&mut self) -> Option<Self::Item> {
30 if self.i < self.objects.len() {
31 Some(self.create_next_group())
32 } else {
33 None
34 }
35 }
36
37 fn size_hint(&self) -> (usize, Option<usize>) {
38 let min = usize::from(!self.objects.is_empty());
39 let max = self.objects.len() - self.i;
40
41 (min, Some(max))
42 }
43}
44
45impl<T: HasInterval> GroupedByIntervalIter<'_, T> {
46 fn create_next_group(&mut self) -> Vec<Weak<T>> {
47 const MARGIN_OF_ERROR: f64 = 5.0;
48
49 let &mut Self { objects, ref mut i } = self;
50
51 let mut grouped_objects = vec![objects[*i].downgrade()];
54
55 *i += 1;
56
57 while *i < objects.len() - 1 {
58 if !(objects[*i]
59 .get()
60 .interval()
61 .almost_eq(objects[*i + 1].get().interval(), MARGIN_OF_ERROR))
62 {
63 if objects[*i + 1].get().interval() > objects[*i].get().interval() + MARGIN_OF_ERROR
66 {
67 grouped_objects.push(objects[*i].downgrade());
68 *i += 1;
69 }
70
71 return grouped_objects;
72 }
73
74 grouped_objects.push(objects[*i].downgrade());
76
77 *i += 1;
78 }
79
80 if objects.len() > 2
83 && *i < objects.len()
84 && objects[objects.len() - 1]
85 .get()
86 .interval()
87 .almost_eq(objects[objects.len() - 2].get().interval(), MARGIN_OF_ERROR)
88 {
89 grouped_objects.push(objects[*i].downgrade());
90 *i += 1;
91 }
92
93 grouped_objects
94 }
95}