v2 / vlib / builtin / js / array.js.v
645 lines · 532 sloc · 14.38 KB · 99f141f741b643327a2628963d95998c862c7ed2
Raw
1module builtin
2
3import strings
4/// Internal representation of `array` type. It is used to implement slices and to make slices behave correctly
5/// it simply stores reference to original array and to index them properly it does index array relative to `index_start`.
6
7struct array_buffer {
8 arr JS.Array
9 index_start int
10 len int
11 cap int
12 has_slice bool
13}
14
15fn (mut a array_buffer) make_copy() {
16 if a.index_start != 0 || a.has_slice {
17 mut new_arr := JS.makeEmptyJSArray()
18 for i in 0 .. a.len {
19 #new_arr.push(a.val.get(i))
20
21 mut x := i
22 x = x
23 }
24 new_arr = new_arr
25 #a.val.arr = new_arr
26 #a.val.index_start = new int(0)
27 #a.val.has_slice = new bool(false)
28 }
29}
30
31#array_buffer.prototype.make_copy = function() { return array_buffer_make_copy(this) }
32// TODO(playX): Should this be implemented fully in JS, use generics or just voidptr?
33fn (a array_buffer) get(ix int) voidptr {
34 mut res := unsafe { nil }
35 #res = a.arr[a.index_start.val + ix.val];
36
37 return res
38}
39
40fn (mut a array_buffer) set(ix int, val voidptr) {
41 #a.val.arr[a.val.index_start.valueOf() + ix.valueOf()] = val;
42}
43
44#array_buffer.prototype.get = function(ix) { return array_buffer_get(this,ix);}
45#array_buffer.prototype.set = function(ix,val) { array_buffer_set(this,ix,val); }
46
47struct array {
48pub mut:
49 arr array_buffer
50
51 len int
52 cap int
53}
54
55fn v_sort(mut arr array, comparator fn (voidptr, voidptr) int) {
56 mut need_iter := true
57 for need_iter {
58 need_iter = false
59 for i := 1; i < arr.len; i++ {
60 if comparator(arr[i], arr[i - 1]) != 1 {
61 tmp := arr[i]
62 arr[i] = arr[i - 1]
63 arr[i - 1] = tmp
64 need_iter = true
65 }
66 }
67 }
68}
69
70// trim trims the array length to "index" without modifying the allocated data. If "index" is greater than len nothing will be changed.
71pub fn (mut a array) trim(index int) {
72 if index < a.len {
73 a.len = index
74 }
75}
76
77#function flatIntoArray(target, source, sourceLength, targetIndex, depth) {
78#"use strict";
79#
80#for (var sourceIndex = 0; sourceIndex < sourceLength; ++sourceIndex) {
81#if (sourceIndex in source) {
82#var element = source[sourceIndex];
83#if (depth > 0 && Array.isArray(element))
84#targetIndex = flatIntoArray(target, element, element.length, targetIndex, depth - 1);
85#else {
86#target[targetIndex] = element;
87#++targetIndex;
88#}
89#}
90#}
91#return targetIndex;
92#}
93#function flatArray(target,depth) {
94#var array = target
95#var length = array.length;
96#var depthNum = 1;
97#
98#if (depth !== undefined)
99#depthNum = +depth
100#
101#var result = []
102#
103#flatIntoArray(result, array, length, 0, depthNum);
104#return result;
105#}
106
107@[unsafe]
108pub fn (a array) repeat_to_depth(count int, depth int) array {
109 if count < 0 {
110 panic('array.repeat: count is negative: ${count}')
111 }
112 mut arr := empty_array()
113
114 if a.len > 0 {
115 for _ in 0 .. count {
116 for i in 0 .. a.len {
117 if depth > 0 {
118 // TODO
119 } else {
120 arr.push(a.arr.get(i))
121 }
122 }
123 }
124 }
125 return arr
126}
127
128// last returns the last element of the array.
129pub fn (a array) last() voidptr {
130 mut res := unsafe { nil }
131 #res = a.arr.get(new int(a.len-1));
132
133 return res
134}
135
136fn (a array) get(ix int) voidptr {
137 if ix < 0 || ix >= a.len {
138 return unsafe { nil }
139 }
140 mut result := unsafe { nil }
141 #result = a.arr.get(ix)
142
143 return result
144}
145
146pub fn (a array) repeat(count int) array {
147 unsafe {
148 return a.repeat_to_depth(count, 0)
149 }
150}
151
152#function makeEmptyArray() { return new array(new array_buffer({ arr: [], len: new int(0), index_start: new int(0), cap: new int(0) })); }
153#function makeEmptyJSArray() { return new Array(); }
154
155fn JS.makeEmptyArray() array
156fn JS.makeEmptyJSArray() JS.Array
157fn empty_array() array {
158 return JS.makeEmptyArray()
159}
160
161#function v_clone_for_array_value(value) {
162#if (value instanceof $ref || value instanceof voidptr || typeof value === 'function') return value;
163#return v_clone_value(value);
164#}
165
166fn (a &array) set_len(i int) {
167 #a.arr.arr.length=i
168}
169
170pub fn (mut a array) sort_with_compare(compare voidptr) {
171 #v_sort(a, compare instanceof voidptr ? compare.val : compare)
172}
173
174pub fn (mut a array) sort_with_compare_old(compare voidptr) {
175 #a.val.arr.arr.sort(compare instanceof voidptr ? compare.val : compare)
176}
177
178pub fn (mut a array) sort() {
179 #a.val.arr.arr.sort($sortComparator)
180}
181
182pub fn (a array) index(v string) int {
183 for i in 0 .. a.len {
184 #if (a.arr.get(i).toString() == v.toString())
185
186 {
187 return i
188 }
189 }
190 return -1
191}
192
193pub fn (a array) last_index(v string) int {
194 for i := a.len - 1; i >= 0; i-- {
195 #if (a.arr.get(i).toString() == v.toString())
196
197 {
198 return i
199 }
200 }
201 return -1
202}
203
204pub fn (a array) slice(start int, end int) array {
205 mut result := a
206 #let slice = a.arr.arr.slice(start,end)
207 #result = new array(new array_buffer({arr: a.arr.arr, len: new int(slice.length),cap: new int(slice.length),index_start: new int(start),has_slice: new bool(true)}))
208 #a.arr.has_slice = true
209 //#v_makeSlice(result)
210
211 return result
212}
213
214pub fn (mut a array) insert(i int, val voidptr) {
215 #a.val.arr.make_copy()
216 #a.val.arr.arr.splice(i,0,v_clone_for_array_value(val))
217 #a.val.arr.len.val = a.val.arr.arr.length
218}
219
220pub fn (mut a array) insert_many(i int, val voidptr, size int) {
221 #a.val.arr.make_copy()
222 #a.val.arr.arr.splice(i,0,...val.arr.slice(0,+size).map(v_clone_for_array_value))
223 #a.val.arr.len.val = a.val.arr.arr.length
224}
225
226fn (mut a array) push(val voidptr) {
227 #a.val.arr.make_copy()
228 #if (arguments[2] && arguments[2].valueOf()) {a.val.arr.arr.push(...val.map(v_clone_for_array_value))} else {
229 #a.val.arr.arr.push(v_clone_for_array_value(val))
230 #}
231 #a.val.arr.len.val = a.val.arr.arr.length
232}
233
234fn v_filter(arr array, callback fn (voidptr) bool) array {
235 mut filtered := empty_array()
236
237 for i := 0; i < arr.arr.len; i++ {
238 if callback(arr.arr.get(i)) {
239 filtered.push(arr.arr.get(i))
240 }
241 }
242 return filtered
243}
244
245fn v_map(arr array, callback fn (voidptr) voidptr) array {
246 mut mapped := empty_array()
247
248 for i := 0; i < arr.arr.len; i++ {
249 mapped.push(callback(arr.arr.get(i)))
250 }
251
252 return mapped
253}
254
255struct array_iterator {
256 ix int
257 end int
258 arr JS.Array
259}
260
261#array_iterator.prototype.next = function () {
262#if (this.ix.val < this.end.val) {
263#this.ix.val++;
264#return {done: false, value: this.arr.arr.get(new int(this.ix.val-1))}
265#} else {
266#return {done: true, value: undefined}
267#}
268#}
269#array_iterator.prototype[Symbol.iterator] = function () { return this; }
270
271#array.prototype[Symbol.iterator] = function () { return new array_iterator({ix: new int(0),end: new int(this.arr.len),arr: this}); }
272#array.prototype.entries = function () { let result = []; for (let key = this.arr.index_start.val;key < this.arr.len.val;key++) { result.push([new int(key), this.arr.get(new int(key))]); } return result[Symbol.iterator](); }
273#array.prototype.map = function(callback) { return v_map(this,callback); }
274#array.prototype.filter = function(callback) { return v_filter(this,callback); }
275#Object.defineProperty(array.prototype,'cap',{ get: function () { return this.len; } })
276#array.prototype.any = function (value) {
277#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
278#for (let i = 0;i < this.arr.arr.length;i++)
279#if (val(this.arr.get(i)))
280#return true;
281#
282#return false;
283#}
284
285#array.prototype.all = function (value) {
286#let val ;if (typeof value == 'function') { val = function (x) { return value(x); } } else { val = function (x) { return vEq(x,value); } }
287#for (let i = 0;i < this.arr.arr.length;i++)
288#if (!val(this.arr.get(i)))
289#return false;
290#
291#return true;
292#}
293//#Object.defineProperty(array_buffer.prototype,"len", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } })
294//#Object.defineProperty(array_buffer.prototype,"cap", { get: function() {return new int(this.arr.length);}, set: function(l) { this.arr.length = l.valueOf(); } })
295#
296#
297#function v_makeSlice(array) { Object.defineProperty(array,'len', {get: function() { return this.arr.len; }, set: function(l) { this.arr.len = l; }}) }
298// delete deletes array element at index `i`.
299pub fn (mut a array) delete(i int) {
300 a.delete_many(i, 1)
301}
302
303fn arr_copy(mut dst array, src array, count int) {
304 for i := 0; i < count; i++ {
305 dst.arr.set(i, src.arr.get(i))
306 }
307}
308
309// delete_many deletes `size` elements beginning with index `i`.
310pub fn (mut a array) delete_many(i int, size int) {
311 #a.val.arr.make_copy()
312 #a.val.arr.arr.splice(i.valueOf(),size.valueOf())
313 #a.val.arr.len.val = a.val.arr.arr.length
314}
315
316// prepend prepends one value to the array.
317pub fn (mut a array) prepend(val voidptr) {
318 a.insert(0, val)
319}
320
321// prepend_many prepends another array to this array.
322@[unsafe]
323pub fn (mut a array) prepend_many(val voidptr, size int) {
324 unsafe { a.insert_many(0, val, size) }
325}
326
327pub fn (a array) reverse() array {
328 mut res := empty_array()
329 #res.arr.arr = Array.from(a.arr).reverse()
330
331 return res
332}
333
334pub fn (mut a array) reverse_in_place() {
335 #a.val.arr.arr.reverse()
336}
337
338#array.prototype.$includes = function (elem) { return this.arr.arr.find(function(e) { return vEq(elem,e); }) !== undefined;}
339
340pub fn (mut a array) clear() {
341 #a.val.arr.make_copy()
342 #a.val.arr.arr.length = 0
343 #a.val.arr.len.val = 0
344}
345
346// reduce executes a given reducer function on each element of the array, resulting in a single output value.
347pub fn (a array) reduce(iter fn (int, int) int, accum_start int) int {
348 mut accum_ := accum_start
349 /*#for (let i = 0;i < a.arr.length;i++) {
350 #accum_ = iter(accum_, a.arr[i])
351 #}*/
352 for i in 0 .. a.len {
353 accum_ = iter(accum_, a.get(i))
354 }
355
356 return accum_
357}
358
359pub fn (mut a array) pop() voidptr {
360 mut res := unsafe { nil }
361 #a.val.arr.make_copy()
362 #res = a.val.arr.arr.pop()
363 #a.val.arr.len.val = a.val.arr.arr.length
364
365 return res
366}
367
368pub fn (a array) first() voidptr {
369 mut res := unsafe { nil }
370 #res = a.arr.get(new int(0))
371
372 return res
373}
374
375#array.prototype.toString = function () {
376#let res = "["
377#for (let i = 0; i < this.arr.arr.length;i++) {
378#res += this.arr.get(i).toString();
379#if (i != this.arr.arr.length-1)
380#res += ', '
381#}
382#res += ']'
383#return res;
384#
385#}
386
387pub fn (a array) contains(key voidptr) bool
388
389// delete_last effectively removes last element of an array.
390pub fn (mut a array) delete_last() {
391 #a.val.arr.arr.pop();
392}
393
394@[unsafe]
395pub fn (a &array) free() {
396}
397
398// todo: once (a []u8) will work rewrite this
399pub fn (a array) bytestr() string {
400 res := ''
401 #for (let i = 0;i < a.arr.len.valueOf();i++) res.str += String.fromCharCode(a.arr.get(new int(i)))
402
403 return res
404}
405
406pub fn (a []string) str() string {
407 mut sb := strings.new_builder(a.len * 3)
408 sb.write_string('[')
409 for i in 0 .. a.len {
410 val := a[i]
411 sb.write_string("'")
412 sb.write_string(val)
413 sb.write_string("'")
414 if i < a.len - 1 {
415 sb.write_string(', ')
416 }
417 }
418 sb.write_string(']')
419 res := sb.str()
420 return res
421}
422
423pub fn (a array) to_js_array() JS.Array {
424 tmp := JS.Array.prototype.constructor()
425 for i in 0 .. a.len {
426 tmp.push(a.arr.get(i))
427 }
428 return tmp
429}
430
431pub fn (a array) to_number_array() JS.Array {
432 tmp := JS.Array.prototype.constructor()
433 for i in 0 .. a.len {
434 elem := a.arr.get(i)
435 _ := elem
436 #tmp.push(Number(elem.valueOf()));
437 }
438 return tmp
439}
440
441// push_many - appends multiple values to the end of the array.
442pub fn (mut a array) push_many(val voidptr, size int) {
443 a.insert_many(a.len, val, size)
444}
445
446type EveryFn = fn (JS.Number, JS.Number) JS.Boolean
447
448type BigEveryFn = fn (JS.BigInt, JS.Number) JS.Boolean
449
450pub interface JS.TypedArray {
451mut:
452 byteLength JS.Number
453 byteOffset JS.Number
454 length JS.Number
455}
456
457pub interface JS.Uint8Array {
458 JS.TypedArray
459 at(index JS.Number) JS.Number
460 every(JS.EveryFn) JS.Boolean
461}
462
463pub interface JS.Uint16Array {
464 JS.TypedArray
465 at(index JS.Number) JS.Number
466 every(JS.EveryFn) JS.Boolean
467}
468
469pub interface JS.Uint32Array {
470 JS.TypedArray
471 at(index JS.Number) JS.Number
472 every(JS.EveryFn) JS.Boolean
473}
474
475pub interface JS.BigUint64Array {
476 JS.TypedArray
477 at(index JS.Number) JS.BigInt
478 every(JS.BigEveryFn) JS.Boolean
479}
480
481pub interface JS.Int8Array {
482 JS.TypedArray
483 at(index JS.Number) JS.Number
484 every(JS.EveryFn) JS.Boolean
485}
486
487pub interface JS.Int16Array {
488 JS.TypedArray
489 at(index JS.Number) JS.Number
490 every(JS.EveryFn) JS.Boolean
491}
492
493pub interface JS.Int32Array {
494 JS.TypedArray
495 at(index JS.Number) JS.Number
496 every(JS.EveryFn) JS.Boolean
497}
498
499pub interface JS.BigInt64Array {
500 JS.TypedArray
501 at(index JS.Number) JS.BigInt
502 every(JS.BigEveryFn) JS.Boolean
503}
504
505pub interface JS.Float32Array {
506 JS.TypedArray
507 at(index JS.Number) JS.Number
508 every(JS.EveryFn) JS.Boolean
509}
510
511pub interface JS.Float64Array {
512 JS.TypedArray
513 at(index JS.Number) JS.Number
514 every(JS.EveryFn) JS.Boolean
515}
516
517pub fn uint8_array(arr []u8) JS.Uint8Array {
518 #let tmp = new Array();
519
520 for elem in arr {
521 _ := elem
522 #tmp.push(elem.val)
523 }
524 mut uint_arr := JS.Uint8Array{}
525 #uint_arr = new Uint8Array(tmp)
526
527 return uint_arr
528}
529
530pub fn uint16_array(arr []u16) JS.Uint16Array {
531 #let tmp = new Array();
532
533 for elem in arr {
534 _ := elem
535 #tmp.push(elem.val)
536 }
537 mut uint_arr := JS.Uint16Array{}
538 #uint_arr = new Uint16Array(tmp)
539
540 return uint_arr
541}
542
543pub fn uint32_array(arr []u32) JS.Uint32Array {
544 #let tmp = new Array();
545
546 for elem in arr {
547 _ := elem
548 #tmp.push(elem.val)
549 }
550 mut uint_arr := JS.Uint32Array{}
551 #uint_arr = new Uint32Array(tmp)
552
553 return uint_arr
554}
555
556pub fn int8_array(arr []i8) JS.Int8Array {
557 #let tmp = new Array();
558
559 for elem in arr {
560 _ := elem
561 #tmp.push(elem.val)
562 }
563 mut int_arr := JS.Int8Array{}
564 #int_arr = new Int8Array(tmp)
565
566 return int_arr
567}
568
569pub fn int16_array(arr []i16) JS.Int16Array {
570 #let tmp = new Array();
571
572 for elem in arr {
573 _ := elem
574 #tmp.push(elem.val)
575 }
576 mut int_arr := JS.Int16Array{}
577 #int_arr = new Int16Array(tmp)
578
579 return int_arr
580}
581
582pub fn int32_array(arr []int) JS.Int32Array {
583 #let tmp = new Array();
584
585 for elem in arr {
586 _ := elem
587 #tmp.push(elem.val)
588 }
589 mut int_arr := JS.Int32Array{}
590 #int_arr = new Int32Array(tmp)
591
592 return int_arr
593}
594
595pub fn int64_array(arr []i64) JS.BigInt64Array {
596 #let tmp = new Array();
597
598 for elem in arr {
599 _ := elem
600 #tmp.push(elem.val)
601 }
602 mut int_arr := JS.BigInt64Array{}
603 #int_arr = new BigInt64Array(tmp)
604
605 return int_arr
606}
607
608pub fn uint64_array(arr []u64) JS.BigUint64Array {
609 #let tmp = new Array();
610
611 for elem in arr {
612 _ := elem
613 #tmp.push(elem.val)
614 }
615 mut int_arr := JS.BigUint64Array{}
616 #int_arr = new BigUint64Array(tmp)
617
618 return int_arr
619}
620
621pub fn float32_array(arr []f32) JS.Float32Array {
622 #let tmp = new Array();
623
624 for elem in arr {
625 _ := elem
626 #tmp.push(elem.val)
627 }
628 mut float_arr := JS.Float32Array{}
629 #float_arr = new Float32Array(tmp)
630
631 return float_arr
632}
633
634pub fn float64_array(arr []f64) JS.Float64Array {
635 #let tmp = new Array();
636
637 for elem in arr {
638 _ := elem
639 #tmp.push(elem.val)
640 }
641 mut float_arr := JS.Float64Array{}
642 #float_arr = new Float64Array(tmp)
643
644 return float_arr
645}
646