@@ -6,22 +6,28 @@ import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, jo
6
6
import { idof , isArray as builtin_isArray } from "./builtins" ;
7
7
import { E_INDEXOUTOFRANGE , E_INVALIDLENGTH , E_ILLEGALGENTYPE , E_EMPTYARRAY , E_HOLEYARRAY } from "./util/error" ;
8
8
9
+ // @ts -ignore: decorator
10
+ @inline @lazy const MIN_SIZE : usize = 8 ;
11
+
9
12
/** 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 ) ;
15
18
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 ) ;
17
23
let newData = __renew ( oldData , newCapacity ) ;
18
24
memory . fill ( newData + oldCapacity , 0 , newCapacity - oldCapacity ) ;
19
25
if ( newData !== oldData ) { // oldData has been free'd
20
26
store < usize > ( array , newData , offsetof < ArrayBufferView > ( "buffer" ) ) ;
21
27
store < usize > ( array , newData , offsetof < ArrayBufferView > ( "dataStart" ) ) ;
22
28
__link ( array , changetype < usize > ( newData ) , false ) ;
23
29
}
24
- store < u32 > ( array , newCapacity , offsetof < ArrayBufferView > ( "byteLength" ) ) ;
30
+ store < u32 > ( array , < u32 > newCapacity , offsetof < ArrayBufferView > ( "byteLength" ) ) ;
25
31
}
26
32
}
27
33
@@ -56,7 +62,8 @@ export class Array<T> {
56
62
57
63
constructor ( length : i32 = 0 ) {
58
64
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 > ( ) ;
60
67
var buffer = changetype < ArrayBuffer > ( __new ( bufferSize , idof < ArrayBuffer > ( ) ) ) ;
61
68
memory . fill ( changetype < usize > ( buffer ) , 0 , bufferSize ) ;
62
69
this . buffer = buffer ; // links
@@ -70,7 +77,7 @@ export class Array<T> {
70
77
}
71
78
72
79
set length ( newLength : i32 ) {
73
- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
80
+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) , false ) ;
74
81
this . length_ = newLength ;
75
82
}
76
83
@@ -106,7 +113,7 @@ export class Array<T> {
106
113
@operator ( "[]=" ) private __set ( index : i32 , value : T ) : void {
107
114
if ( < u32 > index >= < u32 > this . length_ ) {
108
115
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 > ( ) ) ;
110
117
this . length_ = index + 1 ;
111
118
}
112
119
this . __uset ( index , value ) ;
@@ -204,7 +211,7 @@ export class Array<T> {
204
211
push ( value : T ) : i32 {
205
212
var length = this . length_ ;
206
213
var newLength = length + 1 ;
207
- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
214
+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
208
215
if ( isManaged < T > ( ) ) {
209
216
store < usize > ( this . dataStart + ( < usize > length << alignof < T > ( ) ) , changetype < usize > ( value ) ) ;
210
217
__link ( changetype < usize > ( this ) , changetype < usize > ( value ) , true ) ;
@@ -353,7 +360,7 @@ export class Array<T> {
353
360
354
361
unshift ( value : T ) : i32 {
355
362
var newLength = this . length_ + 1 ;
356
- ensureSize ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
363
+ ensureCapacity ( changetype < usize > ( this ) , newLength , alignof < T > ( ) ) ;
357
364
var dataStart = this . dataStart ;
358
365
memory . copy (
359
366
dataStart + sizeof < T > ( ) ,
0 commit comments