@@ -63,6 +63,56 @@ impl ChangeSet {
6363 len
6464 }
6565
66+ // Changeset builder operations: delete/insert/retain
67+ fn delete(&mut self, n: usize) {
68+ use Operation::*;
69+ if n == 0 {
70+ return;
71+ }
72+
73+ if let Some(Delete(count)) = self.changes.last_mut() {
74+ *count += n;
75+ } else {
76+ self.changes.push(Delete(n));
77+ }
78+ }
79+
80+ fn insert(&mut self, fragment: Tendril) {
81+ use Operation::*;
82+
83+ if fragment.is_empty() {
84+ return;
85+ }
86+
87+ let new_last = match self.changes.as_mut_slice() {
88+ [.., Insert(prev)] => {
89+ prev.push_tendril(&fragment);
90+ return;
91+ }
92+ [.., Insert(prev), Delete(_)] => {
93+ prev.push_tendril(&fragment);
94+ return;
95+ }
96+ [.., last @ Delete(_)] => std::mem::replace(last, Insert(fragment)),
97+ _ => Insert(fragment),
98+ };
99+
100+ self.changes.push(new_last);
101+ }
102+
103+ fn retain(&mut self, n: usize) {
104+ use Operation::*;
105+ if n == 0 {
106+ return;
107+ }
108+
109+ if let Some(Retain(count)) = self.changes.last_mut() {
110+ *count += n;
111+ } else {
112+ self.changes.push(Retain(n));
113+ }
114+ }
115+
66116 /// Combine two changesets together.
67117 /// In other words, If `this` goes `docA` → `docB` and `other` represents `docB` → `docC`, the
68118 /// returned value will represent the change `docA` → `docC`.
@@ -77,7 +127,10 @@ impl ChangeSet {
77127 let mut head_a = changes_a.next();
78128 let mut head_b = changes_b.next();
79129
80− let mut changes: Vec<Operation> = Vec::with_capacity(len); // TODO: max(a, b), shrink_to_fit() afterwards
130+ let mut changes = Self {
131+ len: self.len,
132+ changes: Vec::with_capacity(len), // TODO: max(a, b), shrink_to_fit() afterwards
133+ };
81134
82135 loop {
83136 use std::cmp::Ordering;
@@ -88,37 +141,31 @@ impl ChangeSet {
88141 break;
89142 }
90143 // deletion in A
91− (Some(change @ Delete(..)), b) => {
92− changes.push(change);
144+ (Some(Delete(i)), b) => {
145+ changes.delete(i);
93146 head_a = changes_a.next();
94147 head_b = b;
95148 }
96149 // insertion in B
97150 (a, Some(Insert(current))) => {
98− // merge onto previous insert if possible
99− // TODO: do these as operations on a changeset
100− if let Some(Insert(prev)) = changes.last_mut() {
101− prev.push_tendril(¤t);
102− } else {
103− changes.push(Insert(current));
104− }
151+ changes.insert(current);
105152 head_a = a;
106153 head_b = changes_b.next();
107154 }
108155 (None, _) | (_, None) => return unreachable!(),
109156 (Some(Retain(i)), Some(Retain(j))) => match i.cmp(&j) {
110157 Ordering::Less => {
111− changes.push(Retain(i));
158+ changes.retain(i);
112159 head_a = changes_a.next();
113160 head_b = Some(Retain(j - i));
114161 }
115162 Ordering::Equal => {
116− changes.push(Retain(i));
163+ changes.retain(i);
117164 head_a = changes_a.next();
118165 head_b = changes_b.next();
119166 }
120167 Ordering::Greater => {
121− changes.push(Retain(j));
168+ changes.retain(j);
122169 head_a = Some(Retain(i - j));
123170 head_b = changes_b.next();
124171 }
@@ -147,12 +194,12 @@ impl ChangeSet {
147194 let len = s.chars().count();
148195 match len.cmp(&j) {
149196 Ordering::Less => {
150− changes.push(Insert(s));
197+ changes.insert(s);
151198 head_a = changes_a.next();
152199 head_b = Some(Retain(j - len));
153200 }
154201 Ordering::Equal => {
155− changes.push(Insert(s));
202+ changes.insert(s);
156203 head_a = changes_a.next();
157204 head_b = changes_b.next();
158205 }
@@ -160,7 +207,7 @@ impl ChangeSet {
160207 // figure out the byte index of the truncated string end
161208 let (pos, _) = s.char_indices().nth(j).unwrap();
162209 let pos = pos as u32;
163− changes.push(Insert(s.subtendril(0, pos)));
210+ changes.insert(s.subtendril(0, pos));
164211 head_a = Some(Insert(s.subtendril(pos, s.len() as u32 - pos)));
165212 head_b = changes_b.next();
166213 }
@@ -168,17 +215,17 @@ impl ChangeSet {
168215 }
169216 (Some(Retain(i)), Some(Delete(j))) => match i.cmp(&j) {
170217 Ordering::Less => {
171− changes.push(Delete(i));
218+ changes.delete(i);
172219 head_a = changes_a.next();
173220 head_b = Some(Delete(j - i));
174221 }
175222 Ordering::Equal => {
176− changes.push(Delete(j));
223+ changes.delete(j);
177224 head_a = changes_a.next();
178225 head_b = changes_b.next();
179226 }
180227 Ordering::Greater => {
181− changes.push(Delete(j));
228+ changes.delete(j);
182229 head_a = Some(Retain(i - j));
183230 head_b = changes_b.next();
184231 }
@@ -186,10 +233,7 @@ impl ChangeSet {
186233 };
187234 }
188235
189− Self {
190− len: self.len,
191− changes,
192− }
236+ changes
193237 }
194238
195239 /// Given another change set starting in the same document, maps this
@@ -421,37 +465,29 @@ impl Transaction {
421465 I: IntoIterator<Item = Change> + ExactSizeIterator,
422466 {
423467 let len = state.doc.len_chars();
424− let mut acc = Vec::with_capacity(2 * changes.len() + 1);
468+ let acc = Vec::with_capacity(2 * changes.len() + 1);
469+ let mut changeset = ChangeSet { changes: acc, len };
425470
426471 // TODO: verify ranges are ordered and not overlapping or change will panic.
427472
428473 let mut last = 0;
429474 for (from, to, tendril) in changes {
430475 // Retain from last "to" to current "from"
431− if from - last > 0 {
432− acc.push(Operation::Retain(from - last));
433− }
476+ changeset.retain(from - last);
434477 let span = to - from;
435478 match tendril {
436479 Some(text) => {
437− if span > 0 {
438− acc.push(Operation::Delete(span));
439− }
440− acc.push(Operation::Insert(text));
480+ changeset.delete(span);
481+ changeset.insert(text);
441482 }
442− None if span > 0 => acc.push(Operation::Delete(span)),
443− // empty delete is useless
444− None => (),
483+ None => changeset.delete(span),
445484 }
446485 last = to;
447486 }
448487
449− let span = len - last;
450− if span > 0 {
451− acc.push(Operation::Retain(span));
452− }
488+ changeset.retain(len - last);
453489
454− Self::from(ChangeSet { changes: acc, len })
490+ Self::from(changeset)
455491 }
456492
457493 /// Generate a transaction with a change per selection range.
@@ -591,7 +627,7 @@ mod test {
591627 }
592628
593629 #[test]
594− fn insert_composition() {
630+ fn optimized_composition() {
595631 let mut state = State::new("".into());
596632 let t1 = Transaction::insert(&state, Tendril::from_char('h'));
597633 t1.apply(&mut state);
@@ -620,5 +656,6 @@ mod test {
620656
621657 use Operation::*;
622658 assert_eq!(changes.changes, &[Insert("hello".into())]);
659+ // instead of insert h, insert e, insert l, insert l, insert o
623660 }
624661}