@@ -6,22 +6,28 @@ import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, jo
66import { idof , isArray as builtin_isArray } from "./builtins" ;
77import { E_INDEXOUTOFRANGE , E_INVALIDLENGTH , E_ILLEGALGENTYPE , E_EMPTYARRAY , E_HOLEYARRAY } from "./util/error" ;
88
9+ // @ts -ignore: decorator
10+ @inline @lazy const MIN_SIZE : usize = 8 ;
11+
912/** Ensures that the given array has _at least_ the specified backing size. */
10- function ensureSize ( array : usize , minSize : usize , alignLog2 : u32 ) : void {
11- // depends on the fact that Arrays mimic ArrayBufferView
12- var oldCapacity = changetype < ArrayBufferView > ( array ) . byteLength ;
13- if ( minSize > < usize > oldCapacity >>> alignLog2 ) {
14- if ( minSize > BLOCK_MAXSIZE >>> alignLog2 ) throw new RangeError ( E_INVALIDLENGTH ) ;
13+ function ensureCapacity ( array : usize , newSize : usize , alignLog2 : u32 , canGrow : bool = true ) : void {
14+ // Depends on the fact that Arrays mimic ArrayBufferView
15+ var oldCapacity = < usize > changetype < ArrayBufferView > ( array ) . byteLength ;
16+ if ( newSize > oldCapacity >>> alignLog2 ) {
17+ if ( newSize > BLOCK_MAXSIZE >>> alignLog2 ) throw new RangeError ( E_INVALIDLENGTH ) ;
1518 let oldData = changetype < usize > ( changetype < ArrayBufferView > ( array ) . buffer ) ;
16- let newCapacity = minSize << alignLog2 ;
19+ // Grows old capacity by factor of two.
20+ // Make sure we don't reach BLOCK_MAXSIZE for new growed capacity.
21+ let newCapacity = max ( newSize , MIN_SIZE ) << alignLog2 ;
22+ if ( canGrow ) newCapacity = max ( min ( oldCapacity << 1 , BLOCK_MAXSIZE ) , newCapacity ) ;
1723 let newData = __renew ( oldData , newCapacity ) ;
1824 memory . fill ( newData + oldCapacity , 0 , newCapacity - oldCapacity ) ;
1925 if ( newData !== oldData ) { // oldData has been free'd
2026 store < usize > ( array , newData , offsetof < ArrayBufferView > ( "buffer" ) ) ;
2127 store < usize > ( array , newData , offsetof < ArrayBufferView > ( "dataStart" ) ) ;
2228 __link ( array , changetype < usize > ( newData ) , false ) ;
2329 }
24- store < u32 > ( array , newCapacity , offsetof < ArrayBufferView > ( "byteLength" ) ) ;
30+ store < u32 > ( array , < u32 > newCapacity , offsetof < ArrayBufferView > ( "byteLength" ) ) ;
2531 }
2632}
2733
@@ -56,7 +62,8 @@ export class Array<T> {
5662
5763 constructor ( length : i32 = 0 ) {
5864 if ( < u32 > length > < u32 > BLOCK_MAXSIZE >>> alignof < T > ( ) ) throw new RangeError ( E_INVALIDLENGTH ) ;
59- var bufferSize = < usize > length << alignof < T > ( ) ;
65+ // reserve capacity for at least MIN_SIZE elements
66+ var bufferSize = < usize > max ( length , MIN_SIZE ) << alignof < T > ( ) ;
6067 var buffer = changetype < ArrayBuffer > ( __new ( bufferSize , idof < ArrayBuffer > ( ) ) ) ;
6168 memory . fill ( changetype < usize > ( buffer ) , 0 , bufferSize ) ;
6269 this . buffer = buffer ; // links
@@ -70,7 +77,7 @@ export class Array<T> {
7077 }
7178
7279 set length ( newLength : i32 ) {
73- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
80+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) , false ) ;
7481 this . length_ = newLength ;
7582 }
7683
@@ -106,7 +113,7 @@ export class Array<T> {
106113 @operator ( "[]=" ) private __set ( index : i32 , value : T ) : void {
107114 if ( < u32 > index >= < u32 > this . length_ ) {
108115 if ( index < 0 ) throw new RangeError ( E_INDEXOUTOFRANGE ) ;
109- ensureSize ( changetype < usize > ( this ) , index + 1 , alignof < T > ( ) ) ;
116+ ensureCapacity ( changetype < usize > ( this ) , index + 1 , alignof < T > ( ) ) ;
110117 this . length_ = index + 1 ;
111118 }
112119 this . __uset ( index , value ) ;
@@ -204,7 +211,7 @@ export class Array<T> {
204211 push ( value : T ) : i32 {
205212 var length = this . length_ ;
206213 var newLength = length + 1 ;
207- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
214+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
208215 if ( isManaged < T > ( ) ) {
209216 store < usize > ( this . dataStart + ( < usize > length << alignof < T > ( ) ) , changetype < usize > ( value ) ) ;
210217 __link ( changetype < usize > ( this ) , changetype < usize > ( value ) , true ) ;
@@ -353,7 +360,7 @@ export class Array<T> {
353360
354361 unshift ( value : T ) : i32 {
355362 var newLength = this . length_ + 1 ;
356- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
363+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
357364 var dataStart = this . dataStart ;
358365 memory . copy (
359366 dataStart + sizeof < T > ( ) ,
0 commit comments