avoid segment allocations while parsing

This commit is contained in:
MaxOhn
2021-11-06 13:12:47 +01:00
parent 4a1d128ad6
commit 94d743d3e7
5 changed files with 49 additions and 52 deletions
+8 -6
View File
@@ -70,11 +70,12 @@ pub fn stars(
HitObjectKind::Slider { HitObjectKind::Slider {
pixel_len, pixel_len,
repeats, repeats,
curve_points, control_points,
} => { } => {
// HR business // HR business
last_pos.replace( last_pos.replace(
h.pos.x + curve_points[curve_points.len() - 1].pos.x - curve_points[0].pos.x, h.pos.x + control_points[control_points.len() - 1].pos.x
- control_points[0].pos.x, // TODO: Remove subtract
); );
*last_time = h.start_time; *last_time = h.start_time;
@@ -93,7 +94,7 @@ pub fn stars(
/ 100.0; / 100.0;
// Build the curve w.r.t. the curve points // Build the curve w.r.t. the curve points
let curve = Curve::new(curve_points, *pixel_len, &mut curve_buf); let curve = Curve::new(control_points, *pixel_len, &mut curve_buf);
let mut current_distance = tick_distance; let mut current_distance = tick_distance;
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32)); let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
@@ -304,11 +305,12 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
HitObjectKind::Slider { HitObjectKind::Slider {
pixel_len, pixel_len,
repeats, repeats,
curve_points, control_points,
} => { } => {
// HR business // HR business
last_pos.replace( last_pos.replace(
h.pos.x + curve_points[curve_points.len() - 1].pos.x - curve_points[0].pos.x, h.pos.x + control_points[control_points.len() - 1].pos.x
- control_points[0].pos.x, // TODO: Remove subtract
); );
*last_time = h.start_time; *last_time = h.start_time;
@@ -327,7 +329,7 @@ pub fn strains(map: &Beatmap, mods: impl Mods) -> Strains {
/ 100.0; / 100.0;
// Build the curve w.r.t. the curve points // Build the curve w.r.t. the curve points
let curve = Curve::new(curve_points, *pixel_len, &mut curve_buf); let curve = Curve::new(control_points, *pixel_len, &mut curve_buf);
let mut current_distance = tick_distance; let mut current_distance = tick_distance;
let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32)); let time_add = duration * (tick_distance / (*pixel_len * *repeats as f32));
+13 -13
View File
@@ -357,14 +357,14 @@ fn custom_osu() {
let accum = start.elapsed(); let accum = start.elapsed();
// * Tiny benchmark for map parsing // * Tiny benchmark for map parsing
// let mut accum = accum; let mut accum = accum;
// for _ in 0..iters { for _ in 0..iters {
// let file = File::open(path).unwrap(); let file = File::open(path).unwrap();
// let start = Instant::now(); let start = Instant::now();
// let _map = Beatmap::parse(file).unwrap(); let _map = Beatmap::parse(file).unwrap();
// accum += start.elapsed(); accum += start.elapsed();
// } }
println!("Parsing average: {:?}", accum / iters); println!("Parsing average: {:?}", accum / iters);
@@ -375,13 +375,13 @@ fn custom_osu() {
let accum = start.elapsed(); let accum = start.elapsed();
// * Tiny benchmark for pp calculation // * Tiny benchmark for pp calculation
let mut accum = accum; // let mut accum = accum;
for _ in 0..iters { // for _ in 0..iters {
let start = Instant::now(); // let start = Instant::now();
let _result = crate::OsuPP::new(&map).mods(0).calculate(); // let _result = crate::OsuPP::new(&map).mods(0).calculate();
accum += start.elapsed(); // accum += start.elapsed();
} // }
println!("{:#?}", result); println!("{:#?}", result);
println!("Calculation average: {:?}", accum / iters); println!("Calculation average: {:?}", accum / iters);
+2 -2
View File
@@ -48,7 +48,7 @@ impl OsuObject {
HitObjectKind::Slider { HitObjectKind::Slider {
pixel_len, pixel_len,
repeats, repeats,
curve_points, control_points,
} => { } => {
// Key values which are computed here // Key values which are computed here
let mut lazy_end_pos = h.pos; let mut lazy_end_pos = h.pos;
@@ -68,7 +68,7 @@ impl OsuObject {
} }
// Build the curve w.r.t. the curve points // Build the curve w.r.t. the curve points
let curve = Curve::new(curve_points, *pixel_len, slider_buf); let curve = Curve::new(control_points, *pixel_len, slider_buf);
let velocity = let velocity =
(BASE_SCORING_DISTANCE * map.slider_mult * slider_state.slider_velocity) (BASE_SCORING_DISTANCE * map.slider_mult * slider_state.slider_velocity)
+1 -1
View File
@@ -61,7 +61,7 @@ pub enum HitObjectKind {
Slider { Slider {
pixel_len: f32, pixel_len: f32,
repeats: usize, repeats: usize,
curve_points: Vec<PathControlPoint>, control_points: Vec<PathControlPoint>,
}, },
#[cfg(not(any( #[cfg(not(any(
feature = "fruits", feature = "fruits",
+25 -30
View File
@@ -776,7 +776,6 @@ impl Beatmap {
let mut point_split_length = 0; let mut point_split_length = 0;
let mut point_split_capacity = 0; let mut point_split_capacity = 0;
let mut segments = Vec::new();
let mut vertices = Vec::new(); let mut vertices = Vec::new();
while read_line!(reader, buf)? != 0 { while read_line!(reader, buf)? != 0 {
@@ -822,11 +821,9 @@ impl Beatmap {
all(feature = "osu", not(feature = "no_sliders_no_leniency")) all(feature = "osu", not(feature = "no_sliders_no_leniency"))
))] ))]
{ {
let mut curve_points = Vec::with_capacity(4); let mut control_points = Vec::new();
curve_points.push(pos);
// TODO: Rename let control_point_iter = split.next().next_field("control points")?.split('|');
let curve_point_iter = split.next().next_field("curve points")?.split('|');
let mut repeats: usize = split.next().next_field("repeats")?.parse()?; let mut repeats: usize = split.next().next_field("repeats")?.parse()?;
if repeats > 9000 { if repeats > 9000 {
@@ -851,7 +848,7 @@ impl Beatmap {
}; };
point_split.clear(); point_split.clear();
point_split.extend(curve_point_iter); point_split.extend(control_point_iter);
#[allow(clippy::blocks_in_if_conditions)] #[allow(clippy::blocks_in_if_conditions)]
while { while {
@@ -871,7 +868,14 @@ impl Beatmap {
let end_point = point_split.get(end_idx + 1).copied(); let end_point = point_split.get(end_idx + 1).copied();
let slice = &point_split[start_idx..end_idx]; let slice = &point_split[start_idx..end_idx];
convert_points(slice, end_point, first, pos, &mut segments, &mut vertices)?; convert_points(
slice,
end_point,
first,
pos,
&mut control_points,
&mut vertices,
)?;
start_idx = end_idx; start_idx = end_idx;
first = false; first = false;
@@ -879,7 +883,14 @@ impl Beatmap {
if end_idx > start_idx { if end_idx > start_idx {
let slice = &point_split[start_idx..end_idx]; let slice = &point_split[start_idx..end_idx];
convert_points(slice, None, first, pos, &mut segments, &mut vertices)?; convert_points(
slice,
None,
first,
pos,
&mut control_points,
&mut vertices,
)?;
} }
point_split_ptr = point_split.as_mut_ptr() as *const u8; point_split_ptr = point_split.as_mut_ptr() as *const u8;
@@ -887,10 +898,7 @@ impl Beatmap {
point_split_capacity = point_split.capacity(); point_split_capacity = point_split.capacity();
mem::forget(point_split); mem::forget(point_split);
// Drains `segments` so it doesn't have to be cleared if control_points.is_empty() {
let curve_points = merge_points_lists(&mut segments);
if curve_points.is_empty() {
HitObjectKind::Circle HitObjectKind::Circle
} else { } else {
let pixel_len = split let pixel_len = split
@@ -903,7 +911,7 @@ impl Beatmap {
HitObjectKind::Slider { HitObjectKind::Slider {
repeats, repeats,
pixel_len, pixel_len,
curve_points, control_points,
} }
} }
} }
@@ -940,7 +948,7 @@ impl Beatmap {
pos, pos,
start_time: time, start_time: time,
kind, kind,
sound, // TODO: omit if not taiko? sound,
}); });
prev_time = time; prev_time = time;
@@ -978,7 +986,7 @@ fn convert_points(
end_point: Option<&str>, end_point: Option<&str>,
first: bool, first: bool,
offset: Pos2, offset: Pos2,
segments: &mut Vec<Vec<PathControlPoint>>, curve_points: &mut Vec<PathControlPoint>,
vertices: &mut Vec<PathControlPoint>, vertices: &mut Vec<PathControlPoint>,
) -> Result<(), ParseError> { ) -> Result<(), ParseError> {
let mut path_kind = PathType::from_str(points[0]); let mut path_kind = PathType::from_str(points[0]);
@@ -1049,16 +1057,14 @@ fn convert_points(
// * Force a type on the last point, and return // * Force a type on the last point, and return
// * the current control point set as a segment. // * the current control point set as a segment.
vertices[end_idx - 1].kind = Some(path_kind); vertices[end_idx - 1].kind = Some(path_kind);
// TODO: Vec::split_off? curve_points.extend(&vertices[start_idx..end_idx]);
segments.push(vertices[start_idx..end_idx].to_owned());
// * Skip the current control point - as it's the same as the one that's just been returned. // * Skip the current control point - as it's the same as the one that's just been returned.
start_idx = end_idx + 1; start_idx = end_idx + 1;
} }
if end_idx > start_idx { if end_idx > start_idx {
// TODO: Vec::split_off? curve_points.extend(&vertices[start_idx..end_idx]);
segments.push(vertices[start_idx..end_idx].to_owned());
} }
Ok(()) Ok(())
@@ -1073,17 +1079,6 @@ fn read_point(value: &str, start_pos: Pos2) -> Result<PathControlPoint, ParseErr
} }
} }
fn merge_points_lists(
control_point_list: &mut Vec<Vec<PathControlPoint>>,
) -> Vec<PathControlPoint> {
let total_count = control_point_list.iter().map(Vec::len).sum();
let mut merged_list = Vec::with_capacity(total_count);
let iter = control_point_list.drain(..).map(Vec::into_iter).flatten();
merged_list.extend(iter);
merged_list
}
#[cfg(feature = "async_tokio")] #[cfg(feature = "async_tokio")]
impl Beatmap { impl Beatmap {
parse!(async BufReader<AsyncRead>); parse!(async BufReader<AsyncRead>);