@@ -53,6 +53,10 @@ impl<'s> ElementWriter<'s> {
5353 )
5454 }
5555
56+ fn shift ( & self , bundle : & mut BNode ) {
57+ bundle. shift ( self . parent , self . next_sibling . clone ( ) ) ;
58+ }
59+
5660 fn patch ( self , node : VNode , bundle : & mut BNode ) -> Self {
5761 test_log ! ( "patching: {:?} -> {:?}" , bundle, node) ;
5862 test_log ! (
@@ -61,7 +65,6 @@ impl<'s> ElementWriter<'s> {
6165 self . next_sibling
6266 ) ;
6367 // Advance the next sibling reference (from right to left)
64- bundle. shift ( self . parent , self . next_sibling . clone ( ) ) ;
6568 let next = node. reconcile ( self . parent_scope , self . parent , self . next_sibling , bundle) ;
6669 test_log ! ( " next_position: {:?}" , next) ;
6770 Self {
@@ -71,23 +74,23 @@ impl<'s> ElementWriter<'s> {
7174 }
7275}
7376
74- struct NodeEntry ( BNode ) ;
75- impl Borrow < Key > for NodeEntry {
77+ struct KeyedEntry ( BNode , usize ) ;
78+ impl Borrow < Key > for KeyedEntry {
7679 fn borrow ( & self ) -> & Key {
7780 self . 0 . key ( ) . expect ( "unkeyed child in fully keyed list" )
7881 }
7982}
80- impl Hash for NodeEntry {
83+ impl Hash for KeyedEntry {
8184 fn hash < H : std:: hash:: Hasher > ( & self , state : & mut H ) {
8285 <Self as Borrow < Key > >:: borrow ( self ) . hash ( state)
8386 }
8487}
85- impl PartialEq for NodeEntry {
88+ impl PartialEq for KeyedEntry {
8689 fn eq ( & self , other : & Self ) -> bool {
8790 <Self as Borrow < Key > >:: borrow ( self ) == <Self as Borrow < Key > >:: borrow ( other)
8891 }
8992}
90- impl Eq for NodeEntry { }
93+ impl Eq for KeyedEntry { }
9194
9295impl BNode {
9396 fn make_list ( & mut self ) -> & mut BList {
@@ -165,9 +168,14 @@ impl BList {
165168 parent_scope : & AnyScope ,
166169 parent : & Element ,
167170 next_sibling : NodeRef ,
168- lefts : Vec < VNode > ,
169- rights : & mut Vec < BNode > ,
171+ left_vdoms : Vec < VNode > ,
172+ rev_bundles : & mut Vec < BNode > ,
170173 ) -> NodeRef {
174+ macro_rules! key {
175+ ( $v: expr) => {
176+ $v. key( ) . expect( "unkeyed child in fully keyed list" )
177+ } ;
178+ }
171179 /// Find the first differing key in 2 iterators
172180 fn matching_len < ' a , ' b > (
173181 a : impl Iterator < Item = & ' a Key > ,
@@ -178,62 +186,72 @@ impl BList {
178186
179187 // Find first key mismatch from the back
180188 let matching_len_end = matching_len (
181- lefts
182- . iter ( )
183- . map ( |v| v. key ( ) . expect ( "unkeyed child in fully keyed list" ) )
184- . rev ( ) ,
185- rights
186- . iter ( )
187- . map ( |v| v. key ( ) . expect ( "unkeyed child in fully keyed list" ) ) ,
189+ left_vdoms. iter ( ) . map ( |v| key ! ( v) ) . rev ( ) ,
190+ rev_bundles. iter ( ) . map ( |v| key ! ( v) ) ,
188191 ) ;
189192
190- if matching_len_end == std:: cmp:: min ( lefts. len ( ) , rights. len ( ) ) {
193+ // If there is no key mismatch, apply the unkeyed approach
194+ // Corresponds to adding or removing items from the back of the list
195+ if matching_len_end == std:: cmp:: min ( left_vdoms. len ( ) , rev_bundles. len ( ) ) {
191196 // No key changes
192- return Self :: apply_unkeyed ( parent_scope, parent, next_sibling, lefts, rights) ;
197+ return Self :: apply_unkeyed (
198+ parent_scope,
199+ parent,
200+ next_sibling,
201+ left_vdoms,
202+ rev_bundles,
203+ ) ;
193204 }
194- // We partially deconstruct the new vector in several steps.
195- let mut lefts = lefts;
205+
206+ // We partially drain the new vnodes in several steps.
207+ let mut lefts = left_vdoms;
196208 let mut writer = ElementWriter {
197209 parent_scope,
198210 parent,
199211 next_sibling,
200212 } ;
201- // Diff matching children at the end
213+ // Step 1. Diff matching children at the end
202214 let lefts_to = lefts. len ( ) - matching_len_end;
203215 for ( l, r) in lefts
204216 . drain ( lefts_to..)
205217 . rev ( )
206- . zip ( rights [ ..matching_len_end] . iter_mut ( ) )
218+ . zip ( rev_bundles [ ..matching_len_end] . iter_mut ( ) )
207219 {
208220 writer = writer. patch ( l, r) ;
209221 }
222+
223+ // Step 2. Diff matching children in the middle, that is between the first and last key mismatch
210224 // Find first key mismatch from the front
211225 let matching_len_start = matching_len (
212- lefts
213- . iter ( )
214- . map ( |v| v. key ( ) . expect ( "unkeyed child in fully keyed list" ) ) ,
215- rights
216- . iter ( )
217- . map ( |v| v. key ( ) . expect ( "unkeyed child in fully keyed list" ) )
218- . rev ( ) ,
226+ lefts. iter ( ) . map ( |v| key ! ( v) ) ,
227+ rev_bundles. iter ( ) . map ( |v| key ! ( v) ) . rev ( ) ,
219228 ) ;
220229
221- // Diff mismatched children in the middle
222- let rights_to = rights. len ( ) - matching_len_start;
223- let mut spliced_middle = rights. splice ( matching_len_end..rights_to, std:: iter:: empty ( ) ) ;
224- let mut rights_diff: HashSet < NodeEntry > =
230+ // Step 2.1. Splice out the existing middle part and build a lookup by key
231+ let rights_to = rev_bundles. len ( ) - matching_len_start;
232+ let mut spliced_middle =
233+ rev_bundles. splice ( matching_len_end..rights_to, std:: iter:: empty ( ) ) ;
234+ let mut spare_bundles: HashSet < KeyedEntry > =
225235 HashSet :: with_capacity ( ( matching_len_end..rights_to) . len ( ) ) ;
226- for r in & mut spliced_middle {
227- rights_diff . insert ( NodeEntry ( r ) ) ;
236+ for ( idx , r ) in ( & mut spliced_middle) . enumerate ( ) {
237+ spare_bundles . insert ( KeyedEntry ( r , idx ) ) ;
228238 }
239+
240+ // Step 2.2. Put the middle part back together in the new key order
229241 let mut replacements: Vec < BNode > = Vec :: with_capacity ( ( matching_len_start..lefts_to) . len ( ) ) ;
242+ // Roughly keep track of the order in which elements appear. If one appears out-of-order
243+ // we (over approximately) have to shift the element, otherwise it is guaranteed to be in place.
244+ let mut max_seen_idx = 0 ;
230245 for l in lefts
231246 . drain ( matching_len_start..) // lefts_to.. has been drained
232247 . rev ( )
233248 {
234- let l_key = l. key ( ) . expect ( "unkeyed child in fully keyed list" ) ;
235- let bundle = match rights_diff. take ( l_key) {
236- Some ( NodeEntry ( mut r_bundle) ) => {
249+ let bundle = match spare_bundles. take ( key ! ( l) ) {
250+ Some ( KeyedEntry ( mut r_bundle, idx) ) => {
251+ if idx < max_seen_idx {
252+ writer. shift ( & mut r_bundle) ;
253+ }
254+ max_seen_idx = usize:: max ( max_seen_idx, idx) ;
237255 writer = writer. patch ( l, & mut r_bundle) ;
238256 r_bundle
239257 }
@@ -245,22 +263,22 @@ impl BList {
245263 } ;
246264 replacements. push ( bundle) ;
247265 }
248- // now drop the splice iterator
266+ // drop the splice iterator and immediately replace the range with the reordered elements
249267 std:: mem:: drop ( spliced_middle) ;
250- rights . splice ( matching_len_end..matching_len_end, replacements) ;
268+ rev_bundles . splice ( matching_len_end..matching_len_end, replacements) ;
251269
252- // Remove any extra rights
253- for NodeEntry ( r ) in rights_diff . drain ( ) {
270+ // Step 2.3. Remove any extra rights
271+ for KeyedEntry ( r , _ ) in spare_bundles . drain ( ) {
254272 test_log ! ( "removing: {:?}" , r) ;
255273 r. detach ( parent) ;
256274 }
257275
258- // Diff matching children at the start
259- let rights_to = rights . len ( ) - matching_len_start;
276+ // Step 3. Diff matching children at the start
277+ let rights_to = rev_bundles . len ( ) - matching_len_start;
260278 for ( l, r) in lefts
261279 . drain ( ..) // matching_len_start.. has been drained already
262280 . rev ( )
263- . zip ( rights [ rights_to..] . iter_mut ( ) )
281+ . zip ( rev_bundles [ rights_to..] . iter_mut ( ) )
264282 {
265283 writer = writer. patch ( l, r) ;
266284 }
@@ -335,7 +353,6 @@ impl Reconcilable for VList {
335353 if let Some ( additional) = rights. len ( ) . checked_sub ( lefts. len ( ) ) {
336354 rights. reserve_exact ( additional) ;
337355 }
338- #[ allow( clippy:: let_and_return) ]
339356 let first = if self . fully_keyed && blist. fully_keyed {
340357 BList :: apply_keyed ( parent_scope, parent, next_sibling, lefts, rights)
341358 } else {
0 commit comments