Skip to content

Commit 2b51acb

Browse files
author
Moritz Vetter
committed
redirct: flex partialOrd and itertools to allocate less space during union
1 parent ff59147 commit 2b51acb

File tree

3 files changed

+42
-12
lines changed

3 files changed

+42
-12
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/text_edit/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ rust-version = "1.57"
1010
doctest = false
1111

1212
[dependencies]
13+
itertools = "0.10.0"
1314
text-size = "1.0.0"

crates/text_edit/src/lib.rs

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
//! so `TextEdit` is the ultimate representation of the work done by
55
//! rust-analyzer.
66
7+
use itertools::Itertools;
8+
use std::cmp::Ordering;
79
pub use text_size::{TextRange, TextSize};
810

911
/// `InsertDelete` -- a single "atomic" change to text
@@ -16,6 +18,22 @@ pub struct Indel {
1618
pub delete: TextRange,
1719
}
1820

21+
impl PartialOrd for Indel {
22+
fn partial_cmp(&self, other: &Indel) -> Option<Ordering> {
23+
if self == other {
24+
return Some(Ordering::Equal);
25+
}
26+
let cmp_to_other = self.delete.end() <= other.delete.start();
27+
let cmp_to_self = other.delete.end() <= self.delete.start();
28+
match (cmp_to_other, cmp_to_self) {
29+
(true, true) => Some(Ordering::Equal),
30+
(true, false) => Some(Ordering::Less),
31+
(false, true) => Some(Ordering::Greater),
32+
(false, false) => None,
33+
}
34+
}
35+
}
36+
1937
#[derive(Default, Debug, Clone)]
2038
pub struct TextEdit {
2139
/// Invariant: disjoint and sorted by `delete`.
@@ -109,9 +127,8 @@ impl TextEdit {
109127
}
110128

111129
pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
112-
// FIXME: can be done without allocating intermediate vector
113-
let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
114-
if !check_disjoint_and_sort(&mut all) {
130+
let mut iter_merge = self.iter().merge(other.iter());
131+
if !check_disjoint(&mut iter_merge) {
115132
return Err(other);
116133
}
117134

@@ -185,17 +202,28 @@ impl TextEditBuilder {
185202
}
186203
}
187204

188-
fn assert_disjoint_or_equal(indels: &mut [Indel]) {
205+
fn assert_disjoint_or_equal(indels: &mut Vec<Indel>) {
189206
assert!(check_disjoint_and_sort(indels));
190207
}
191-
// FIXME: Remove the impl Bound here, it shouldn't be needed
192-
fn check_disjoint_and_sort(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
193-
indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
194-
indels.iter().zip(indels.iter().skip(1)).all(|(l, r)| {
195-
let l = l.borrow();
196-
let r = r.borrow();
197-
l.delete.end() <= r.delete.start() || l == r
198-
})
208+
209+
fn check_disjoint_and_sort(indels: &mut Vec<Indel>) -> bool {
210+
indels.sort_by_key(|indel| (indel.delete.start(), indel.delete.end()));
211+
return check_disjoint(&mut indels.iter());
212+
}
213+
214+
fn check_disjoint<'a, I>(indels: &mut I) -> bool
215+
where
216+
I: std::iter::Iterator<Item = &'a Indel>,
217+
{
218+
if let Some(indel) = indels.next() {
219+
let mut indel = indel;
220+
return indels.all(|right_indel| {
221+
let check = indel <= right_indel;
222+
indel = right_indel;
223+
return check;
224+
});
225+
}
226+
true
199227
}
200228

201229
#[cfg(test)]

0 commit comments

Comments
 (0)