another crack at the algorithm. outros not currently applied

pull/568/head
Rich-Harris 8 years ago
parent 776b68ff71
commit c9dba817fb

@ -126,10 +126,16 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea
block.builders.create.addBlock( deindent` block.builders.create.addBlock( deindent`
var ${lookup} = Object.create( null ); var ${lookup} = Object.create( null );
var last;
for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { for ( var ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) {
var ${key} = ${each_block_value}[${i}].${node.key}; var ${key} = ${each_block_value}[${i}].${node.key};
${iterations}[${i}] = ${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); ${iterations}[${i}] = ${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} );
${state.parentNode && `${iterations}[${i}].${mountOrIntro}( ${state.parentNode}, null );`} ${state.parentNode && `${iterations}[${i}].${mountOrIntro}( ${state.parentNode}, null );`}
if ( last ) last.next = ${lookup}[ ${key} ];
${lookup}[ ${key} ].last = last;
last = ${lookup}[${key}];
} }
` ); ` );
@ -155,48 +161,78 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea
block.builders.update.addBlock( deindent` block.builders.update.addBlock( deindent`
var ${each_block_value} = ${snippet}; var ${each_block_value} = ${snippet};
if ( ${each_block_value}.length === 0 ) {
// special case
for ( ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) {
${iterations}[${i}].destroy( true );
}
${iterations} = [];
return;
}
var ${_iterations} = Array( ${each_block_value}.length ); var ${_iterations} = Array( ${each_block_value}.length );
var ${keys} = Object.create( null );
var index_by_key = Object.create( null ); var expected = ${iterations}[0];
var key_by_index = Array( ${each_block_value}.length ); var last;
var new_iterations = []; var discard_pile = [];
for ( ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) { for ( ${i} = 0; ${i} < ${each_block_value}.length; ${i} += 1 ) {
var ${key} = ${each_block_value}[${i}].${node.key}; var ${key} = ${each_block_value}[${i}].${node.key};
index_by_key[${key}] = ${i};
key_by_index[${i}] = ${key};
if ( ${lookup}[ ${key} ] ) { if ( expected ) {
// TODO this is an empty branch for non-dynamic blocks if ( ${key} === expected.key ) {
${dynamic && `${lookup}[ ${key} ].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} );`} expected = expected.next;
} else {
if ( ${key} in ${lookup} ) {
// probably a deletion
do {
expected.discard = true;
discard_pile.push( expected );
expected = expected.next;
} while ( expected && expected.key !== ${key} );
expected = expected && expected.next;
${lookup}[${key}].discard = false;
${lookup}[${key}].next = expected;
${lookup}[${key}].mount( ${parentNode}, expected ? expected.first : null );
} else {
// key is being inserted
${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} );
${lookup}[${key}].${mountOrIntro}( ${parentNode}, expected.first );
}
}
} else { } else {
${lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} ); // we're appending from this point forward
new_iterations.push( ${lookup}[ ${key} ] ); if ( ${lookup}[${key}] ) {
${lookup}[${key}].discard = false;
${lookup}[${key}].next = null;
${lookup}[${key}].mount( ${parentNode}, null );
} else {
${lookup}[${key}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}, ${key} );
${lookup}[${key}].${mountOrIntro}( ${parentNode}, null );
}
} }
if ( last ) last.next = ${lookup}[${key}];
${lookup}[${key}].last = last;
last = ${lookup}[${key}];
${_iterations}[${i}] = ${lookup}[ ${key} ]; ${_iterations}[${i}] = ${lookup}[ ${key} ];
} }
// TODO group consecutive runs into fragments? last.next = null;
${i} = new_iterations.length;
while ( ${i}-- ) {
${iteration} = new_iterations[${i}];
var index = index_by_key[${iteration}.key];
var next_sibling_key = key_by_index[index + 1];
${iteration}.${mountOrIntro}( ${parentNode}, next_sibling_key === undefined ? ${anchor} : ${lookup}[next_sibling_key].first );
}
for ( ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { while ( expected ) {
var ${iteration} = ${iterations}[${i}]; expected.destroy( true );
var index = index_by_key[${iteration}.key]; expected = expected.next;
}
if ( index === undefined ) { for ( ${i} = 0; ${i} < discard_pile.length; ${i} += 1 ) {
${destroy} if ( discard_pile[${i}].discard ) {
} else { discard_pile[${i}].destroy( true );
var next_sibling_key = key_by_index[index + 1];
${iteration}.mount( ${parentNode}, next_sibling_key === undefined ? ${anchor} : ${lookup}[next_sibling_key].first );
} }
} }

@ -0,0 +1,48 @@
const VALUES = Array.from( 'abcdefghijklmnopqrstuvwxyz' );
function toObjects ( array ) {
return array.split( '' ).map( x => ({ id: x }) );
}
function permute () {
const values = VALUES.slice();
const number = Math.floor(Math.random() * VALUES.length);
const permuted = [];
for (let i = 0; i < number; i++) {
permuted.push( ...values.splice( Math.floor( Math.random() * ( number - i ) ), 1 ) );
}
return permuted.join( '' );
}
export default {
data: {
values: toObjects( 'abc' )
},
html: `(a)(b)(c)`,
test ( assert, component, target ) {
function test ( sequence ) {
component.set({ values: toObjects( sequence ) });
assert.htmlEqual( target.innerHTML, sequence.split( '' ).map( x => `(${x})` ).join( '' ) );
}
// first, some fixed tests so that we can debug them
test( 'abc' );
test( 'abcd' );
test( 'abecd' );
test( 'fabecd' );
test( 'fabed' );
test( 'beadf' );
test( 'ghbeadf' );
test( 'gf' );
test( 'gc' );
test( 'g' );
test( '' );
test( 'abc' );
// then, we party
for ( let i = 0; i < 100; i += 1 ) test( permute() );
}
};

@ -0,0 +1,3 @@
{{#each values as value @id}}
({{value.id}})
{{/each}}
Loading…
Cancel
Save