• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 std.core;
17
18// NOTE: autogenerated file
19
20% template = ERB.new(File.read("Array_header.erb"), trim_mode: '%', eoutvar: '_sub04')
21<%= template.result(binding) %>
22
23// Range is [startIndex, endIndex), i.e. startIndex included and endIndex is excluded
24function checkRange(arrLen: int, startIndex: int, endIndex: int): boolean {
25    // Since mostly everywhere for loop is used from startIndex till endIndex exclusive,
26    // startIndex <= endIndex is used to cover empty array case
27    return ((0 <= startIndex) && (startIndex <= endIndex) && (endIndex <= arrLen));
28}
29
30native function __alloc_array<T>(len: int, ofType: Object | null): FixedArray<T>
31
32class BuiltinArrayKeysIterator implements IterableIterator<number> {
33    private len: int
34    private idx: int = 0
35    private isDone: boolean = false
36
37    constructor(len: int) {
38        this.len = len
39    }
40
41    override next(): IteratorResult<number> {
42        if (this.isDone || this.idx >= this.len) {
43            this.isDone = true
44            return new IteratorResult<number>()
45        }
46        return new IteratorResult<number>(this.idx++ as number)
47    }
48
49    override $_iterator(): IterableIterator<number> {
50        return this
51    }
52}
53
54% require 'ostruct'
55% ctx = OpenStruct.new
56% $ctx = ctx
57% ctx.this = 'self'
58% ctx.this_len_int = 'self.length'
59% ctx.array_len_int = Proc.new { |v| "#{v}.length" }
60% ctx.access_public = 'export function'
61% ctx.access_private = 'function'
62% ctx.override = ''
63% ctx.get_unsafe = Proc.new { |t, i| "#{t}[#{i}]" }
64% ctx.set_unsafe = Proc.new { |t, i, v| "#{t}[#{i}] = #{v}" }
65% ctx.arr_method_call = Proc.new { |t, f, *args| "#{f}(#{args.prepend(t).join(', ')})" }
66% primitive_types = ['boolean', 'byte', 'short', 'int', 'long', 'float', 'double', 'char']
67% # NOTE(kprokopenko): primitive_types + ['T']
68% (primitive_types).each { |el_type|
69%   ctx.this_type = "FixedArray<#{el_type}>"
70%   ctx.this_arg = "self: #{ctx.this_type}, "
71%   ctx.this_return_type = ctx.this_type
72%   ctx.el_type = el_type
73%   ctx.el_type_boxed = el_type[0].upcase + el_type[1..]
74%   ctx.clone_this = 'cloneArray(self)'
75%   ctx.make_buffer = Proc.new { |l, elt|
76%     elt ||= ctx.el_type
77%     if elt == 'T'
78%       "__alloc_array<#{elt}>(#{l}, self)"
79%     elsif elt == 'U'
80%       "__alloc_array<#{elt}>(#{l}, null)"
81%     else
82%       "new #{elt}[#{l}]"
83%     end
84%   }
85%   ctx.make_fixed_array = "FixedArray<#{el_type}>"
86%   ctx.from_buffer = Proc.new { |b, elt| b }
87%   ctx.array_of_type = Proc.new { |t| "FixedArray<#{t}>" }
88%   ctx.this_generic = ''
89%   ctx.this_generic_one = ''
90%   ctx.this_iterator_generic = ''
91%   if el_type == 'T'
92%     ctx.this_generic = '<T>'
93%     ctx.this_iterator_generic = '<T>'
94%     ctx.this_generic_one = 'T, '
95%   end
96% ctx.this_call = Proc.new { |f| "#{f}#{ctx.this_generic}(self, " }
97function cloneArray<%= ctx.this_generic %>(self: <%= ctx.this_type %>): <%= ctx.this_type %> {
98    const ret : <%= ctx.make_fixed_array %> = <%= ctx.make_buffer.('self.length') %>;;
99    for (let i = 0; i < self.length; i++) {
100        ret[i] = self[i];
101    }
102    return <%= ctx.from_buffer.('ret') %>;
103}
104% template = ERB.new(File.read("Array_common.erb"), trim_mode: '%', eoutvar: '_sub01')
105<%= template.result(ctx.instance_eval { binding }) %>
106% template = ERB.new(File.read("BuiltinArray.erb"), trim_mode: '%', eoutvar: '_sub02')
107% primitive_types.each { |mapped|
108%   ctx.mapped_type = mapped
109%   ctx.map_generic = ctx.this_generic
110<%# template.result(ctx.instance_eval { binding }) %>
111% }
112
113% ctx.mapped_type = ctx.el_type
114% ctx.map_generic = ctx.this_generic
115<%= template.result(ctx.instance_eval { binding }) %>
116
117% ctx.mapped_type = 'U'
118% ctx.map_generic = "<#{ctx.this_generic_one}U>"
119<%# template.result(ctx.instance_eval { binding }) %>
120
121/**
122 * Constructs a new `Array` instance and populates it with
123 * portion of a given array, filtered down to just the elements from the
124 * given array that pass the test implemented by the provided function.
125 *
126 * @param fn test function, applied to each element of an array.
127 *
128 * @returns New `Array` instance constructed from `this` with elements filtered using test function `fn`.
129 */
130export function filter<%= ctx.this_generic %>(<%= ctx.this_arg %>fn: (v: <%= ctx.el_type %>, k: number, array: <%= ctx.this_type %>) => boolean): <%= ctx.this_type %> {
131    const mask : FixedArray<boolean> = new boolean[<%= ctx.this_len_int %>]
132    let cnt = 0
133
134    for (let i: int = 0; i < <%= ctx.this_len_int %>; i++) {
135        const val = self[i];
136        if (fn(val, i, self)) {
137            mask[i] = true
138            cnt++;
139        }
140    }
141    const res : <%= ctx.make_fixed_array %> = <%= ctx.make_buffer.('cnt') %>;
142    let idx_store = 0;
143    for (let i: int = 0; i < <%= ctx.this_len_int %>; i++) {
144        if (mask[i]) {
145            res[idx_store++] = self[i]
146        }
147    }
148    return <%= ctx.from_buffer.('res') %>;
149}
150
151export function concat<%= ctx.this_generic %>(self: <%= ctx.this_type %>, fst: <%= ctx.this_type %>, ...more: FixedArray<<%= ctx.this_type %>>): <%= ctx.this_type %> {
152    const lnMin = self.length + fst.length;
153    let ln = lnMin;
154    for (let i = 0; i < more.length; i++) {
155        ln += more[i].length
156    }
157    const r : <%= ctx.make_fixed_array %> = <%= ctx.make_buffer.('ln', ctx.el_type) %>;
158    try {
159        copyTo(self, r, 0, 0, self.length);
160        copyTo(fst, r, self.length, 0, fst.length);
161        let idx = lnMin;
162        for (let i = 0; i < more.length; i++) {
163            copyTo(more[i], r, idx, 0, more[i].length);
164            idx += more[i].length;
165        }
166    } catch (e) {
167        // impossible
168    }
169    return <%= ctx.from_buffer.('r') %>
170}
171
172/**
173 * Reorders elements of `this` using comparator function.
174 *
175 * @param comparator function that defines the sort order.
176 *
177 * @note Mutating method
178 */
179export function sort<%= ctx.this_generic %>(<%= ctx.this_arg %>comparator: (a: <%= ctx.el_type %>, b: <%= ctx.el_type %>) => number): <%= ctx.this_return_type %> {
180%   sort_elem_type = ctx.el_type == 'T' ? 'NullishType' : ctx.el_type
181%   from_sort_elem_type = ctx.el_type == 'T' ? ' as T' : ''
182    sort_subarray(self<%= ctx.el_type == 'T' ? ' as FixedArray<NullishType>' : '' %>, 0, self.length, (l: <%= sort_elem_type %>, r: <%= sort_elem_type %>): boolean => {
183        return comparator(l<%= from_sort_elem_type %>, r <%= from_sort_elem_type %>) < 0;
184    });
185    return self;
186}
187
188/**
189 * Reorders elements of `this` using comparator function.
190 *
191 * @param comparator function that defines the sort order.
192 *
193 * @note Mutating method
194 */
195export function sort<%= ctx.this_generic %>(<%= ctx.this_arg.chomp(', ') %>): <%= ctx.this_return_type %> {
196% if !primitive_types.include?(ctx.el_type)
197    sort_subarray(self<%= ctx.el_type == 'T' ? ' as FixedArray<NullishType>' : '' %>, 0, self.length, (l: <%= sort_elem_type %>, r: <%= sort_elem_type %>): boolean => {
198        return new String(l).compareTo(new String(r)) < 0;
199    });
200% else
201    sort(self, 0, self.length);
202% end
203    return self;
204}
205
206export function keys<%= ctx.this_generic %>(self: <%= ctx.this_type %>): IterableIterator<number> {
207    return new BuiltinArrayKeysIterator(self.length);
208}
209
210%   template = ERB.new(File.read("Array_common_top_scope.erb"), trim_mode: '%', eoutvar: '_sub03')
211<%= template.result(ctx.instance_eval { binding }).gsub(/[ \t]+$/, '') %>
212
213% }
214
215function builtin_insertion_sort<T>(arr: FixedArray<T>, startIndex: int, endIndex: int, comp: (lhs: T, rhs: T) => number): void {
216    for (let i = startIndex + 1; i < endIndex; i++) {
217        const tmp = arr[i];
218        if (comp(tmp, arr[startIndex]) as int < 0) {
219            for (let j = i; j > startIndex; j--) {
220                arr[j] = arr[j - 1]
221            }
222            arr[startIndex] = tmp
223        } else {
224            let j = i - 1;
225            while (comp(tmp, arr[j]) as int < 0) {
226                arr[j + 1] = arr[j];
227                j--;
228            }
229            arr[j + 1] = tmp;
230        }
231    }
232}
233
234function perform_merge<T>(arr: FixedArray<T>, startIndex: int, midIndex: int, endIndex: int, comp: (lhs: T, rhs: T) => number): void {
235    const len1 = midIndex - startIndex + 1;
236    const len2 = endIndex - midIndex;
237    let left : FixedArray<T | undefined> = new (T | undefined)[len1];
238    let right : FixedArray<T | undefined> = new (T | undefined)[len2];
239    for (let i = 0; i < len1; i++) {
240        left[i] = arr[startIndex + i];
241    }
242    for (let i = 0; i < len2; i++) {
243        right[i] = arr[midIndex + 1 + i];
244    }
245    let i = 0;
246    let j = 0;
247    let k = startIndex;
248    while (i < len1 && j < len2) {
249        if (comp(left[i]!, right[j]!) as int <= 0) {
250            arr[k] = left[i]!;
251            i++;
252        } else {
253            arr[k] = right[j]!;
254            j++;
255        }
256        k++;
257    }
258    while (i < len1) {
259        arr[k] = left[i]!;
260        k++;
261        i++;
262    }
263    while (j < len2) {
264        arr[k] = right[j]!;
265        k++;
266        j++;
267    }
268}
269
270export function sort_stable<T>(arr: FixedArray<T>, startIndex: int, endIndex: int, comp: (lhs: T, rhs: T) => number): void {
271    if (endIndex <= startIndex) {
272        return;
273    }
274
275    const INS_SORT_DELTA = 16
276    for (let i = startIndex; i < endIndex; i += INS_SORT_DELTA ) {
277        builtin_insertion_sort<T>(arr, i, min(i + INS_SORT_DELTA , endIndex), comp)
278    }
279    if ((endIndex - startIndex) < INS_SORT_DELTA) {
280        return;
281    }
282    for (let size = INS_SORT_DELTA; size < endIndex; size = 2 * size) {
283        for (let left = startIndex; left < endIndex; left += 2 * size) {
284
285            // Find ending point of left subarray and right subarray
286            const mid = min(left + size - 1, endIndex - 1);
287            const right = min((left + 2 * size - 1), (endIndex - 1));
288
289            // Merge sub array arr[left.....mid] and arr[mid+1....right]
290            if (mid < right) {
291                perform_merge(arr, left, mid, right, comp);
292            }
293        }
294    }
295}
296
297function defaultComparatorStr(a: String, b: String): number {
298    return a.compareTo(b)
299}
300
301type buffStr = String | undefined
302function stringified_insertion_sort<T>(arr: FixedArray<T>, arrStr: FixedArray<buffStr>, startIndex: int, endIndex: int): void {
303    for (let i = startIndex + 1; i < endIndex; i++) {
304        const tmp = arr[i]
305        const tmpStr = arrStr[i];
306        if (defaultComparatorStr(tmpStr!, arrStr[startIndex]!) < 0) {
307            for (let j = i; j > startIndex; j--) {
308                arr[j] = arr[j - 1]
309                arrStr[j] = arrStr[j - 1]
310            }
311            arrStr[startIndex] = tmpStr
312            arr[startIndex] = tmp
313        } else {
314            let j = i - 1;
315            while (defaultComparatorStr(tmpStr!, arrStr[j]!) < 0) {
316                arr[j + 1] = arr[j];
317                arrStr[j + 1] = arrStr[j]
318                j--;
319            }
320            arr[j + 1] = tmp;
321            arrStr[j + 1] = tmpStr
322        }
323    }
324}
325
326function stringified_perform_merge<T>(arr: FixedArray<T>, arrStr: FixedArray<buffStr>, startIndex: int, midIndex: int, endIndex: int): void {
327    const len1 = midIndex - startIndex + 1;
328    const len2 = endIndex - midIndex;
329    type buffType = T | undefined
330    let left : FixedArray<buffType> = new buffType[len1]
331    let right : FixedArray<buffType> = new buffType[len2]
332    let leftStr : FixedArray<buffStr> = new buffStr[len1]
333    let rightStr : FixedArray<buffStr> = new buffStr[len2]
334    for (let i = 0; i < len1; i++) {
335        left[i] = arr[startIndex + i]
336        leftStr[i] = arrStr[startIndex + i]
337    }
338    for (let i = 0; i < len2; i++) {
339        right[i] = arr[midIndex + 1 + i]
340        rightStr[i] = arrStr[midIndex + 1 + i]
341    }
342    let i = 0;
343    let j = 0;
344    let k = startIndex;
345    while (i < len1 && j < len2) {
346        if (defaultComparatorStr(leftStr[i]!, rightStr[j]!) <= 0) {
347            arr[k] = left[i]!;
348            arrStr[k] = leftStr[i]!;
349            i++;
350        } else {
351            arr[k] = right[j]!;
352            arrStr[k] = rightStr[j]!;
353            j++;
354        }
355        k++;
356    }
357    while (i < len1) {
358        arr[k] = left[i]!;
359        arrStr[k] = leftStr[i]!;
360        k++;
361        i++;
362    }
363    while (j < len2) {
364        arr[k] = right[j]!;
365        arrStr[k] = rightStr[j]!;
366        k++;
367        j++;
368    }
369}
370
371export function sort_default<T>(arr: FixedArray<T>, arrStr: FixedArray<buffStr>, startIndex: int, endIndex: int): void {
372    if (endIndex <= startIndex) {
373        return;
374    }
375    const INS_SORT_DELTA = 16
376    for (let i = startIndex; i < endIndex; i += INS_SORT_DELTA ) {
377        stringified_insertion_sort<T>(arr, arrStr, i, min(i + INS_SORT_DELTA , endIndex))
378    }
379
380    if ((endIndex - startIndex) < INS_SORT_DELTA) {
381        return;
382    }
383    for (let size = INS_SORT_DELTA; size < endIndex; size = 2 * size) {
384        for (let left = startIndex; left < endIndex; left += 2 * size) {
385
386            // Find ending point of left subarray and right subarray
387            const mid = min(left + size - 1, endIndex - 1);
388            const right = min((left + 2 * size - 1), (endIndex - 1));
389
390            // Merge sub array arr[left.....mid] and arr[mid+1....right]
391            if (mid < right) {
392                stringified_perform_merge(arr, arrStr, left, mid, right);
393            }
394        }
395    }
396}
397
398/**
399 * 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.
400 *
401 * @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.
402 *
403 * @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.
404 *
405 * @returns a result after applying callbackfn over all elements of the Array
406 */
407export function reduce<U, T>(self: Array<U>, callbackfn: (previousValue: T, currentValue: U, index: number, array: Array<U>) => T, initialValue: T): T {
408    let acc = initialValue
409    for (let i = 0; i < self.length; i++) {
410        acc = callbackfn(acc, self[i], i as number, self)
411    }
412    return acc
413}
414