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