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