@@ -23,60 +23,68 @@ export function repeat<T>(
2323 mapFn : ( i : number ) => T ,
2424 options : { fallback ?: Accessor < T > } = { } ,
2525) : Accessor < T [ ] > {
26- let disposers : ( ( ) => void ) [ ] = [ ] ,
27- items : T [ ] = [ ] ,
28- prevLen = 0 ;
29-
30- onCleanup ( ( ) => disposers . forEach ( f => f ( ) ) ) ;
26+ let prev : readonly T [ ] = [ ] ;
27+ let prevLen = 0 ;
28+ const disposers : ( ( ) => void ) [ ] = [ ] ;
29+ onCleanup ( ( ) => {
30+ for ( let index = 0 ; index < disposers . length ; index ++ ) {
31+ disposers [ index ] ! ( ) ;
32+ }
33+ } ) ;
3134
32- const mapLength = ( len : number ) : T [ ] => {
33- if ( len === 0 ) {
34- disposers . forEach ( f => f ( ) ) ;
35+ // Truncate toward zero and force positive
36+ const memoLen = createMemo ( ( ) => Math . max ( times ( ) | 0 , 0 ) ) ;
3537
36- if ( options . fallback )
37- return createRoot ( dispose => {
38- disposers = [ dispose ] ;
39- return ( items = [ options . fallback ! ( ) ] ) ;
40- } ) ;
38+ return function mapLength ( ) : T [ ] {
39+ const len = memoLen ( ) ;
40+ if ( len === prevLen ) return prev as T [ ] ;
4141
42- disposers = [ ] ;
43- return ( items = [ ] ) ;
42+ // Dispose of fallback or unnecessarry elements
43+ if ( prevLen === 0 ) disposers [ 0 ] ?.( ) ;
44+ else {
45+ for ( let index = len ; index < disposers . length ; index ++ ) {
46+ disposers [ index ] ! ( ) ;
47+ }
4448 }
4549
46- if ( prevLen === 0 ) {
47- // after fallback case:
48- if ( disposers [ 0 ] ) disposers [ 0 ] ( ) ;
49- for ( let i = 0 ; i < len ; i ++ ) items [ i ] = createRoot ( mapper . bind ( void 0 , i ) ) ;
50- return items ;
51- }
50+ // The following prefers to use `prev.slice` to
51+ // preserve any array element kind optimizations
52+ // the runtime has made.
5253
53- {
54- const diff = prevLen - len ;
55- if ( diff > 0 ) {
56- for ( let i = prevLen - 1 ; i >= len ; i -- ) disposers [ i ] ! ( ) ;
57- items . splice ( len , diff ) ;
58- disposers . splice ( len , diff ) ;
59- return items ;
54+ if ( len === 0 ) {
55+ const fallback = options . fallback ;
56+ if ( fallback ) {
57+ // Show fallback if available
58+ const next = prev . slice ( 0 , 1 ) ;
59+ next [ 0 ] = createRoot ( dispose => {
60+ disposers [ 0 ] = dispose ;
61+ return fallback ( ) ;
62+ } ) ;
63+
64+ disposers . length = 1 ;
65+ prevLen = 0 ;
66+ return ( prev = next ) ;
67+ } else {
68+ // Show empty array, otherwise
69+ disposers . length = 0 ;
70+ prevLen = 0 ;
71+ return ( prev = prev . slice ( 0 , 0 ) ) ;
6072 }
6173 }
6274
63- for ( let i = prevLen ; i < len ; i ++ ) items [ i ] = createRoot ( mapper . bind ( void 0 , i ) ) ;
64- return items ;
65- } ;
75+ const next = prev . slice ( 0 , len ) ;
6676
67- const mapper = ( index : number , dispose : ( ) => void ) : T => {
68- disposers [ index ] = dispose ;
69- return mapFn ( index ) ;
70- } ;
77+ // Create new elements as needed
78+ for ( let index = prevLen ; index < len ; index ++ ) {
79+ next [ index ] = createRoot ( dispose => {
80+ disposers [ index ] = dispose ;
81+ return mapFn ( index ) ;
82+ } ) ;
83+ }
7184
72- const memoLen = createMemo ( ( ) => Math . floor ( Math . max ( times ( ) , 0 ) ) ) ;
73- return ( ) => {
74- const len = memoLen ( ) ;
75- return untrack ( ( ) => {
76- const newItems = mapLength ( len ) ;
77- prevLen = len ;
78- return newItems ;
79- } ) ;
85+ disposers . length = len ;
86+ prevLen = len ;
87+ return ( prev = next ) ;
8088 } ;
8189}
8290
0 commit comments