1/* 2 * Copyright (c) 2021-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16package escompat; 17 18// NOTE: autogenerated file 19 20function asIntOrDefault(n: Number | undefined, def: int): int { 21 if (n === undefined) { 22 return def 23 } 24 return (n!).toInt(); 25} 26 27function normalizeIndex(idx: int, len: int): int { 28 if (idx < -len) { 29 return 0 30 } 31 if (idx < 0) { 32 return len + idx 33 } 34 if (idx > len) { 35 return len 36 } 37 return idx 38} 39 40class ArrayKeysIterator<T> implements IterableIterator<number> { 41 private parent: Array<T> 42 private idx: int = 0 43 private isDone: boolean = false 44 45 constructor(parent: Array<T>) { 46 this.parent = parent 47 } 48 49 override next(): IteratorResult<number> { 50 if (this.isDone || this.idx >= this.parent.actualLength) { 51 this.isDone = true 52 return new IteratorResult<number>() 53 } 54 return new IteratorResult<number>(this.idx++ as number) 55 } 56 57 override $_iterator(): IterableIterator<number> { 58 return this 59 } 60} 61 62class FromBuffer {} 63// initialized in _initializerBlock_.ets 64const FROM_BUFFER: FromBuffer; 65 66/** 67 * Represents JS API-compatible Array 68 */ 69export class Array<T> implements ReadonlyArray<T>, Iterable<T> { 70 private buffer: FixedArray<NullishType> 71 internal actualLength: int 72 73 override get length(): number { 74 return this.actualLength as number 75 } 76 77 set length(newLen: number) { 78 const len = newLen as int 79 if (len < 0 || len > this.actualLength) { 80 throw new RangeError("can't change length to bigger or negative") 81 } 82 this.actualLength = len 83 } 84 85 public override $_get(index: number): T { 86 return this.$_get(index as int) 87 } 88 89 public $_set(i: number, val: T): void { 90 this.$_set(i as int, val) 91 } 92 93 public native $_get(idx: int): T; 94 95 internal final $_get_unsafe(idx: int): T { 96 return this.buffer[idx] as T 97 } 98 99 public native $_set(idx: int, val: T): void; 100 101 private $_set_unsafe(idx: int, val: T): void { 102 this.buffer[idx] = val 103 } 104 105 /** 106 * Creates a new instance of Array 107 */ 108 public constructor(arrayLen: int) { 109 this.buffer = new NullishType[arrayLen] 110 this.actualLength = arrayLen 111 } 112 113 public constructor(arrayLen: number) { 114 this(arrayLen as int) 115 } 116 117 internal constructor(_tag: FromBuffer, buf: FixedArray<NullishType>) { 118 this.buffer = buf 119 this.actualLength = buf.length 120 } 121 122 internal constructor() { 123 this.buffer = new NullishType[4] 124 this.actualLength = 0 125 } 126 127 /** 128 * Creates a new instance of Array based on Object[] 129 * 130 * @param d Array initializer 131 */ 132 public constructor(first: T, ...d: T[]) { 133 this.buffer = new NullishType[d.length + 1] 134 this.actualLength = d.length as int + 1 135 136 this.buffer[0] = first 137 138 for (let k: int = 0; k < d.length; k++) { 139 this.$_set_unsafe(k + 1, d[k]) 140 } 141 } 142 143 /** 144 * Creates a new instance of Array. 145 * 146 * @param arrayLength amount of elements. 147 * 148 * @param initialValue initial value of elements. 149 * 150 */ 151 public static create<T>(arrayLength: number, initialValue: T): Array<T> { 152 let other = new Array<T>(arrayLength as int) 153 other.fill(initialValue) 154 return other 155 } 156 157 /** 158 * Extends Array with new elements to specified length. 159 * 160 * @param arrayLength new length of the array. 161 * 162 * @param initialValue initial value of added elements. 163 * 164 */ 165 public extendTo(arrayLength: number, initialValue: T): void { 166 if (arrayLength > Int.MAX_VALUE) { 167 throw new RangeError("arrayLength must be <= int32 max") 168 } 169 const len = arrayLength as int 170 const delta: int = len - this.actualLength 171 if (delta <= 0) { 172 return 173 } 174 this.ensureUnusedCapacity(delta) 175 for (let i: int = 0; i < delta; i++) { 176 this.buffer[this.actualLength + i] = initialValue 177 } 178 this.actualLength = len 179 } 180 181 /** 182 * Shrinks Array to specified length. 183 * 184 * @param arrayLength length at which to shrink. 185 * 186 */ 187 public shrinkTo(arrayLength: number): void { 188 if (arrayLength >= this.actualLength) { 189 return 190 } 191 let newLen: int = arrayLength as int 192 if (newLen < 0) { 193 // Convert from signed to unsigned 194 newLen = newLen & Int.MAX_VALUE 195 } 196 const other = this.slice(0, newLen) 197 this.buffer = other.buffer 198 this.actualLength = other.actualLength 199 } 200 201 /** 202 * Creates a new instance of an Array with the specified length 203 * 204 * @param arrayLength The length of the array to be created (optional). 205 * 206 * @returns A new Array instance with the specified length 207 */ 208 static $_invoke<T>(): Array<T> { 209 return new Array<T>(); 210 } 211 212 /** 213 * Creates a new instance of an Array with the specified length 214 * 215 * @param arrayLength The length of the array to be created (optional). 216 * 217 * @returns A new Array instance with the specified length 218 */ 219 static $_invoke<T>(arrayLength?: number): Array<T> { 220 if (arrayLength != undefined) { 221 return new Array<T>(arrayLength); 222 } else { 223 return new Array<T>(); 224 } 225 } 226 227 /** 228 * Creates a new instance of an Array with the specified length 229 * 230 * @param items array of values. 231 * 232 * @returns A new Array instance with the specified length 233 */ 234 static $_invoke<T>(...items: T[]): Array<T> { 235 if (items.length == 0) { 236 return new Array<T>(0) 237 } 238 return new Array<T>(items[0], ...items.slice(1)) 239 } 240 241 /** 242 * Creates a new `Array` instance from `Object[]` primitive array. 243 * 244 * @param iterable an iterable object to convert to an array. 245 * 246 * @returns `Array` intance constructed from `Object[]` primitive array. 247 */ 248 public static from<T>(iterable: ArrayLike<T> | Iterable<T>): Array<T> { 249 const ret = new Array<T>() 250 iteratorForEach<T>(iterable.$_iterator(), (x: T): void => { 251 ret.push(x) 252 }) 253 return ret 254 } 255 256 /** 257 * Creates a new `Array` instance from `Object[]` ArrayLike. 258 * 259 * @param arr an iterable object to convert to an array. 260 * 261 * @returns `Array` intance constructed from `Object[]` ArrayLike. 262 */ 263 public static from<T>(arr: ArrayLike<T>): Array<T> { 264 const ret = new Array<T>(arr.length as int) 265 let i = 0 266 iteratorForEach<T>(arr.$_iterator(), (x: T): void => { 267 ret[i] = x 268 i += 1 269 }) 270 return ret 271 } 272 273 /** 274 * Creates a new `Array` instance from `Object[]` primitive array. 275 * 276 * @param iterable an iterable object to convert to an array. 277 * 278 * @param mapfn a mapping function to call on every element of the array. 279 * Every value to be added to the array is first passed through this function, and `mapfn`'s return value 280 * is added to the array instead. 281 * 282 * @returns `Array` intance constructed from `Object[]` primitive array and given function. 283 */ 284 public static from<T, U>(iterable: ArrayLike<T> | Iterable<T>, mapfn: (v: T, k: number) => U): Array<U> { 285 const ret = new Array<U>() 286 // NOTE (ikorobkov): Please don't replace idx as int[1] with int-variable, because of value of single variable doesn't change (idx++) into lambda call by unknown reason 287 const idx : FixedArray<int> = new int[1] 288 idx[0] = 0 289 iteratorForEach<T>(iterable.$_iterator(), (x: T): void => { 290 ret.push(mapfn(x, idx[0] as number)) 291 idx[0] += 1 292 }) 293 return ret 294 } 295 296 public static from<T, U>(values: FixedArray<T>, mapfn: (v: T, k: number) => U): Array<U> { 297 const ret = new Array<U>(values.length) 298 for (let i = 0; i < values.length; ++i) { 299 ret[i] = mapfn(values[i], i) 300 } 301 return ret 302 } 303 304 /** 305 * Creates a new `Array` instance from `Object[]` primitive array. 306 * 307 * @param arr primitive array. 308 * 309 * @returns `Array` intance constructed from `Object[]` primitive array. 310 */ 311 public static from<T>(arr: FixedArray<T>): Array<T> { 312 const len = arr.length 313 const ret : FixedArray<NullishType> = new NullishType[len as int] 314 for (let i: int = 0; i < len; i++) { 315 ret[i] = arr[i] as NullishType 316 } 317 return new Array<T>(FROM_BUFFER, ret) 318 } 319 320 private lastIndexOfUndefined(fi: int): int { 321 for (let i = fi; i >= 0; i--) { 322 if (this.$_get_unsafe(i) instanceof undefined) { 323 return i 324 } 325 } 326 return -1 327 } 328 329 private lastIndexOfNull(fi: int): int { 330 for (let i = fi; i >= 0; i--) { 331 if (this.$_get_unsafe(i) instanceof null) { 332 return i 333 } 334 } 335 return -1 336 } 337 338 private lastIndexOfString(val: String, fi: int): int { 339 for (let i = fi; i >= 0; i--) { 340 const tmp = this.$_get_unsafe(i) 341 if (tmp instanceof String) { 342 if (tmp == val) { 343 return i 344 } 345 } 346 } 347 return -1 348 } 349 350 private lastIndexOfNumber(val: Number, fi: int): int { 351 const unboxedVal: number = val.valueOf() 352 if (isNaN(val)) { 353 return -1 354 } 355 for (let i = fi; i >= 0; i--) { 356 const tmp = this.$_get_unsafe(i) 357 if (tmp instanceof Number) { 358 if (unboxedVal == tmp.unboxed()) { 359 return i 360 } 361 } 362 } 363 return -1 364 } 365 366 private lastIndexOfFloat(val: Float, fi: int): int { 367 const unboxedVal: float = val.unboxed() 368 if (isNaN(val)) { 369 return -1 370 } 371 for (let i = fi; i >= 0; i--) { 372 const tmp = this.$_get_unsafe(i) 373 if (tmp instanceof Float) { 374 if (unboxedVal == tmp.unboxed()) { 375 return i 376 } 377 } 378 } 379 return -1 380 } 381 382 private lastIndexOfLong(val: Long, fi: int): int { 383 const unboxedVal: long = val.unboxed() 384 for (let i = fi; i >= 0; i--) { 385 const tmp = this.$_get_unsafe(i) 386 if (tmp instanceof Long) { 387 if (tmp == unboxedVal) { 388 return i 389 } 390 } 391 } 392 return -1 393 } 394 395 private lastIndexOfInt(val: Int, fi: int): int { 396 const unboxedVal: int = val.unboxed() 397 for (let i = fi; i >= 0; i--) { 398 const tmp = this.$_get_unsafe(i) 399 if (tmp instanceof Int) { 400 if (tmp == unboxedVal) { 401 return i 402 } 403 } 404 } 405 return -1 406 } 407 408 private lastIndexOfCommon(val: T, fi: int): int { 409 for (let i = fi; i >= 0; i--) { 410 if (val == this.$_get_unsafe(i)) { 411 return i 412 } 413 } 414 return -1 415 } 416 417 private searchUndefined(fi: int, len: int): boolean { 418 for (let i = fi; i < len; i++) { 419 if (this.$_get_unsafe(i) instanceof undefined) { 420 return true 421 } 422 } 423 return false 424 } 425 426 private searchNull(fi: int, len: int): boolean { 427 for (let i = fi; i < len; i++) { 428 if (this.$_get_unsafe(i) instanceof null) { 429 return true 430 } 431 } 432 return false 433 } 434 435 private searchString(val: String, fi: int, len: int): boolean { 436 for (let i = fi; i < len; i++) { 437 const tmp = this.$_get_unsafe(i) 438 if (tmp instanceof String) { 439 if (tmp == val) { 440 return true 441 } 442 } 443 } 444 return false 445 } 446 447 private searchNumber(val: Number, fi: int, len: int): boolean { 448 const unboxedVal: number = val.valueOf() 449 if (isNaN(unboxedVal)) { 450 for (let i = fi; i < len; i++) { 451 const tmp = this.$_get_unsafe(i) 452 if (tmp instanceof Number) { 453 if (isNaN(tmp.valueOf())) { 454 return true 455 } 456 } 457 } 458 } else { 459 for (let i = fi; i < len; i++) { 460 const tmp = this.$_get_unsafe(i) 461 if (tmp instanceof Number) { 462 if (unboxedVal == tmp.unboxed()) { 463 return true 464 } 465 } 466 } 467 } 468 return false 469 } 470 471 private searchFloat(val: Float, fi: int, len: int): boolean { 472 const unboxedVal: float = val.unboxed() 473 if (isNaN(unboxedVal)) { 474 for (let i = fi; i < len; i++) { 475 const tmp = this.$_get_unsafe(i) 476 if (tmp instanceof Float) { 477 if (isNaN(tmp.unboxed())) { 478 return true 479 } 480 } 481 } 482 } else { 483 for (let i = fi; i < len; i++) { 484 const tmp = this.$_get_unsafe(i) 485 if (tmp instanceof Float) { 486 if (unboxedVal == tmp.unboxed()) { 487 return true 488 } 489 } 490 } 491 } 492 return false 493 } 494 495 private searchLong(val: Long, fi: int, len: int): boolean { 496 const unboxedVal: long = val.unboxed() 497 for (let i = fi; i < len; i++) { 498 const tmp = this.$_get_unsafe(i) 499 if (tmp instanceof Long) { 500 if (tmp == unboxedVal) { 501 return true 502 } 503 } 504 } 505 return false 506 } 507 508 private searchInt(val: Int, fi: int, len: int): boolean { 509 const unboxedVal: int = val.unboxed() 510 for (let i = fi; i < len; i++) { 511 const tmp = this.$_get_unsafe(i) 512 if (tmp instanceof Int) { 513 if (tmp == unboxedVal) { 514 return true 515 } 516 } 517 } 518 return false 519 } 520 521 private searchCommon(val: T, fi: int, len: int): boolean { 522 for (let i = fi; i < len; i++) { 523 if (val == this.$_get_unsafe(i)) { 524 return true; 525 } 526 } 527 return false 528 } 529 530 private indexOfUndefined(fi: int, len: int): int { 531 for (let i = fi; i < len; i++) { 532 if (this.$_get_unsafe(i) instanceof undefined) { 533 return i 534 } 535 } 536 return -1 537 } 538 539 private indexOfNull(fi: int, len: int): int { 540 for (let i = fi; i < len; i++) { 541 if (this.$_get_unsafe(i) instanceof null) { 542 return i 543 } 544 } 545 return -1 546 } 547 548 private indexOfString(val: String, fi: int, len: int): int { 549 for (let i = fi; i < len; i++) { 550 const tmp = this.$_get_unsafe(i) 551 if (tmp instanceof String) { 552 if (tmp == val) { 553 return i 554 } 555 } 556 } 557 return -1 558 } 559 560 private indexOfNumber(val: Number, fi: int, len: int): int { 561 const unboxedVal: number = val.valueOf() 562 if (isNaN(val)) { 563 return -1 564 } 565 for (let i = fi; i < len; i++) { 566 const tmp = this.$_get_unsafe(i) 567 if (tmp instanceof Number) { 568 if (unboxedVal == tmp.unboxed()) { 569 return i 570 } 571 } 572 } 573 return -1 574 } 575 576 private indexOfFloat(val: Float, fi: int, len: int): int { 577 const unboxedVal: float = val.unboxed() 578 if (isNaN(val)) { 579 return -1 580 } 581 for (let i = fi; i < len; i++) { 582 const tmp = this.$_get_unsafe(i) 583 if (tmp instanceof Float) { 584 if (unboxedVal == tmp.unboxed()) { 585 return i 586 } 587 } 588 } 589 return -1 590 } 591 592 private indexOfLong(val: Long, fi: int, len: int): int { 593 const unboxedVal: long = val.unboxed() 594 for (let i = fi; i < len; i++) { 595 const tmp = this.$_get_unsafe(i) 596 if (tmp instanceof Long) { 597 if (tmp == unboxedVal) { 598 return i 599 } 600 } 601 } 602 return -1 603 } 604 605 private indexOfInt(val: Int, fi: int, len: int): int { 606 const unboxedVal: int = val.unboxed() 607 for (let i = fi; i < len; i++) { 608 const tmp = this.$_get_unsafe(i) 609 if (tmp instanceof Int) { 610 if (tmp == unboxedVal) { 611 return i 612 } 613 } 614 } 615 return -1 616 } 617 618 private indexOfCommon(val: T, fi: int, len: int): int { 619 for (let i = fi; i < len; i++) { 620 if (val == this.$_get_unsafe(i)) { 621 return i 622 } 623 } 624 return -1 625 } 626 /** 627 * Default comparison function for sort algorithm. 628 * Objects are compared as string. Both objects are convereted to string 629 * using `toString()` method and compared using `compareTo() method of `string` class. 630 * 631 * @param a: Object - Object to be compared 632 * 633 * @param b: Object - Object to be compared 634 * 635 * @returns Returns one of values -1, 0, 1 (_less_, _equal_, _greater_ respectively). 636 */ 637 private static defaultComparator(a: NullishType, b: NullishType): number { 638 if (a instanceof Number && b instanceof Number) { 639 const x = (a as Number).valueOf() 640 const y = (b as Number).valueOf() 641 if (Number.isInteger(x) && Number.isInteger(y) && 642 x <= Int.MAX_VALUE / 128 && x >= Int.MIN_VALUE / 128 && 643 y <= Int.MAX_VALUE / 128 && y >= Int.MIN_VALUE / 128) { 644 let z = x as int 645 let w = y as int 646 return Array.defaultComparatorInts(z, w) 647 } 648 } else if (a instanceof String && b instanceof String) { 649 return a.compareTo(b) 650 } 651 let sa = new String(a) 652 let sb = new String(b) 653 return sa.compareTo(sb) 654 } 655 656 private static defaultComparatorInts(a: int, b: int): number { 657 if (a < 0) { 658 if (b >= 0) { 659 return -1 660 } 661 a *= -1 662 b *= -1 663 } else if (b < 0) { 664 return 1 665 } 666 let aDigs = 1 667 while (10 * aDigs <= a) { 668 aDigs *= 10 669 } 670 let bDigs = 1 671 while (10 * bDigs <= b) { 672 bDigs *= 10 673 } 674 675 while (aDigs > 0 && bDigs > 0) { 676 let r = (a / aDigs) - (b / bDigs) 677 if (r != 0) { 678 return r 679 } 680 aDigs /= 10 681 bDigs /= 10 682 } 683 return (aDigs - bDigs) 684 } 685 686 private static defaultComparatorStr(a: String, b: String) { 687 return a.compareTo(b) 688 } 689 690 /** 691 * Helper function preparing copy of `this` instance of `Array` class' data array. 692 * 693 * @returns Copy of an `Array`'s primitive array data. 694 */ 695 private copyArray(): FixedArray<NullishType> { 696 let len: int = this.actualLength 697 let res : FixedArray<NullishType> = new NullishType[len] 698 for (let i = 0; i < len; i++) { 699 res[i] = this.$_get_unsafe(i) 700 } 701 return res 702 } 703 704 private wrap_default_sort(): void { 705 let idxNonUndef = 0 706 type arrType = String | undefined 707 try { 708 let strArr : FixedArray<arrType> = new arrType[this.actualLength] 709 for (let i = 0; i < this.actualLength; i++) { 710 const vl = this.$_get_unsafe(i) 711 if (vl !== undefined) { 712 if (vl == null) { 713 this.$_set_unsafe(idxNonUndef, vl as T) 714 strArr[idxNonUndef] = "null" 715 } else { 716 this.$_set_unsafe(idxNonUndef, vl) 717 strArr[idxNonUndef] = (vl as object).toString() // #26217 718 } 719 idxNonUndef++ 720 } 721 } 722 let sortTo = idxNonUndef 723 for (let i = idxNonUndef; i < this.actualLength; i++) { 724 this.$_set_unsafe(i, undefined as T) 725 } 726 727 sort_default<NullishType>(this.buffer, strArr, 0, sortTo) 728 } 729 catch (e) { 730 if (e instanceof OutOfMemoryError) { 731 this.slow_default_sort() 732 } else { 733 throw e as Error 734 } 735 } 736 } 737 738 private slow_default_sort(): void { 739 let idxNonUndef = 0 740 const cmp: (l: NullishType, r: NullishType) => number = (l: NullishType, r: NullishType): number => { 741 return Array.defaultComparator(l, r) 742 } 743 for (let i = 0; i < this.actualLength; i++) { 744 const vl = this.$_get_unsafe(i) 745 if (vl !== undefined) { 746 this.$_set_unsafe(idxNonUndef, vl) 747 idxNonUndef++ 748 } 749 } 750 let sortTo = idxNonUndef 751 for (let i = idxNonUndef; i < this.actualLength; i++) { 752 this.$_set_unsafe(i, undefined as T) 753 } 754 sort_stable<NullishType>(this.buffer, 0, sortTo, cmp) 755 } 756 757 private move_undefined_end(): int { 758 let writeIndex: int = 0 759 for (let i = 0; i < this.actualLength; i++) { 760 let val = this.$_get_unsafe(i) 761 if (val !== undefined) { 762 if(writeIndex != i) { 763 this.$_set_unsafe(writeIndex, val) 764 } 765 writeIndex++ 766 } 767 } 768 for (let i = writeIndex; i < this.actualLength; i++) { 769 this.$_set_unsafe(i, undefined as T) 770 } 771 return writeIndex 772 } 773 774 /** 775 * Reorders elements of `this` using comparator function. 776 * 777 * @see ECMA-262, 23.1.3.30 778 * 779 * @param comparator function that defines the sort order. 780 * 781 * @returns `this` instance of `Array` class. 782 * 783 * @note Mutating method 784 * 785 * NOTE clarify UTF-16 or UTF-8 786 */ 787 public sort(comparator?: (a: T, b: T) => number): this { 788 if (this.actualLength <= 1) 789 return this 790 791 if (comparator == undefined) { 792 this.wrap_default_sort() 793 return this 794 } 795 796 const compareTo = this.move_undefined_end() 797 let cmp: (l: NullishType, r: NullishType) => number = (l: NullishType, r: NullishType): number => { 798 return comparator!(l as T, r as T) 799 } 800 sort_stable<NullishType>(this.buffer, 0, compareTo, cmp) 801 return this 802 } 803 804 /** 805 * Removes the first element from an array and returns that removed element. 806 * This method changes the length of the array. 807 * 808 * @returns shifted element, i.e. that was at index zero 809 */ 810 public shift(): T | undefined { 811 if(this.actualLength == 0) { 812 return undefined 813 } 814 let obj = this.$_get_unsafe(0) 815 const other = this.slice(1, this.actualLength) 816 this.buffer = other.buffer 817 this.actualLength = other.actualLength 818 return obj 819 } 820 821 /** 822 * Removes the last element from an array and returns that element. 823 * This method changes the length of the array. 824 * 825 * @returns removed element 826 */ 827 public pop(): T | undefined { 828 if(this.actualLength == 0) { 829 return undefined 830 } 831 let obj = this.$_get_unsafe(this.actualLength - 1) 832 this.buffer[this.actualLength - 1] = null 833 this.actualLength-- 834 return obj 835 } 836 837 /** 838 * Adds the specified elements to the end of an array and returns the new length of the array. 839 * 840 * @returns new length 841 */ 842 public push(...val: T[]): number { 843 this.ensureUnusedCapacity(val.length as int) 844 for (let i = 0; i < val.length; i++) { 845 this.buffer[this.actualLength + i] = val[i] 846 } 847 this.actualLength += val.length 848 return this.actualLength 849 } 850 851 /** 852 * Adds the specified elements to the end of an array and returns the new length of the array. 853 * 854 * @returns new length 855 */ 856 public pushECMA(...val: T[]): number { 857 this.ensureUnusedCapacity(val.length as int) 858 for (let i = 0; i < val.length; i++) { 859 this.buffer[this.actualLength + i] = val[i] 860 } 861 this.actualLength += val.length 862 return this.actualLength 863 } 864 865 private ensureUnusedCapacity(cap: int): void { 866 if (this.actualLength + cap > this.buffer.length) { 867 const copy : FixedArray<NullishType> = new NullishType[this.buffer.length * 2 + cap] 868 for (let i = 0; i < this.actualLength; i++) { 869 copy[i] = this.buffer[i] 870 } 871 this.buffer = copy 872 } 873 } 874 875 /** 876 * Changes the contents of an array by removing or replacing existing elements 877 * and/or adding new elements in place. 878 * 879 * @param start index 880 * 881 * @param delete number of items after start index 882 * 883 * @returns an Array with deleted elements 884 */ 885 public splice(start: number, delete: Number | undefined, ...items: T[]): Array<T> { 886 return this.splice(start as int, asIntOrDefault(delete, 0), ...items) 887 } 888 889 /** 890 * Changes the contents of an array by removing or replacing existing elements 891 * and/or adding new elements in place. 892 * 893 * @param start index 894 * 895 * @param delete number of items after start index 896 * 897 * @returns an Array with deleted elements 898 */ 899 public splice(start: int, delete: int, ...items: T[]): Array<T> { 900 start = normalizeIndex(start, this.actualLength) 901 if (delete < 0) { 902 delete = 0 903 } 904 if (start > this.actualLength - delete) { 905 delete = this.actualLength - start 906 } 907 // this: [left middle right], we must replace middle with `items` 908 909 this.ensureUnusedCapacity(items.length as int - delete) 910 const oldLen = this.actualLength 911 this.actualLength = this.actualLength - delete + items.length as int 912 913 let ret = new Array<T>(delete) 914 let lastSet = start 915 // left part remains unchanged 916 // copy excluded part 917 for (let i = 0; i < delete; i++) { 918 ret.buffer[i] = this.buffer[start + i] 919 } 920 // move right part to the right of the buffer 921 const rightLen = oldLen - start - delete 922 if (items.length > delete) { 923 for (let i = 0; i < rightLen; i++) { 924 this.buffer[this.actualLength - 1 - i] = this.buffer[oldLen - 1 - i] 925 } 926 } else { 927 for (let i = 0; i < rightLen; i++) { 928 this.buffer[start + items.length as int + i] = this.buffer[start + delete + i] 929 } 930 } 931 // insert middle part 932 for (let i = 0; i < items.length; i++) { 933 this.buffer[start + i] = items[i] 934 } 935 return ret 936 } 937 938 /** 939 * Changes the contents of an array by removing or replacing existing elements 940 * and/or adding new elements in place. 941 * 942 * @param start index 943 * 944 * @returns an Array with deleted elements from start to the last element of the current instance 945 */ 946 public splice(start: number): Array<T> { 947 return this.splice(start as int) 948 } 949 950 /** 951 * Changes the contents of an array by removing or replacing existing elements 952 * and/or adding new elements in place. 953 * 954 * @param start index 955 * 956 * @returns an Array with deleted elements from start to the last element of the current instance 957 */ 958 public splice(start: int): Array<T> { 959 return this.splice(start, this.actualLength) 960 } 961 962 /** 963 * Checks whether the passed value is an Array. 964 * 965 * @param arr 966 * 967 * @returns true is arr is a non-nullish array, false otherwise 968 */ 969 public static isArray(o: NullishType): boolean { 970 if (o instanceof Array) { 971 return true 972 } 973 return (Type.of(o) instanceof ArrayType) 974 } 975 976 /** 977 * Creates a new Array instance from a variable number of arguments, 978 * regardless of number or type of the arguments. 979 * 980 * @param values an initilizer 981 * 982 * @returns a newly created Array 983 */ 984 public static of<T>(...values: T[]): Array<T> { 985 const ret = new Array<T>() 986 ret.ensureUnusedCapacity(values.length as int) 987 for (let i = 0; i < values.length; i++) { 988 ret.push(values[i]) 989 } 990 return ret 991 } 992 993 /** 994 * Adds the specified elements to the beginning of an Array 995 * and returns the new length of the Array. 996 * 997 * @param values data to be added 998 * 999 * @returns new length of the Array 1000 */ 1001 public unshift(...values: T[]): number { 1002 let buffer = this.buffer 1003 if (this.buffer.length <= values.length + this.actualLength) { 1004 buffer = new NullishType[this.buffer.length * 2 + values.length] 1005 } 1006 for (let i = 0; i < this.actualLength; i++) { 1007 buffer[this.actualLength + values.length as int - i - 1] = this.buffer[this.actualLength - 1 - i] 1008 } 1009 for (let i = 0; i < values.length; i++) { 1010 buffer[i] = values[i] 1011 } 1012 this.buffer = buffer 1013 this.actualLength += values.length 1014 return this.actualLength 1015 } 1016 1017 /** 1018 * Returns an iterator over all indices 1019 */ 1020 public override keys(): IterableIterator<Number> { 1021 return new ArrayKeysIterator<T>(this) 1022 } 1023 1024 /** 1025 * Returns an iterator over all values 1026 */ 1027 public override $_iterator(): IterableIterator<T> { 1028 return this.values() 1029 } 1030 1031 // === methods with uncompatible implementation === 1032 /** 1033 * Returns the elements of an array that meet the condition specified in a callback function. 1034 * 1035 * @param predicate A function that accepts up to three arguments. The filter method calls the predicate function one time for each element in the array. 1036 * 1037 * @returns New `Array` instance constructed from `this` with elements filtered using test function `predicate`. 1038 */ 1039 public override filter(predicate: (value: T, index: number, array: Array<T>) => boolean): Array<T> { 1040 const res = new Array<T>() 1041 for (let i: int = 0; i < this.actualLength; i++) { 1042 const val = this.$_get_unsafe(i) 1043 if (predicate(val, i as number, this)) { 1044 res.push(val) 1045 } 1046 } 1047 return res 1048 } 1049 1050 /** 1051 * Creates a new Array with all sub-array elements concatenated 1052 * into it recursively up to the specified depth. 1053 * 1054 * @param depth 1055 * 1056 * @returns a flattened Array with respect to depth 1057 */ 1058 public flat<U>(depth: number): Array<U> { 1059 return this.flat<U>(depth as int) 1060 } 1061 1062 /** 1063 * Creates a new Array with all sub-array elements concatenated 1064 * into it recursively up to the specified depth. 1065 * 1066 * @param depth 1067 * 1068 * @returns a flattened Array with respect to depth 1069 */ 1070 public flat<U>(depth: int): Array<U> { 1071 let ret = new Array<U>() 1072 this.flatImpl<U>(depth, ret) 1073 return ret 1074 } 1075 1076 private flatImpl<U>(depth: int, to: Array<U>) { 1077 throw new Error("not implemented") 1078 } 1079 1080 /** 1081 * Creates a new Array with all sub-array elements concatenated 1082 * 1083 * @returns a flattened Array 1084 */ 1085 public flat<U>(): Array<U> { 1086 return this.flat<U>(1) 1087 } 1088 1089 /** 1090 * Applies flat and than map 1091 * 1092 * fn a function to apply 1093 * 1094 * @return new Array after map and than flat 1095 */ 1096 // NOTE(ivan-tyulyandin): TBD, flatMap may be not subset, see ReadonlyArray 1097 public flatMap<U>(fn: (v: T, k: number, arr: Array<T>) => U): Array<U> { 1098 let mapped: Array<U> = this.map<U>(fn) 1099 return mapped.flat<U>() 1100 } 1101 1102 // === methods common among all arrays === 1103 1104 /** 1105 * Takes an integer value and returns the item at that index, 1106 * allowing for positive and negative integers. Negative integers count back 1107 * from the last item in the array. 1108 * 1109 * @param index Zero-based index of the array element to be returned. 1110 * Negative index counts back from the end of the array — if `index` < 0, index + `array.length()` is accessed. 1111 * 1112 * @returns The element in the array matching the given index. 1113 * Returns undefined if `index` < `-length()` or `index` >= `length()`. 1114 */ 1115 public override at(index: number): T | undefined { 1116 return this.at(index as int) 1117 } 1118 1119 /** 1120 * Creates a new `Array` from this `Array` instance and given `Array` instance. 1121 * 1122 * @param other to concatenate into a new array. 1123 * 1124 * @returns New `Array` instance, constructed from `this` and given `other` instances of `Array` class. 1125 */ 1126 // public override concat(...items: (T | ConcatArray<T>)[]): Array<T> { 1127 // throw new Error("not implemented") 1128 // } 1129 1130 public concat(...items: FixedArray<ConcatArray<T>>): Array<T> { 1131 let totalAdd = this.actualLength; 1132 for (let i = 0; i < items.length; i++) { 1133 totalAdd += items[i].length as int 1134 } 1135 1136 const buf : FixedArray<NullishType> = new NullishType[totalAdd]; 1137 1138 for (let i = 0; i < this.actualLength; i++) { 1139 buf[i] = this.$_get_unsafe(i); 1140 } 1141 1142 let insertTo = this.actualLength; 1143 for (let i = 0; i < items.length; i++) { 1144 const arr = items[i] 1145 const len = arr.length as int 1146 for (let j = 0; j < len; j++) { 1147 buf[insertTo++] = arr.$_get(j) 1148 } 1149 } 1150 1151 return new Array<T>(FROM_BUFFER, buf); 1152 } 1153 1154 /** 1155 * Takes an integer value and returns the item at that index, 1156 * allowing for positive and negative integers. Negative integers count back 1157 * from the last item in the array. 1158 * 1159 * @param index Zero-based index of the array element to be returned. 1160 * Negative index counts back from the end of the array — if `index` < 0, index + `array.length()` is accessed. 1161 * 1162 * @returns The element in the array matching the given index. 1163 * Returns undefined if `index` < `-length()` or `index` >= `length()`. 1164 */ 1165 public at(index: int): T | undefined { 1166 let len = this.actualLength; 1167 let k: int; 1168 if (index >= 0) { 1169 k = index; 1170 } else { 1171 k = len + index; 1172 } 1173 1174 if (k < 0 || k >= len) { 1175 return undefined; 1176 } 1177 1178 return this.$_get_unsafe(k); 1179 } 1180 1181 /** 1182 * Makes a shallow copy of the Array part to another location in the same Array and returns it without modifying its length. 1183 * 1184 * @param target index at which to copy the sequence 1185 * 1186 * @param start index at which to start copying elements from 1187 * 1188 * @param end index at which to end copying elements from 1189 * 1190 * @returns this array after transformation 1191 */ 1192 public copyWithin(target: number, start: number, end?: Number): this { 1193 this.copyWithin(target as int, start as int, asIntOrDefault(end, this.actualLength)); 1194 return this; 1195 } 1196 1197 /** 1198 * Makes a shallow copy of the Array part to another location in the same Array and returns it without modifying its length. 1199 * 1200 * @param target index at which to copy the sequence 1201 * 1202 * @param start index at which to start copying elements from 1203 * 1204 * @param end index at which to end copying elements from 1205 * 1206 * @returns this array after transformation 1207 */ 1208 public copyWithin(target: int, start: int, end: int): this { 1209 target = normalizeIndex(target, this.actualLength) 1210 start = normalizeIndex(start, this.actualLength) 1211 end = normalizeIndex(end, this.actualLength) 1212 1213 if (end <= start) { 1214 return this; 1215 } 1216 1217 if (target <= start) { 1218 while (start < end) { 1219 const read = this.$_get_unsafe(start++); 1220 this.$_set_unsafe(target++, read); 1221 } 1222 } else { 1223 let len = end - start; 1224 if (target + len > this.actualLength) { 1225 len = this.actualLength - target 1226 } 1227 for (let i = 0; i < len; i++) { 1228 const read = this.$_get_unsafe(start + len - 1 - i); 1229 this.$_set_unsafe(target + len - 1 - i, read); 1230 } 1231 } 1232 1233 return this; 1234 } 1235 1236 /** 1237 * Makes a shallow copy of the Array part to another location in the same Array and returns it without modifying its length. 1238 * 1239 * @param target index at which to copy the sequence 1240 * 1241 * @param start index at which to start copying elements from 1242 * 1243 * @returns this array after transformation 1244 */ 1245 public copyWithin(target: int, start: int): this { 1246 this.copyWithin(target, start, this.actualLength); 1247 return this; 1248 } 1249 1250 /** 1251 * Makes a shallow copy of the Array part to another location in the same Array and returns it without modifying its length. 1252 * 1253 * @param target index at which to copy the sequence 1254 * 1255 * @returns this array after transformation 1256 */ 1257 public copyWithin(target: int): this { 1258 this.copyWithin(target, 0, this.actualLength); 1259 return this; 1260 } 1261 1262 /** 1263 * Changes all elements in the Array to a static value, from a start index to an end index 1264 * 1265 * @param value to fill the array with 1266 * 1267 * @param start index at which to start filling 1268 * 1269 * @param end index at which to end filling, but not including 1270 * 1271 * @returns this array after transformation 1272 */ 1273 public fill(value: T, start?: Number, end?: Number): this { 1274 this.fill(value, asIntOrDefault(start, 0), asIntOrDefault(end, this.actualLength)); 1275 return this; 1276 } 1277 1278 /** 1279 * Changes all elements in the Array to a static value, from a start index to an end index 1280 * 1281 * @param value to fill the array with 1282 * 1283 * @param start index at which to start filling 1284 * 1285 * @param end index at which to end filling, but not including 1286 * 1287 * @returns this array after transformation 1288 */ 1289 public native fill(value: T, start: int, end: int): this; 1290 1291 /** 1292 * Returns the value of the first element in the array where predicate is true, and undefined 1293 * otherwise. 1294 * 1295 * @param predicate find calls predicate once for each element of the array, in ascending 1296 * order, until it finds one where predicate returns true. If such an element is found, find 1297 * immediately returns that element value. Otherwise, find returns undefined. 1298 * 1299 * @returns the value of the first element in the array or undefined 1300 */ 1301 public override find(predicate: (value: T, index: number, array: Array<T>) => boolean): T | undefined { 1302 const res = this.findIndex(predicate) 1303 if (res == -1) { 1304 return undefined 1305 } 1306 return this.$_get_unsafe(res as int); 1307 } 1308 1309 /** 1310 * Returns the index of the first element in the array where predicate is true, and -1 1311 * otherwise. 1312 * 1313 * @param predicate find calls predicate once for each element of the array, in ascending 1314 * order, until it finds one where predicate returns true. If such an element is found, 1315 * findIndex immediately returns that element index. Otherwise, findIndex returns -1. 1316 * 1317 * @returns found element index or -1 otherwise 1318 */ 1319 public override findIndex(predicate: (value: T, index: number, array: Array<T>) => boolean): number { 1320 for (let i = 0; i < this.actualLength; i++) { 1321 if (predicate(this.$_get_unsafe(i), i as number, this)) { 1322 return i; 1323 } 1324 } 1325 return -1; 1326 } 1327 1328 /** 1329 * Iterates the array in reverse order and returns the value of the first element 1330 * that satisfies the provided testing function 1331 * 1332 * @param predicate testing function 1333 * 1334 * @returns found element or undefined otherwise 1335 */ 1336 public override findLast(predicate: (elem: T, index: number, array: Array<T>) => boolean): T | undefined { 1337 for (let i = this.actualLength - 1; i >= 0; i--) { 1338 const val = this.$_get_unsafe(i); 1339 if (predicate(val, i as number, this)) { 1340 return val; 1341 } 1342 } 1343 return undefined; 1344 } 1345 1346 /** 1347 * Determines whether all the members of an array satisfy the specified test. 1348 * 1349 * @param predicate A function that accepts up to three arguments. The every method calls 1350 * the predicate function for each element in the array until the predicate returns a value 1351 * which is coercible to the Boolean value false, or until the end of the array. 1352 * 1353 * @returns `true` if `predicate` returns a `true` value for every array element. Otherwise, `false`. 1354 */ 1355 public override every(predicate: (value: T, index: number, array: Array<T>) => boolean): boolean { 1356 let curArrLength = this.actualLength 1357 for (let i = 0; i < curArrLength && i < this.actualLength; i++) { 1358 if (!predicate(this.$_get_unsafe(i), i as number, this)) { 1359 return false 1360 } 1361 } 1362 return true; 1363 } 1364 1365 /** 1366 * Determines whether the specified callback function returns true for any element of an array. 1367 * 1368 * @param predicate A function that accepts up to three arguments. The some method calls 1369 * the predicate function for each element in the array until the predicate returns a value 1370 * which is coercible to the Boolean value true, or until the end of the array. 1371 * 1372 * @returns `true` if `predicate` returns a `true` value for at least one array element. Otherwise, `false`. 1373 */ 1374 public override some(predicate: (value: T, index: number, array: Array<T>) => boolean): boolean { 1375 for (let i = 0; i < this.actualLength; i++) { 1376 if (predicate(this.$_get_unsafe(i), i as number, this)) { 1377 return true 1378 } 1379 } 1380 return false 1381 } 1382 1383 /** 1384 * Iterates the array in reverse order and returns the index of 1385 * the first element that satisfies the provided testing function. 1386 * If no elements satisfy the testing function, -1 is returned. 1387 * 1388 * @param predicate testing function 1389 * 1390 * @returns index of first element satisfying to predicate, -1 if no such element 1391 */ 1392 public override findLastIndex(predicate: (element: T, index: number, array: Array<T>) => boolean): number { 1393 for (let i = this.actualLength - 1; i >= 0; i--) { 1394 if (predicate(this.$_get_unsafe(i), i as number, this)) { 1395 return i 1396 } 1397 } 1398 return -1 1399 } 1400 1401 /** 1402 * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. 1403 * 1404 * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. 1405 * 1406 * @returns a result after applying callbackfn over all elements of the Array 1407 */ 1408 public override reduce(callbackfn: (previousValue: T, currentValue: T, index: number, array: Array<T>) => T): T { 1409 if (this.actualLength == 0) { 1410 throw new TypeError("Reduce of empty array with no initial value") 1411 } 1412 let acc: T = this.$_get_unsafe(0); 1413 for (let i = 1; i < this.actualLength; i++) { 1414 acc = callbackfn(acc, this.$_get_unsafe(i), i as number, this) 1415 } 1416 return acc 1417 } 1418 1419 /** 1420 * Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. 1421 * 1422 * @param callbackfn A function that accepts up to four arguments. The reduce method calls the callbackfn function one time for each element in the array. 1423 * 1424 * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. 1425 * 1426 * @returns a result after applying callbackfn over all elements of the Array 1427 */ 1428 public override reduce<U = T>(callbackfn: (previousValue: U, currentValue: T, index: number, array: Array<T>) => U, initialValue: U): U { 1429 let acc = initialValue 1430 for (let i = 0; i < this.actualLength; i++) { 1431 acc = callbackfn(acc, this.$_get_unsafe(i), i as number, this) 1432 } 1433 return acc 1434 } 1435 1436 /** 1437 * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. 1438 * 1439 * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. 1440 * 1441 * @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of an array value. 1442 * 1443 * @returns a result after applying callbackfn over all elements of the Array 1444 */ 1445 public override reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, index: number, array: Array<T>) => U, initialValue: U): U { 1446 let acc = initialValue 1447 for (let i = this.actualLength - 1; i >= 0; i--) { 1448 acc = callbackfn(acc, this.$_get_unsafe(i), i as number, this) 1449 } 1450 return acc 1451 } 1452 1453 /** 1454 * Performs the specified action for each element in an array. 1455 * 1456 * @param callbackfn A function that accepts up to three arguments. forEach calls the callbackfn function one time for each element in the array. 1457 */ 1458 public override forEach(callbackfn: (value: T, index: number, array: Array<T>) => void): void { 1459 const len0 = this.actualLength; 1460 for (let i = 0; i < len0; i++) { 1461 callbackfn(this.$_get_unsafe(i), i as number, this) 1462 } 1463 } 1464 1465 /** 1466 * Creates a new `Array` object and populates it with elements of `this` instance of `Array` class 1467 * selected from `start` to `end` (`end` not included) where `start` and `end` represent the index of items in that array. 1468 * 1469 * @param start zero-based index at which to start extraction 1470 * 1471 * @param end zero-based index at which to end extraction. `slice()` extracts up to but not including end. 1472 * 1473 * @returns `Array` instance, constructed from extracted elements of `this` instance. 1474 */ 1475 public override slice(start?: Number, end?: Number): Array<T> { 1476 const len: int = this.actualLength; 1477 return this.slice(asIntOrDefault(start, 0), asIntOrDefault(end, len)) 1478 } 1479 1480 /** 1481 * Creates a new `Array` object and populates it with elements of `this` instance of `Array` class 1482 * selected from `start` to `end` (`end` not included) where `start` and `end` represent the index of items in that array. 1483 * 1484 * @param start zero-based index at which to start extraction 1485 * 1486 * @param end zero-based index at which to end extraction. `slice()` extracts up to but not including end. 1487 * 1488 * @returns `Array` instance, constructed from extracted elements of `this` instance. 1489 */ 1490 public slice(start: int, end: int): Array<T> { 1491 const len: int = this.actualLength; 1492 const relStart = normalizeIndex(start, len) 1493 const relEnd = normalizeIndex(end, len) 1494 1495 let count = relEnd - relStart; 1496 if (count < 0) { 1497 count = 0; 1498 } 1499 let res : FixedArray<NullishType> = new NullishType[count] 1500 for (let i = 0; i < count; i++) { 1501 res[i] = this.$_get_unsafe(relStart + i); 1502 } 1503 1504 return new Array<T>(FROM_BUFFER, res) 1505 } 1506 1507 /** 1508 * Creates a new `Array` object and populates it with elements of `this` instance of `Array` class 1509 * selected from `start` to `Int.MAX_VALUE`, which means 'to the end of an array'. 1510 * 1511 * @param start zero-based index at which to start extraction 1512 * 1513 * @returns `Array` instance, constructed from extracted elements of `this` instance. 1514 */ 1515 public slice(start: int): Array<T> { 1516 return this.slice(start, Int.MAX_VALUE as int); 1517 } 1518 1519 /** 1520 * Returns the last index at which a given element can be found in the array, 1521 * or -1 if it is not present. The array is searched backwards, starting at fromIndex. 1522 * 1523 * @param searchElement element to locate in the array. 1524 * 1525 * @param fromIndex zero-based index at which to start searching backwards. 1526 * Negative index counts back from the end of the array — if `fromIndex` < 0, `fromIndex` + `length()` is used. 1527 * If `fromIndex` < `-length()`, the array is not searched and -1 is returned. 1528 * If `fromIndex` >= `length()` then `array.length - 1` is used, causing the entire array to be searched. 1529 * If `fromIndex` is undefined then `fromIndex = 0`. 1530 * If `fromIndex` is ommited then `fromIndex = length()-1`. 1531 * 1532 * @returns The last index of the element in the array; -1 if not found. 1533 */ 1534 public native lastIndexOf(searchElement: T, fromIndex: int): int; 1535 1536 /** 1537 * Returns the last index at which a given element can be found in the array, 1538 * or -1 if it is not present. The array is searched backwards, starting at fromIndex. 1539 * 1540 * @param searchElement element to locate in the array. 1541 * 1542 * @param fromIndex zero-based index at which to start searching backwards. 1543 * Negative index counts back from the end of the array — if `fromIndex` < 0, `fromIndex` + `length()` is used. 1544 * If `fromIndex` < `-length()`, the array is not searched and -1 is returned. 1545 * If `fromIndex` >= `length()` then `array.length - 1` is used, causing the entire array to be searched. 1546 * If `fromIndex` is undefined then `fromIndex = 0`. 1547 * If `fromIndex` is ommited then `fromIndex = length()-1`. 1548 * 1549 * @returns The last index of the element in the array; -1 if not found. 1550 */ 1551 public lastIndexOf(searchElement: T, fromIndex: number|undefined): number { 1552 return this.lastIndexOf(searchElement, asIntOrDefault(fromIndex, 0)); 1553 } 1554 1555 /** 1556 * Returns the last index at which a given element can be found in the array, 1557 * or -1 if it is not present. The array is searched backwards, starting at fromIndex. 1558 * 1559 * @param searchElement element to locate in the array. 1560 * 1561 * @param fromIndex zero-based index at which to start searching backwards. 1562 * Negative index counts back from the end of the array — if `fromIndex` < 0, `fromIndex` + `length()` is used. 1563 * If `fromIndex` < `-length()`, the array is not searched and -1 is returned. 1564 * If `fromIndex` >= `length()` then `array.length - 1` is used, causing the entire array to be searched. 1565 * If `fromIndex` is undefined then `fromIndex = 0`. 1566 * If `fromIndex` is ommited then `fromIndex = length()-1`. 1567 * 1568 * @returns The last index of the element in the array; -1 if not found. 1569 */ 1570 public native lastIndexOf(searchElement: T): number; 1571 1572 /** 1573 * Creates and returns a new string by concatenating all of the elements in an `Array`, 1574 * separated by a specified separator string. 1575 * If the array has only one item, then that item will be returned without using the separator. 1576 * 1577 * @param sep specifies a separator 1578 * 1579 * @returns A string with all array elements joined. If `length()` is 0, the empty string is returned. 1580 */ 1581 public override join(sep?: String): string { 1582 if (this.actualLength == 0) { 1583 return "" 1584 } 1585 const sepReal = sep === undefined ? "," : sep! 1586 // NOTE(aleksander-sotov) We can't call String constructor here due to internal issue 18583 1587 const first_el = this.$_get_unsafe(0) 1588 let first_str = "" 1589 if (first_el !== undefined && first_el !== null) { 1590 first_str = new String(first_el) 1591 } 1592 let sb = new StringBuilder(first_str) 1593 for (let i: int = 1; i < this.actualLength; i++) { 1594 const tmp = this.$_get_unsafe(i) 1595 sb.append(sepReal); 1596 // NOTE(aleksander-sotov) We can't call String constructor here due to internal issue 18583 1597 if (tmp !== undefined && tmp !== null) { 1598 sb.append(new String(tmp)) 1599 } else { 1600 sb.append("") 1601 } 1602 } 1603 1604 return sb.toString(); 1605 } 1606 1607 /** 1608 * Returns a string representing the specified array and its elements. 1609 * 1610 * @returns string representation 1611 */ 1612 public override toString(): string { 1613 return this.join(","); 1614 } 1615 1616 /** 1617 * Returns a locale string representing the specified array and its elements. 1618 * 1619 * @param locales 1620 * 1621 * @param options 1622 * 1623 * @returns string representation 1624 */ 1625 public toLocaleString(locales: Object, options: Object): string { 1626 throw new Error("Array.toLocaleString: not implemented") 1627 } 1628 1629 /** 1630 * Returns a locale string representing the specified array and its elements. 1631 * 1632 * @param options 1633 * 1634 * @returns string representation 1635 */ 1636 public toLocaleString(locales: Object): string { 1637 return this.toLocaleString(new Object(), new Object()) 1638 } 1639 1640 /** 1641 * Returns a locale string representing the specified array and its elements. 1642 * 1643 * @returns string representation 1644 */ 1645 public override toLocaleString(): string { 1646 const sb = new StringBuilder() 1647 const len = this.actualLength; 1648 for (let i = 0; i < len; i++) { 1649 if (i != 0) { 1650 sb.append(",") 1651 } 1652 let x = this.$_get_unsafe(i) as NullishType; 1653 if ((null !== x) && (undefined !== x)) { 1654 sb.append((x! as object).toLocaleString()) // #26217 1655 } 1656 } 1657 return sb.toString() 1658 } 1659 1660 /** 1661 * Copying version of the splice() method. 1662 * 1663 * @param start index 1664 * 1665 * @param delete number of items after start index 1666 * 1667 * @returns a new Array with some elements removed and/or replaced at a given index. 1668 */ 1669 public toSpliced(start?: Number, delete?: Number): Array<T> { 1670 const len = this.actualLength; 1671 return this.toSpliced(asIntOrDefault(start, len), asIntOrDefault(delete, len)) 1672 } 1673 1674 /** 1675 * Copying version of the splice() method. 1676 * 1677 * @param start index 1678 * 1679 * @param delete number of items after start index 1680 * 1681 * @returns a new Array with some elements removed and/or replaced at a given index. 1682 */ 1683 public toSpliced(start: number, delete: number, ...items: FixedArray<T>): Array<T> { 1684 const len = this.actualLength; 1685 return this.toSpliced(start as int, delete as int, ...items) 1686 } 1687 1688 /** 1689 * Copying version of the splice() method. 1690 * 1691 * @param start index 1692 * 1693 * @param delete number of items after start index 1694 * 1695 * @returns a new Array with some elements removed and/or replaced at a given index. 1696 */ 1697 public toSpliced(start: int, delete: int, ...items: FixedArray<T>): Array<T> { 1698 const len = this.actualLength; 1699 start = normalizeIndex(start, len); 1700 if (delete < 0) { 1701 delete = 0; 1702 } else if (delete > len) { 1703 delete = len; 1704 } 1705 if (start > len - delete) { 1706 delete = len - start 1707 } 1708 const res : FixedArray<NullishType> = new NullishType[len - delete + items.length]; 1709 for (let i = 0; i < start; i++) { 1710 res[i] = this.$_get_unsafe(i) 1711 } 1712 for (let i = 0; i < items.length; i++) { 1713 res[start + i] = items[i] 1714 } 1715 for (let i = start + delete; i < len; i++) { 1716 res[i - delete + items.length] = this.$_get_unsafe(i) 1717 } 1718 return new Array<T>(FROM_BUFFER, res); 1719 } 1720 1721 /** 1722 * Copying version of the splice() method. 1723 * 1724 * @param start index 1725 * 1726 * @returns a new Array with some elements removed and/or replaced at a given index. 1727 */ 1728 public toSpliced(start: int): Array<T> { 1729 return this.toSpliced(start, this.actualLength) 1730 } 1731 1732 /** 1733 * Checks whether an Array includes a certain value among its entries, 1734 * returning true or false as appropriate. 1735 * 1736 * @param val value to search 1737 * 1738 * @param fromIndex start index 1739 * 1740 * @returns true if val is in Array 1741 */ 1742 public override includes(val: T, fromIndex?: Number): boolean { 1743 const len = this.actualLength; 1744 const fi = normalizeIndex(asIntOrDefault(fromIndex, 0), len); 1745 if (val instanceof String) { 1746 return this.searchString(val, fi, len) 1747 } else if (val instanceof Number) { 1748 return this.searchNumber(val, fi, len) 1749 } else if (val instanceof Float) { 1750 return this.searchFloat(val, fi, len) 1751 } else if (val instanceof Long) { 1752 return this.searchLong(val, fi, len) 1753 } else if (val instanceof Int) { 1754 return this.searchInt(val, fi, len) 1755 } else if (val === undefined) { 1756 return this.searchUndefined(fi, len) 1757 } else if (val == null) { 1758 return this.searchNull(fi, len) 1759 } else { 1760 return this.searchCommon(val, fi, len) 1761 } 1762 } 1763 1764 /** 1765 * Returns the first index at which a given element 1766 * can be found in the array, or -1 if it is not present. 1767 * 1768 * @param val value to search 1769 * 1770 * @param fromIndex index to search from 1771 * 1772 * @returns index of val, -1 otherwise 1773 */ 1774 public native indexOf(val: T, fromIndex: int): int; 1775 1776 /** 1777 * Returns the first index at which a given element 1778 * can be found in the array, or -1 if it is not present. 1779 * 1780 * @param val value to search 1781 * 1782 * @param fromIndex index to search from 1783 * 1784 * @returns index of val, -1 otherwise 1785 */ 1786 public override indexOf(val: T, fromIndex?: Number): number { 1787 return this.indexOf(val, asIntOrDefault(fromIndex, 0)) 1788 } 1789 1790 public native indexOf(val: T): number; 1791 1792 /** 1793 * Copying version of the sort() method. 1794 * It returns a new array with the elements sorted in ascending order. 1795 * 1796 * @returns sorted copy of hte current instance using default comparator 1797 */ 1798 public toSorted(): Array<T> { 1799 let arr = new Array<T>(FROM_BUFFER, this.copyArray()); 1800 arr.sort() 1801 return arr 1802 } 1803 1804 /** 1805 * Copying version of the sort() method. 1806 * It returns a new array with the elements sorted in ascending order. 1807 * 1808 * @param comparator function to compare to elements of the Array 1809 * 1810 * @returns sorted copy of the current instance comparator 1811 */ 1812 public toSorted(comparator: (a: T, b: T) => number): Array<T> { 1813 let arr = new Array<T>(FROM_BUFFER, this.copyArray()); 1814 arr.sort(comparator) 1815 return arr 1816 } 1817 1818 /** 1819 * Modifies `this` instance of `Array` class and populates 1820 * it with same elements ordered towards the direction opposite to that previously stated. 1821 * 1822 * @note Mutating method 1823 */ 1824 public reverse(): this { 1825 for (let i = 0; i < this.actualLength / 2; i++) { 1826 const tmp = this.$_get_unsafe(i); 1827 const idx_r = this.actualLength - 1 - i; 1828 const val_r = this.$_get_unsafe(idx_r); 1829 this.$_set_unsafe(i, val_r); 1830 this.$_set_unsafe(idx_r, tmp); 1831 } 1832 return this; 1833 } 1834 1835 /** 1836 * Copying version of the reverse() method. 1837 * It returns a new array with the elements in reversed order. 1838 * 1839 * @returns reversed copy of the current Array 1840 */ 1841 public toReversed(): Array<T> { 1842 let arr : FixedArray<NullishType> = new NullishType[this.actualLength] 1843 for (let i = 0; i < this.actualLength; i++) { 1844 arr[this.actualLength - 1 - i] = this.$_get_unsafe(i) 1845 } 1846 return new Array<T>(FROM_BUFFER, arr) 1847 } 1848 1849 /** 1850 * Copying version of using the bracket notation to change the value of a given index. 1851 * It returns a new Array with the element at the given index replaced with the given value. 1852 * 1853 * @param index to replace 1854 * 1855 * @param value new value 1856 * 1857 * @returns a new Array with the element at the given index replaced with the given value 1858 */ 1859 public with(index: number, value: T): Array<T> { 1860 return this.with(index as int, value) 1861 } 1862 1863 /** 1864 * Copying version of using the bracket notation to change the value of a given index. 1865 * It returns a new Array with the element at the given index replaced with the given value. 1866 * 1867 * @param index to replace 1868 * 1869 * @param value new value 1870 * 1871 * @returns a new Array with the element at the given index replaced with the given value 1872 */ 1873 public with(index: int, value: T): Array<T> { 1874 if (index < 0) { 1875 index += this.actualLength; 1876 } 1877 if (index >= this.actualLength) { 1878 throw new RangeError("Invalid index") 1879 } 1880 let arr = new Array<T>(FROM_BUFFER, this.copyArray()); 1881 arr.$_set_unsafe(index, value); 1882 return arr 1883 } 1884 1885 /** 1886 * Returns an iterator over all values 1887 */ 1888 public override values(): IterableIterator<T> { 1889 return new ArrayValuesIterator_T<T>(this); 1890 } 1891 1892 /** 1893 * Returns an iterable of key, value pairs for every entry in the array 1894 */ 1895 public override entries(): IterableIterator<[number, T]> { 1896 return new ArrayEntriesIterator_T<T>(this); 1897 } 1898 1899 /** 1900 * Calls a defined callback function on each element of an array, and returns an array that contains the results. 1901 * 1902 * @param callbackfn A function that accepts up to three arguments. The map method calls the callbackfn function one time for each element in the array. 1903 * 1904 * @returns `Array` instance, constructed from `this` and given function. 1905 */ 1906 public override map<U>(callbackfn: (value: T, index: number, array: Array<T>) => U): Array<U> { 1907 const len = this.actualLength; 1908 let res : FixedArray<NullishType> = new NullishType[len]; 1909 for (let i = 0; i < this.actualLength; i++) { 1910 res[i] = callbackfn(this.$_get_unsafe(i), i as number, this); 1911 } 1912 return new Array<U>(FROM_BUFFER, res); 1913 } 1914 1915 /** 1916 * Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function. 1917 * 1918 * @param callbackfn A function that accepts up to four arguments. The reduceRight method calls the callbackfn function one time for each element in the array. 1919 * 1920 * @returns a result after applying callbackfn over all elements of the Array 1921 */ 1922 public override reduceRight(callbackfn: (previousValue: T, currentValue: T, index: number, array: Array<T>) => T): T { 1923 if (this.actualLength == 0) { 1924 throw new TypeError("Reduce of empty array with no initial value") 1925 } 1926 let acc: T = this.$_get_unsafe(this.actualLength - 1); 1927 for (let i = this.actualLength - 2; i >= 0; i--) { 1928 if (this.actualLength > i) { 1929 acc = callbackfn(acc, this.$_get_unsafe(i), i as number, this) 1930 } 1931 } 1932 return acc 1933 } 1934 1935} 1936 1937class ArrayValuesIterator_T<T> implements IterableIterator<T> { 1938 private parent: Array<T> 1939 private idx: int = 0 1940 private isDone: boolean = false 1941 1942 constructor(parent: Array<T>) { 1943 this.parent = parent 1944 } 1945 1946 override next(): IteratorResult<T> { 1947 if (this.isDone || this.idx >= this.parent.actualLength) { 1948 this.isDone = true 1949 return new IteratorResult<T>() 1950 } 1951 return new IteratorResult<T>(this.parent.$_get_unsafe(this.idx++)) 1952 } 1953 1954 override $_iterator(): IterableIterator<T> { 1955 return this; 1956 } 1957 1958 public __Iterator_getLength(): int { 1959 return this.parent.length as int 1960 } 1961} 1962 1963class ArrayEntriesIterator_T<T> implements IterableIterator<[number, T]> { 1964 private parent: Array<T> 1965 private idx: int = 0 1966 private isDone: boolean = false 1967 1968 constructor(parent: Array<T>) { 1969 this.parent = parent 1970 } 1971 1972 override next(): IteratorResult<[number, T]> { 1973 if (this.isDone || this.idx >= this.parent.actualLength) { 1974 this.isDone = true 1975 return new IteratorResult<[number, T]>() 1976 } 1977 const i = this.idx++; 1978 const vl: [number, T] = [i as number, this.parent.$_get_unsafe(i)] 1979 return new IteratorResult<[number, T]>(vl); 1980 } 1981 1982 override $_iterator(): IterableIterator<[number, T]> { 1983 return this; 1984 } 1985 1986 public __Iterator_getLength(): int { 1987 return this.parent.length as int 1988 } 1989} 1990