Arena allocate vertices

This reduces the instruction count by 4% on larger files, such as
slow_before/after.rs.

Co-authored-by: mgt <mgt@oi-wiki.org>
pull/290/head
Wilfred Hughes 2022-05-21 22:12:43 +07:00
parent f7aa78bd2b
commit 1646d456f4
2 changed files with 37 additions and 34 deletions

@ -11,20 +11,22 @@ use crate::{
use itertools::Itertools;
use radix_heap::RadixHeapMap;
use rustc_hash::FxHashMap;
use typed_arena::Arena;
type PredecessorInfo<'a> = (u64, Rc<Vertex<'a>>, Edge);
type PredecessorInfo<'a, 'b> = (u64, &'b Vertex<'a>, Edge);
fn shortest_path(start: Vertex) -> Vec<(Edge, Rc<Vertex>)> {
fn shortest_path(start: Vertex) -> Vec<(Edge, Vertex)> {
// We want to visit nodes with the shortest distance first, but
// RadixHeapMap is a max-heap. Ensure nodes are wrapped with
// Reverse to flip comparisons.
let mut heap: RadixHeapMap<Reverse<_>, Rc<Vertex>> = RadixHeapMap::new();
let mut heap: RadixHeapMap<Reverse<_>, &Vertex> = RadixHeapMap::new();
heap.push(Reverse(0), Rc::new(start));
let vertex_arena: Arena<Vertex> = Arena::new();
heap.push(Reverse(0), vertex_arena.alloc(start));
// TODO: this grows very big. Consider using IDA* to reduce memory
// usage.
let mut predecessors: FxHashMap<Rc<Vertex>, PredecessorInfo> = FxHashMap::default();
let mut predecessors: FxHashMap<&Vertex, PredecessorInfo> = FxHashMap::default();
let mut neighbour_buf = [
None, None, None, None, None, None, None, None, None, None, None, None,
@ -36,7 +38,7 @@ fn shortest_path(start: Vertex) -> Vec<(Edge, Rc<Vertex>)> {
break current;
}
neighbours(&current, &mut neighbour_buf);
neighbours(current, &mut neighbour_buf, &vertex_arena);
for neighbour in &mut neighbour_buf {
if let Some((edge, next)) = neighbour.take() {
let distance_to_next = distance + edge.cost();
@ -46,10 +48,7 @@ fn shortest_path(start: Vertex) -> Vec<(Edge, Rc<Vertex>)> {
};
if found_shorter_route {
let next = Rc::new(next);
predecessors
.insert(next.clone(), (distance_to_next, current.clone(), edge));
predecessors.insert(next, (distance_to_next, current, edge));
heap.push(Reverse(distance_to_next), next);
}
@ -69,7 +68,7 @@ fn shortest_path(start: Vertex) -> Vec<(Edge, Rc<Vertex>)> {
);
let mut current = end;
let mut route: Vec<(Edge, Rc<Vertex>)> = vec![];
let mut route: Vec<(Edge, Vertex)> = vec![];
let mut cost = 0;
while let Some((_, node, edge)) = predecessors.remove(&current) {
route.push((edge, node.clone()));

@ -5,9 +5,9 @@ use std::{
cmp::min,
fmt,
hash::{Hash, Hasher},
rc::Rc,
};
use strsim::normalized_levenshtein;
use typed_arena::Arena;
use crate::{
changes::{insert_deep_unchanged, ChangeKind, ChangeMap},
@ -332,7 +332,11 @@ impl Edge {
}
/// Calculate all the neighbours from `v` and write them to `buf`.
pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
pub fn neighbours<'a, 'b>(
v: &Vertex<'a>,
buf: &mut [Option<(Edge, &'b Vertex<'a>)>],
alloc: &'b Arena<Vertex<'a>>,
) {
for item in &mut *buf {
*item = None;
}
@ -347,14 +351,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
// Continue from sibling of parent.
buf[i] = Some((
ExitDelimiterBoth,
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_parent.next_sibling(),
rhs_syntax: rhs_parent.next_sibling(),
can_pop_either: can_pop_either_parent(&parents_next),
parents: parents_next,
lhs_parent_id: lhs_parent.parent().map(Syntax::id),
rhs_parent_id: rhs_parent.parent().map(Syntax::id),
},
}),
));
i += 1;
}
@ -367,14 +371,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
// Continue from sibling of parent.
buf[i] = Some((
ExitDelimiterLHS,
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_parent.next_sibling(),
rhs_syntax: v.rhs_syntax,
can_pop_either: can_pop_either_parent(&parents_next),
parents: parents_next,
lhs_parent_id: lhs_parent.parent().map(Syntax::id),
rhs_parent_id: v.rhs_parent_id,
},
}),
));
i += 1;
}
@ -387,14 +391,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
// Continue from sibling of parent.
buf[i] = Some((
ExitDelimiterRHS,
Vertex {
alloc.alloc(Vertex {
lhs_syntax: v.lhs_syntax,
rhs_syntax: rhs_parent.next_sibling(),
can_pop_either: can_pop_either_parent(&parents_next),
parents: parents_next,
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: rhs_parent.parent().map(Syntax::id),
},
}),
));
i += 1;
}
@ -409,14 +413,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
// Both nodes are equal, the happy case.
buf[i] = Some((
UnchangedNode { depth_difference },
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_syntax.next_sibling(),
rhs_syntax: rhs_syntax.next_sibling(),
parents: v.parents.clone(),
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: v.rhs_parent_id,
can_pop_either: v.can_pop_either,
},
}),
));
i += 1;
}
@ -450,14 +454,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
buf[i] = Some((
EnterUnchangedDelimiter { depth_difference },
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_next,
rhs_syntax: rhs_next,
parents: parents_next,
lhs_parent_id: Some(lhs_syntax.id()),
rhs_parent_id: Some(rhs_syntax.id()),
can_pop_either: false,
},
}),
));
i += 1;
}
@ -483,14 +487,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
(normalized_levenshtein(lhs_content, rhs_content) * 100.0).round() as u8;
buf[i] = Some((
ReplacedComment { levenshtein_pct },
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_syntax.next_sibling(),
rhs_syntax: rhs_syntax.next_sibling(),
parents: v.parents.clone(),
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: v.rhs_parent_id,
can_pop_either: v.can_pop_either,
},
}),
));
i += 1;
}
@ -507,14 +511,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
// node rather than a sibling?
contiguous: lhs_syntax.prev_is_contiguous(),
},
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_syntax.next_sibling(),
rhs_syntax: v.rhs_syntax,
parents: v.parents.clone(),
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: v.rhs_parent_id,
can_pop_either: v.can_pop_either,
},
}),
));
i += 1;
}
@ -528,14 +532,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
EnterNovelDelimiterLHS {
contiguous: lhs_syntax.prev_is_contiguous(),
},
Vertex {
alloc.alloc(Vertex {
lhs_syntax: lhs_next,
rhs_syntax: v.rhs_syntax,
parents: parents_next,
lhs_parent_id: Some(lhs_syntax.id()),
rhs_parent_id: v.rhs_parent_id,
can_pop_either: true,
},
}),
));
i += 1;
}
@ -550,14 +554,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
NovelAtomRHS {
contiguous: rhs_syntax.prev_is_contiguous(),
},
Vertex {
alloc.alloc(Vertex {
lhs_syntax: v.lhs_syntax,
rhs_syntax: rhs_syntax.next_sibling(),
parents: v.parents.clone(),
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: v.rhs_parent_id,
can_pop_either: v.can_pop_either,
},
}),
));
i += 1;
}
@ -571,14 +575,14 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
EnterNovelDelimiterRHS {
contiguous: rhs_syntax.prev_is_contiguous(),
},
Vertex {
alloc.alloc(Vertex {
lhs_syntax: v.lhs_syntax,
rhs_syntax: rhs_next,
parents: parents_next,
lhs_parent_id: v.lhs_parent_id,
rhs_parent_id: Some(rhs_syntax.id()),
can_pop_either: true,
},
}),
));
i += 1;
}
@ -590,7 +594,7 @@ pub fn neighbours<'a>(v: &Vertex<'a>, buf: &mut [Option<(Edge, Vertex<'a>)>]) {
);
}
pub fn populate_change_map<'a>(route: &[(Edge, Rc<Vertex<'a>>)], change_map: &mut ChangeMap<'a>) {
pub fn populate_change_map<'a>(route: &[(Edge, Vertex<'a>)], change_map: &mut ChangeMap<'a>) {
for (e, v) in route {
match e {
ExitDelimiterBoth | ExitDelimiterLHS | ExitDelimiterRHS => {