1/* 2 * Copyright (c) 2021-2024 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 20% template = ERB.new(File.read("Array_header.erb"), nil, '%', eoutvar: '_sub04') 21<%= template.result(binding) %> 22 23class ArrayKeysIterator<T> implements IterableIterator<number> { 24 private parent: Array<T> 25 private idx: int = 0 26 27 constructor(parent: Array<T>) { 28 this.parent = parent 29 } 30 31 override next(): IteratorResult<number> { 32 if (this.idx >= this.parent.actualLength) { 33 return new IteratorResult<number>() 34 } 35 return new IteratorResult<number>(this.idx++ as number) 36 } 37 38 override $_iterator(): IterableIterator<number> { 39 return this 40 } 41} 42 43class FromBuffer {} 44const FROM_BUFFER = new FromBuffer() 45 46/** 47 * Represents JS API-compatible Array 48 */ 49export class Array<T> implements ReadonlyArray<T>, Iterable<T> { 50 private buffer: NullishType[] 51 internal actualLength: int 52 53 override get length(): number { 54 return this.actualLength as number 55 } 56 57 set length(newLen: number): void { 58 const len = newLen as int 59 if (len < 0 || len > this.actualLength) { 60 throw new RangeError("can't change length to bigger or negative") 61 } 62 this.actualLength = len 63 } 64 65 public override $_get(index: number): T { 66 return this.$_get(index as int) 67 } 68 69 public $_set(i: number, val: T): void { 70 this.$_set(i as int, val) 71 } 72 73 public $_get(idx: int): T { 74 if (idx >= this.actualLength || idx < 0) { 75 throw new RangeError("Out of bounds") 76 } 77 return this.buffer[idx] as T 78 } 79 80 internal $_get_unsafe(idx: int): T { 81 return this.buffer[idx] as T 82 } 83 84 public $_set(idx: int, val: T): void { 85 if (idx >= this.actualLength) { 86 throw new RangeError("Out of bounds") 87 } 88 this.buffer[idx] = val 89 } 90 91 private $_set_unsafe(idx: int, val: T): void { 92 this.buffer[idx] = val 93 } 94 95 /** 96 * Creates a new instance of Array 97 */ 98 public constructor(arrayLen: int) { 99 this.buffer = new NullishType[arrayLen] 100 this.actualLength = arrayLen 101 } 102 103 public constructor(arrayLen: number) { 104 this(arrayLen as int) 105 } 106 107 internal constructor(_tag: FromBuffer, buf: NullishType[]) { 108 this.buffer = buf 109 this.actualLength = buf.length 110 } 111 112 internal constructor() { 113 this.buffer = new NullishType[4] 114 this.actualLength = 0 115 } 116 117 /** 118 * Creates a new instance of Array based on Object[] 119 * 120 * @param d Array initializer 121 */ 122 public constructor(first: T, ...d: T[]) { 123 this.buffer = new NullishType[d.length + 1] 124 this.actualLength = d.length + 1 125 126 this.buffer[0] = first 127 128 for (let k: int = 0; k < d.length; k++) { 129 this.$_set_unsafe(k + 1, d[k]) 130 } 131 } 132 133 /** 134 * Creates a new instance of an Array with the specified length 135 * 136 * @param arrayLength The length of the array to be created (optional). 137 * 138 * @returns A new Array instance with the specified length 139 */ 140 static invoke<T>(arrayLength?: number): Array<T> { 141 if (arrayLength != undefined) { 142 return new Array<T>(arrayLength); 143 } else { 144 return new Array<T>(); 145 } 146 } 147 148 /** 149 * Creates a new `Array` instance from `Object[]` primitive array. 150 * 151 * @param arr an iterable object to convert to an array. 152 * 153 * @returns `Array` intance constructed from `Object[]` primitive array. 154 */ 155 public static from<T>(iterable: ArrayLike<T> | Iterable<T>): Array<T> { 156 return Array.from<T, T>(iterable, (x: T, k: number): T => x) 157 } 158 159 /** 160 * Creates a new `Array` instance from `Object[]` primitive array. 161 * 162 * @param iterable an iterable object to convert to an array. 163 * 164 * @param mapfn a mapping function to call on every element of the array. 165 * Every value to be added to the array is first passed through this function, and `mapfn`'s return value 166 * is added to the array instead. 167 * 168 * @returns `Array` intance constructed from `Object[]` primitive array and given function. 169 */ 170 public static from<T, U>(iterable: ArrayLike<T> | Iterable<T>, mapfn: (v: T, k: number) => U): Array<U> { 171 const ret = new Array<U>() 172 // 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 173 const idx = new int[1] 174 idx[0] = 0 175 iteratorForEach<T>(iterable.$_iterator(), (x: T): void => { 176 ret.push(mapfn(x, idx[0] as number)) 177 idx[0] += 1 178 }) 179 return ret 180 } 181 182 /** 183 * Creates a new `Array` instance from `Object[]` primitive array. 184 * 185 * @param arr primitive array. 186 * 187 * @returns `Array` intance constructed from `Object[]` primitive array. 188 */ 189 public static from<T>(arr: T[]): Array<T> { 190 const len = arr.length 191 const ret = new NullishType[len as int] 192 for (let i: int = 0; i < len; i++) { 193 ret[i] = arr[i] as NullishType 194 } 195 return new Array<T>(FROM_BUFFER, ret) 196 } 197 198 private lastIndexOfUndefined(fi: int): int { 199 for (let i = fi; i >= 0; i--) { 200 if (this.$_get_unsafe(i) instanceof undefined) { 201 return i 202 } 203 } 204 return -1 205 } 206 207 private lastIndexOfNull(fi: int): int { 208 for (let i = fi; i >= 0; i--) { 209 if (this.$_get_unsafe(i) instanceof null) { 210 return i 211 } 212 } 213 return -1 214 } 215 216 private lastIndexOfString(val: String, fi: int): int { 217 for (let i = fi; i >= 0; i--) { 218 const tmp = this.$_get_unsafe(i) 219 if (tmp instanceof String) { 220 if (tmp == val) { 221 return i 222 } 223 } 224 } 225 return -1 226 } 227 228 private lastIndexOfNumber(val: Number, fi: int): int { 229 const unboxedVal: number = val.valueOf() 230 if (isNaN(val)) { 231 return -1 232 } 233 for (let i = fi; i >= 0; i--) { 234 const tmp = this.$_get_unsafe(i) 235 if (tmp instanceof Number) { 236 if (unboxedVal == tmp.unboxed()) { 237 return i 238 } 239 } 240 } 241 return -1 242 } 243 244 private lastIndexOfFloat(val: Float, fi: int): int { 245 const unboxedVal: float = val.unboxed() 246 if (isNaN(val)) { 247 return -1 248 } 249 for (let i = fi; i >= 0; i--) { 250 const tmp = this.$_get_unsafe(i) 251 if (tmp instanceof Float) { 252 if (unboxedVal == tmp.unboxed()) { 253 return i 254 } 255 } 256 } 257 return -1 258 } 259 260 private lastIndexOfLong(val: Long, fi: int): int { 261 const unboxedVal: long = val.unboxed() 262 for (let i = fi; i >= 0; i--) { 263 const tmp = this.$_get_unsafe(i) 264 if (tmp instanceof Long) { 265 if (tmp == unboxedVal) { 266 return i 267 } 268 } 269 } 270 return -1 271 } 272 273 private lastIndexOfInt(val: Int, fi: int): int { 274 const unboxedVal: int = val.unboxed() 275 for (let i = fi; i >= 0; i--) { 276 const tmp = this.$_get_unsafe(i) 277 if (tmp instanceof Int) { 278 if (tmp == unboxedVal) { 279 return i 280 } 281 } 282 } 283 return -1 284 } 285 286 private lastIndexOfCommon(val: T, fi: int): int { 287 for (let i = fi; i >= 0; i--) { 288 if (val == this.$_get_unsafe(i)) { 289 return i 290 } 291 } 292 return -1 293 } 294 295 private searchUndefined(fi: int, len: int): boolean { 296 for (let i = fi; i < len; i++) { 297 if (this.$_get_unsafe(i) instanceof undefined) { 298 return true 299 } 300 } 301 return false 302 } 303 304 private searchNull(fi: int, len: int): boolean { 305 for (let i = fi; i < len; i++) { 306 if (this.$_get_unsafe(i) instanceof null) { 307 return true 308 } 309 } 310 return false 311 } 312 313 private searchString(val: String, fi: int, len: int): boolean { 314 for (let i = fi; i < len; i++) { 315 const tmp = this.$_get_unsafe(i) 316 if (tmp instanceof String) { 317 if (tmp == val) { 318 return true 319 } 320 } 321 } 322 return false 323 } 324 325 private searchNumber(val: Number, fi: int, len: int): boolean { 326 const unboxedVal: number = val.valueOf() 327 if (isNaN(unboxedVal)) { 328 for (let i = fi; i < len; i++) { 329 const tmp = this.$_get_unsafe(i) 330 if (tmp instanceof Number) { 331 if (isNaN(tmp.valueOf())) { 332 return true 333 } 334 } 335 } 336 } else { 337 for (let i = fi; i < len; i++) { 338 const tmp = this.$_get_unsafe(i) 339 if (tmp instanceof Number) { 340 if (unboxedVal == tmp.unboxed()) { 341 return true 342 } 343 } 344 } 345 } 346 return false 347 } 348 349 private searchFloat(val: Float, fi: int, len: int): boolean { 350 const unboxedVal: float = val.unboxed() 351 if (isNaN(unboxedVal)) { 352 for (let i = fi; i < len; i++) { 353 const tmp = this.$_get_unsafe(i) 354 if (tmp instanceof Float) { 355 if (isNaN(tmp.unboxed())) { 356 return true 357 } 358 } 359 } 360 } else { 361 for (let i = fi; i < len; i++) { 362 const tmp = this.$_get_unsafe(i) 363 if (tmp instanceof Float) { 364 if (unboxedVal == tmp.unboxed()) { 365 return true 366 } 367 } 368 } 369 } 370 return false 371 } 372 373 private searchLong(val: Long, fi: int, len: int): boolean { 374 const unboxedVal: long = val.unboxed() 375 for (let i = fi; i < len; i++) { 376 const tmp = this.$_get_unsafe(i) 377 if (tmp instanceof Long) { 378 if (tmp == unboxedVal) { 379 return true 380 } 381 } 382 } 383 return false 384 } 385 386 private searchInt(val: Int, fi: int, len: int): boolean { 387 const unboxedVal: int = val.unboxed() 388 for (let i = fi; i < len; i++) { 389 const tmp = this.$_get_unsafe(i) 390 if (tmp instanceof Int) { 391 if (tmp == unboxedVal) { 392 return true 393 } 394 } 395 } 396 return false 397 } 398 399 private searchCommon(val: T, fi: int, len: int): boolean { 400 for (let i = fi; i < len; i++) { 401 if (val == this.$_get_unsafe(i)) { 402 return true; 403 } 404 } 405 return false 406 } 407 408 private indexOfUndefined(fi: int, len: int): int { 409 for (let i = fi; i < len; i++) { 410 if (this.$_get_unsafe(i) instanceof undefined) { 411 return i 412 } 413 } 414 return -1 415 } 416 417 private indexOfNull(fi: int, len: int): int { 418 for (let i = fi; i < len; i++) { 419 if (this.$_get_unsafe(i) instanceof null) { 420 return i 421 } 422 } 423 return -1 424 } 425 426 private indexOfString(val: String, fi: int, len: int): int { 427 for (let i = fi; i < len; i++) { 428 const tmp = this.$_get_unsafe(i) 429 if (tmp instanceof String) { 430 if (tmp == val) { 431 return i 432 } 433 } 434 } 435 return -1 436 } 437 438 private indexOfNumber(val: Number, fi: int, len: int): int { 439 const unboxedVal: number = val.valueOf() 440 if (isNaN(val)) { 441 return -1 442 } 443 for (let i = fi; i < len; i++) { 444 const tmp = this.$_get_unsafe(i) 445 if (tmp instanceof Number) { 446 if (unboxedVal == tmp.unboxed()) { 447 return i 448 } 449 } 450 } 451 return -1 452 } 453 454 private indexOfFloat(val: Float, fi: int, len: int): int { 455 const unboxedVal: float = val.unboxed() 456 if (isNaN(val)) { 457 return -1 458 } 459 for (let i = fi; i < len; i++) { 460 const tmp = this.$_get_unsafe(i) 461 if (tmp instanceof Float) { 462 if (unboxedVal == tmp.unboxed()) { 463 return i 464 } 465 } 466 } 467 return -1 468 } 469 470 private indexOfLong(val: Long, fi: int, len: int): int { 471 const unboxedVal: long = val.unboxed() 472 for (let i = fi; i < len; i++) { 473 const tmp = this.$_get_unsafe(i) 474 if (tmp instanceof Long) { 475 if (tmp == unboxedVal) { 476 return i 477 } 478 } 479 } 480 return -1 481 } 482 483 private indexOfInt(val: Int, fi: int, len: int): int { 484 const unboxedVal: int = val.unboxed() 485 for (let i = fi; i < len; i++) { 486 const tmp = this.$_get_unsafe(i) 487 if (tmp instanceof Int) { 488 if (tmp == unboxedVal) { 489 return i 490 } 491 } 492 } 493 return -1 494 } 495 496 private indexOfCommon(val: T, fi: int, len: int): int { 497 for (let i = fi; i < len; i++) { 498 if (val == this.$_get_unsafe(i)) { 499 return i 500 } 501 } 502 return -1 503 } 504 /** 505 * Default comparison function for sort algorithm. 506 * Objects are compared as string. Both objects are convereted to string 507 * using `toString()` method and compared using `compareTo() method of `string` class. 508 * 509 * @param a: Object - Object to be compared 510 * 511 * @param b: Object - Object to be compared 512 * 513 * @returns Returns one of values -1, 0, 1 (_less_, _equal_, _greater_ respectively). 514 */ 515 private static defaultComparator(a: NullishType, b: NullishType): number { 516 if (a instanceof Number && b instanceof Number) { 517 const x = (a as Number).valueOf() 518 const y = (b as Number).valueOf() 519 if (Number.isInteger(x) && Number.isInteger(y) && 520 x <= Int.MAX_VALUE / 128 && x >= Int.MIN_VALUE / 128 && 521 y <= Int.MAX_VALUE / 128 && y >= Int.MIN_VALUE / 128) { 522 let z = x as int 523 let w = y as int 524 return Array.defaultComparatorInts(z, w) 525 } 526 } else if (a instanceof String && b instanceof String) { 527 return a.compareTo(b) 528 } 529 let sa = new String(a) 530 let sb = new String(b) 531 return sa.compareTo(sb) 532 } 533 534 private static defaultComparatorInts(a: int, b: int): number { 535 if (a < 0) { 536 if (b >= 0) { 537 return -1 538 } 539 a *= -1 540 b *= -1 541 } else if (b < 0) { 542 return 1 543 } 544 let aDigs = 1 545 while (10 * aDigs <= a) { 546 aDigs *= 10 547 } 548 let bDigs = 1 549 while (10 * bDigs <= b) { 550 bDigs *= 10 551 } 552 553 while (aDigs > 0 && bDigs > 0) { 554 let r = (a / aDigs) - (b / bDigs) 555 if (r != 0) { 556 return r 557 } 558 aDigs /= 10 559 bDigs /= 10 560 } 561 return (aDigs - bDigs) 562 } 563 564 private static defaultComparatorStr(a: String, b: String) { 565 return a.compareTo(b) 566 } 567 568 /** 569 * Helper function preparing copy of `this` instance of `Array` class' data array. 570 * 571 * @returns Copy of an `Array`'s primitive array data. 572 */ 573 private copyArray(): NullishType[] { 574 let len: int = this.actualLength 575 let res = new NullishType[len] 576 for (let i = 0; i < len; i++) { 577 res[i] = this.$_get_unsafe(i) 578 } 579 return res 580 } 581 582 private wrap_default_sort(): void { 583 let idxNonUndef = 0 584 type arrType = String | null 585 try { 586 let strArr = new arrType[this.actualLength] 587 for (let i = 0; i < this.actualLength; i++) { 588 const vl = this.$_get_unsafe(i) 589 // NOTE(aleksander-sotov) We can't use === to compare with undefined due to 18518 590 if (!__runtimeIsSameReference(vl, undefined)) { 591 if (vl == null) { 592 this.$_set_unsafe(idxNonUndef, vl as T) 593 strArr[idxNonUndef] = "null" 594 } else { 595 this.$_set_unsafe(idxNonUndef, vl) 596 strArr[idxNonUndef] = vl.toString() 597 } 598 idxNonUndef++ 599 } 600 } 601 let sortTo = idxNonUndef 602 for (let i = idxNonUndef; i < this.actualLength; i++) { 603 this.$_set_unsafe(i, undefined as T) 604 } 605 606 sort_default<NullishType>(this.buffer, strArr, 0, sortTo) 607 } 608 catch (e) { 609 if (e instanceof OutOfMemoryError) { 610 this.slow_default_sort() 611 } else { 612 throw e as Error 613 } 614 } 615 } 616 617 private slow_default_sort(): void { 618 let idxNonUndef = 0 619 const cmp: (l: NullishType, r: NullishType) => number = (l: NullishType, r: NullishType): number => { 620 return Array.defaultComparator(l, r) 621 } 622 for (let i = 0; i < this.actualLength; i++) { 623 const vl = this.$_get_unsafe(i) 624 if (!__runtimeIsSameReference(vl, undefined)) { 625 this.$_set_unsafe(idxNonUndef, vl) 626 idxNonUndef++ 627 } 628 } 629 let sortTo = idxNonUndef 630 for (let i = idxNonUndef; i < this.actualLength; i++) { 631 this.$_set_unsafe(i, undefined as T) 632 } 633 sort_stable<NullishType>(this.buffer, 0, sortTo, cmp) 634 } 635 636 /** 637 * Reorders elements of `this` using comparator function. 638 * 639 * @param comparator function that defines the sort order. 640 * 641 * @note Mutating method 642 * 643 * NOTE clarify UTF-16 or UTF-8 644 */ 645 public sort(comparator?: (a: T, b: T) => number): this { 646 let cmp: (l: NullishType, r: NullishType) => number = (l: NullishType, r: NullishType): number => { 647 return Array.defaultComparator(l, r) 648 } 649 let sortTo = this.actualLength 650 if (!__runtimeIsSameReference(comparator, undefined)) { 651 cmp = (l: NullishType, r: NullishType): number => { 652 return comparator!(l as T, r as T) 653 } 654 sort_stable<NullishType>(this.buffer, 0, sortTo, cmp) 655 } else { 656 this.wrap_default_sort() 657 } 658 return this 659 } 660 661 /** 662 * Removes the first element from an array and returns that removed element. 663 * This method changes the length of the array. 664 * 665 * @returns shifted element, i.e. that was at index zero 666 */ 667 public shift(): T | undefined { 668 if(this.actualLength == 0) { 669 return undefined 670 } 671 let obj = this.$_get_unsafe(0) 672 const other = this.slice(1, this.actualLength) 673 this.buffer = other.buffer 674 this.actualLength = other.actualLength 675 return obj 676 } 677 678 /** 679 * Removes the last element from an array and returns that element. 680 * This method changes the length of the array. 681 * 682 * @returns removed element 683 */ 684 public pop(): T | undefined { 685 if(this.actualLength == 0) { 686 return undefined 687 } 688 let obj = this.$_get_unsafe(this.actualLength - 1) 689 this.buffer[this.actualLength - 1] = null 690 this.actualLength-- 691 return obj 692 } 693 694 /** 695 * Adds the specified elements to the end of an array and returns the new length of the array. 696 * 697 * @returns new length 698 */ 699 public push(...val: T[]): number { 700 this.ensureUnusedCapacity(val.length) 701 for (let i = 0; i < val.length; i++) { 702 this.buffer[this.actualLength + i] = val[i] 703 } 704 this.actualLength += val.length 705 return this.actualLength 706 } 707 708 /** 709 * Adds the specified elements to the end of an array and returns the new length of the array. 710 * 711 * @returns new length 712 */ 713 public pushECMA(...val: T[]): number { 714 this.ensureUnusedCapacity(val.length) 715 for (let i = 0; i < val.length; i++) { 716 this.buffer[this.actualLength + i] = val[i] 717 } 718 this.actualLength += val.length 719 return this.actualLength 720 } 721 722 private ensureUnusedCapacity(cap: int): void { 723 if (this.actualLength + cap > this.buffer.length) { 724 const copy = new NullishType[this.buffer.length * 2 + cap] 725 for (let i = 0; i < this.actualLength; i++) { 726 copy[i] = this.buffer[i] 727 } 728 this.buffer = copy 729 } 730 } 731 732 /** 733 * Changes the contents of an array by removing or replacing existing elements 734 * and/or adding new elements in place. 735 * 736 * @param start index 737 * 738 * @param delete number of items after start index 739 * 740 * @returns an Array with deleted elements 741 */ 742 public splice(start: number, delete: Number | undefined, ...items: T[]): Array<T> { 743 return this.splice(start as int, asIntOrDefault(delete, this.actualLength), ...items) 744 } 745 746 /** 747 * Changes the contents of an array by removing or replacing existing elements 748 * and/or adding new elements in place. 749 * 750 * @param start index 751 * 752 * @param delete number of items after start index 753 * 754 * @returns an Array with deleted elements 755 */ 756 public splice(start: int, delete: int, ...items: T[]): Array<T> { 757 start = normalizeIndex(start, this.actualLength) 758 if (delete < 0) { 759 delete = 0 760 } 761 if (start > this.actualLength - delete) { 762 delete = this.actualLength - start 763 } 764 // this: [left middle right], we must replace middle with `items` 765 766 this.ensureUnusedCapacity(items.length - delete) 767 const oldLen = this.actualLength 768 this.actualLength = this.actualLength - delete + items.length 769 770 let ret = new Array<T>(delete) 771 let lastSet = start 772 // left part remains unchanged 773 // copy excluded part 774 for (let i = 0; i < delete; i++) { 775 ret.buffer[i] = this.buffer[start + i] 776 } 777 // move right part to the right of the buffer 778 const rightLen = oldLen - start - delete 779 if (items.length > delete) { 780 for (let i = 0; i < rightLen; i++) { 781 this.buffer[this.actualLength - 1 - i] = this.buffer[oldLen - 1 - i] 782 } 783 } else { 784 for (let i = 0; i < rightLen; i++) { 785 this.buffer[start + items.length + i] = this.buffer[start + delete + i] 786 } 787 } 788 // insert middle part 789 for (let i = 0; i < items.length; i++) { 790 this.buffer[start + i] = items[i] 791 } 792 return ret 793 } 794 795 /** 796 * Changes the contents of an array by removing or replacing existing elements 797 * and/or adding new elements in place. 798 * 799 * @param start index 800 * 801 * @returns an Array with deleted elements from start to the last element of the current instance 802 */ 803 public splice(start: number): Array<T> { 804 return this.splice(start as int) 805 } 806 807 /** 808 * Changes the contents of an array by removing or replacing existing elements 809 * and/or adding new elements in place. 810 * 811 * @param start index 812 * 813 * @returns an Array with deleted elements from start to the last element of the current instance 814 */ 815 public splice(start: int): Array<T> { 816 return this.splice(start, this.actualLength) 817 } 818 819 /** 820 * Checks whether the passed value is an Array. 821 * 822 * @param arr 823 * 824 * @returns true is arr is a non-nullish array, false otherwise 825 */ 826 public static isArray(o: NullishType): boolean { 827 if (o instanceof Array) { 828 return true 829 } 830 return (Type.of(o) instanceof ArrayType) 831 } 832 833 /** 834 * Creates a new Array instance from a variable number of arguments, 835 * regardless of number or type of the arguments. 836 * 837 * @param values an initilizer 838 * 839 * @returns a newly created Array 840 */ 841 public static of<T>(...values: T[]): Array<T> { 842 const ret = new Array<T>() 843 ret.ensureUnusedCapacity(values.length) 844 for (let i = 0; i < values.length; i++) { 845 ret.push(values[i]) 846 } 847 return ret 848 } 849 850 /** 851 * Adds the specified elements to the beginning of an Array 852 * and returns the new length of the Array. 853 * 854 * @param values data to be added 855 * 856 * @returns new length of the Array 857 */ 858 public unshift(...values: T[]): number { 859 let buffer = this.buffer 860 if (this.buffer.length <= values.length + this.actualLength) { 861 buffer = new NullishType[this.buffer.length * 2 + values.length] 862 } 863 for (let i = 0; i < this.actualLength; i++) { 864 buffer[this.actualLength + values.length - i - 1] = this.buffer[this.actualLength - 1 - i] 865 } 866 for (let i = 0; i < values.length; i++) { 867 buffer[i] = values[i] 868 } 869 this.buffer = buffer 870 this.actualLength += values.length 871 return this.actualLength 872 } 873 874 /** 875 * Returns an iterator over all indices 876 */ 877 public override keys(): IterableIterator<Number> { 878 return new ArrayKeysIterator<T>(this) 879 } 880 881 /** 882 * Returns an iterator over all values 883 */ 884 public override $_iterator(): IterableIterator<T> { 885 return this.values() 886 } 887 888 // === methods with uncompatible implementation === 889 /** 890 * Returns the elements of an array that meet the condition specified in a callback function. 891 * 892 * @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. 893 * 894 * @returns New `Array` instance constructed from `this` with elements filtered using test function `predicate`. 895 */ 896 public override filter(predicate: (value: T, index: number) => boolean): Array<T> { 897 const res = new Array<T>() 898 for (let i: int = 0; i < this.actualLength; i++) { 899 const val = this.$_get_unsafe(i) 900 if (predicate(val, i as number)) { 901 res.push(val) 902 } 903 } 904 return res 905 } 906 907 /** 908 * Creates a new Array with all sub-array elements concatenated 909 * into it recursively up to the specified depth. 910 * 911 * @param depth 912 * 913 * @returns a flattened Array with respect to depth 914 */ 915 public flat<U>(depth: number): Array<U> { 916 return this.flat<U>(depth as int) 917 } 918 919 /** 920 * Creates a new Array with all sub-array elements concatenated 921 * into it recursively up to the specified depth. 922 * 923 * @param depth 924 * 925 * @returns a flattened Array with respect to depth 926 */ 927 public flat<U>(depth: int): Array<U> { 928 let ret = new Array<U>() 929 this.flatImpl<U>(depth, ret) 930 return ret 931 } 932 933 private flatImpl<U>(depth: int, to: Array<U>) { 934 throw new Error("not implemented") 935 } 936 937 /** 938 * Creates a new Array with all sub-array elements concatenated 939 * 940 * @returns a flattened Array 941 */ 942 public flat<U>(): Array<U> { 943 return this.flat<U>(1) 944 } 945 946 /** 947 * Applies flat and than map 948 * 949 * fn a function to apply 950 * 951 * @return new Array after map and than flat 952 */ 953 // NOTE(ivan-tyulyandin): TBD, flatMap may be not subset, see ReadonlyArray 954 public flatMap<U>(fn: (v: T, k: number, arr: Array<T>) => U): Array<U> { 955 let mapped: Array<U> = this.map<U>(fn) 956 return mapped.flat<U>() 957 } 958 959 /** 960 * Applies flat and than map 961 * 962 * fn a function to apply 963 * 964 * @return new Array after map and than flat 965 */ 966 // NOTE(ivan-tyulyandin): TBD, flatMap may be not subset, see ReadonlyArray 967 public flatMap<U>(fn: (v: T, k: number) => U): Array<U> { 968 let mapped: Array<U> = this.map<U>(fn) 969 return mapped.flat<U>() 970 } 971 972 /** 973 * Applies flat and than map 974 * 975 * fn a function to apply 976 * 977 * @return new Array after map and than flat 978 */ 979 // NOTE(ivan-tyulyandin): TBD, flatMap may be not subset, see ReadonlyArray 980 public flatMap<U>(fn: (v: T) => U): Array<U> { 981 let mapped: Array<U> = this.map<U>(fn) 982 return mapped.flat<U>() 983 } 984 985 // === methods common among all arrays === 986% require 'ostruct' 987% ctx = OpenStruct.new 988% $ctx = ctx 989% ctx.this = 'this' 990% ctx.this_arg = '' 991% ctx.this_len_int = 'this.actualLength' 992% ctx.array_len_int = Proc.new { |v| "#{v}.actualLength" } 993% ctx.access_public = 'public' 994% ctx.access_private = 'private' 995% ctx.override = 'override' 996% ctx.override_expected_here = '' # hide 'override' when it cannot be implemented 997% ctx.get_unsafe = Proc.new { |t, i| "#{t}.$_get_unsafe(#{i})" } 998% ctx.set_unsafe = Proc.new { |t, i, v| "#{t}.$_set_unsafe(#{i}, #{v})" } 999% ctx.el_type = 'T' 1000% ctx.el_type_boxed = 'T' 1001% ctx.this_type = 'Array<T>' 1002% ctx.this_return_type = 'this' 1003% ctx.clone_this = 'new Array<T>(FROM_BUFFER, this.copyArray())' 1004% ctx.make_buffer = Proc.new { |l, elt| 1005% "new NullishType[#{l}]" 1006% } 1007% ctx.from_buffer = Proc.new { |b, elt| 1008% elt ||= ctx.el_type 1009% "new Array<#{elt}>(FROM_BUFFER, #{b})" 1010% } 1011% ctx.array_of_type = Proc.new { |t| "Array<#{t}>" } 1012% ctx.this_call = Proc.new { |f| "this.#{f}(" } 1013% ctx.arr_method_call = Proc.new { |t, f| "#{t}.#{f}(" } 1014% ctx.this_generic = '' 1015% ctx.this_generic_one = '' 1016% ctx.this_iterator_generic = '<T>' 1017% template = ERB.new(File.read("Array_common.erb"), nil, '%', eoutvar: '_sub01') 1018<%= template.result(ctx.instance_eval { binding }).gsub(/^/, ' ') %> 1019% template = ERB.new(File.read("Array_map.erb"), nil, '%', eoutvar: '_sub02') 1020% ctx.mapped_type = 'U' 1021% ctx.map_generic = '<U>' 1022<%= template.result(ctx.instance_eval { binding }).gsub(/^/, ' ') %> 1023} 1024% template = ERB.new(File.read("Array_common_top_scope.erb"), nil, '%', eoutvar: '_sub03') 1025<%= template.result(ctx.instance_eval { binding }).rstrip %> 1026