@grain/stdlib 0.4.2 → 0.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +1 -1
  3. package/array.gr +200 -89
  4. package/array.md +81 -5
  5. package/buffer.gr +93 -36
  6. package/bytes.gr +10 -10
  7. package/char.gr +112 -56
  8. package/char.md +200 -0
  9. package/float32.gr +120 -4
  10. package/float32.md +315 -0
  11. package/float64.gr +120 -4
  12. package/float64.md +315 -0
  13. package/hash.gr +42 -15
  14. package/hash.md +44 -0
  15. package/int32.gr +370 -75
  16. package/int32.md +833 -0
  17. package/int64.gr +370 -75
  18. package/int64.md +833 -0
  19. package/list.gr +121 -50
  20. package/map.gr +106 -110
  21. package/number.gr +37 -1
  22. package/number.md +66 -0
  23. package/option.gr +260 -53
  24. package/option.md +579 -0
  25. package/package.json +1 -1
  26. package/pervasives.gr +32 -20
  27. package/queue.gr +102 -30
  28. package/queue.md +191 -0
  29. package/range.gr +26 -26
  30. package/range.md +1 -1
  31. package/regex.md +9 -9
  32. package/result.gr +216 -70
  33. package/result.md +446 -0
  34. package/runtime/dataStructures.gr +28 -29
  35. package/runtime/debug.gr +0 -1
  36. package/runtime/equal.gr +37 -16
  37. package/runtime/exception.gr +28 -15
  38. package/runtime/gc.gr +33 -20
  39. package/runtime/malloc.gr +19 -11
  40. package/runtime/numberUtils.gr +208 -103
  41. package/runtime/numbers.gr +217 -118
  42. package/runtime/string.gr +98 -39
  43. package/runtime/stringUtils.gr +176 -0
  44. package/runtime/unsafe/conv.gr +10 -10
  45. package/runtime/unsafe/memory.gr +14 -3
  46. package/runtime/unsafe/printWasm.gr +4 -4
  47. package/runtime/unsafe/tags.gr +2 -2
  48. package/runtime/unsafe/wasmf32.gr +9 -2
  49. package/runtime/unsafe/wasmf64.gr +9 -2
  50. package/runtime/unsafe/wasmi32.gr +65 -47
  51. package/runtime/unsafe/wasmi64.gr +78 -50
  52. package/runtime/wasi.gr +199 -45
  53. package/set.gr +281 -119
  54. package/set.md +502 -0
  55. package/stack.gr +26 -26
  56. package/string.gr +657 -341
  57. package/string.md +815 -0
  58. package/sys/file.gr +356 -177
  59. package/sys/process.gr +10 -6
  60. package/sys/random.gr +3 -6
  61. package/sys/time.gr +3 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # Changelog
2
2
 
3
+ ### [0.4.6](https://www.github.com/grain-lang/grain/compare/stdlib-v0.4.5...stdlib-v0.4.6) (2022-01-17)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **grainfmt:** Indent function application args when adding parens ([#1095](https://www.github.com/grain-lang/grain/issues/1095)) ([64af7d3](https://www.github.com/grain-lang/grain/commit/64af7d387dca2fddb9b3d190ccdf5790ec3d8e65))
9
+
10
+ ### [0.4.5](https://www.github.com/grain-lang/grain/compare/stdlib-v0.4.4...stdlib-v0.4.5) (2021-12-31)
11
+
12
+
13
+ ### Features
14
+
15
+ * **stdlib:** Add sign function to Number module ([#1079](https://www.github.com/grain-lang/grain/issues/1079)) ([b6483d5](https://www.github.com/grain-lang/grain/commit/b6483d5046cd1b6b89a717a925594d3b20b05837))
16
+
17
+ ### [0.4.4](https://www.github.com/grain-lang/grain/compare/stdlib-v0.4.3...stdlib-v0.4.4) (2021-12-11)
18
+
19
+
20
+ ### Features
21
+
22
+ * **stdlib:** Add reverse function to String module ([#1027](https://www.github.com/grain-lang/grain/issues/1027)) ([df761db](https://www.github.com/grain-lang/grain/commit/df761db55b3e14e31190090ae008ce5047135c09))
23
+ * **stdlib:** Add rotate function in Array module ([#838](https://www.github.com/grain-lang/grain/issues/838)) ([98fc577](https://www.github.com/grain-lang/grain/commit/98fc577ee754317cd2421bfaa8e3c1e049488949))
24
+ * **stdlib:** Add sort function to Array module ([#1012](https://www.github.com/grain-lang/grain/issues/1012)) ([9091930](https://www.github.com/grain-lang/grain/commit/9091930344224925bb7b2e1ef6f879c79a5c2f62))
25
+ * **stdlib:** Implement List.sort via mergesort ([#1014](https://www.github.com/grain-lang/grain/issues/1014)) ([a076e20](https://www.github.com/grain-lang/grain/commit/a076e200013114ccf16c2e6cbe814af1ec09c1ce))
26
+ * **stdlib:** Number.parseInt ([#1051](https://www.github.com/grain-lang/grain/issues/1051)) ([abafb58](https://www.github.com/grain-lang/grain/commit/abafb587e54219a32ed77ba09863bb2d6a80bac8))
27
+
28
+
29
+ ### Bug Fixes
30
+
31
+ * **graindoc:** Ensure value_description is resolved to outcome before printing ([#1070](https://www.github.com/grain-lang/grain/issues/1070)) ([5eb05cc](https://www.github.com/grain-lang/grain/commit/5eb05cc2dedc3b933e194be86dd5d3c3656d6490))
32
+ * **stdlib:** Add bounds checking to Buffer addStringSlice & addBytesSlice ([#1065](https://www.github.com/grain-lang/grain/issues/1065)) ([06fe512](https://www.github.com/grain-lang/grain/commit/06fe512e863aeeb855ccf3e3b83bcd3bc8854723))
33
+ * **stdlib:** Fix String.encode GC ([#1067](https://www.github.com/grain-lang/grain/issues/1067)) ([0ab38c9](https://www.github.com/grain-lang/grain/commit/0ab38c9f4aa0ee84688ba5c6bec1521b380d38b1))
34
+ * **stdlib:** Removed memory leak in Hash module ([#1045](https://www.github.com/grain-lang/grain/issues/1045)) ([01a81c6](https://www.github.com/grain-lang/grain/commit/01a81c6a2573cca94b2d57d0fc70693d39f810a1))
35
+ * **stdlib:** Removed memory leaks in Buffer module ([#1047](https://www.github.com/grain-lang/grain/issues/1047)) ([d33017b](https://www.github.com/grain-lang/grain/commit/d33017b37e988d3facbca2e30e3de4fb8c7b5b8a))
36
+ * **stdlib:** Support arrays of any type in Array rotate ([#1048](https://www.github.com/grain-lang/grain/issues/1048)) ([3ceb1cf](https://www.github.com/grain-lang/grain/commit/3ceb1cf04c1604f49077e8733dcccb6cdaaf9f3a))
37
+ * **stdlib:** Support empty arrays in Array rotate ([3ceb1cf](https://www.github.com/grain-lang/grain/commit/3ceb1cf04c1604f49077e8733dcccb6cdaaf9f3a))
38
+
39
+ ### [0.4.3](https://www.github.com/grain-lang/grain/compare/stdlib-v0.4.2...stdlib-v0.4.3) (2021-10-27)
40
+
41
+
42
+ ### Features
43
+
44
+ * **stdlib:** Add cycle function to Array module ([#993](https://www.github.com/grain-lang/grain/issues/993)) ([c595622](https://www.github.com/grain-lang/grain/commit/c595622b28366655dfd5447270e8f9fc3f988a67))
45
+
46
+
47
+ ### Bug Fixes
48
+
49
+ * **compiler:** Ensure TExpApp is always expansive in Grain ([ef0a69f](https://www.github.com/grain-lang/grain/commit/ef0a69fb4418d318b3227e5db7e743a026762274))
50
+ * **compiler:** Handle let-mut value restriction, such that mutable lets are always expansive ([ef0a69f](https://www.github.com/grain-lang/grain/commit/ef0a69fb4418d318b3227e5db7e743a026762274))
51
+ * **compiler:** Properly handle value restriction on function application & mutable vars ([#988](https://www.github.com/grain-lang/grain/issues/988)) ([ef0a69f](https://www.github.com/grain-lang/grain/commit/ef0a69fb4418d318b3227e5db7e743a026762274))
52
+ * **runtime:** Add types to boxed GC functions to avoid weak type errors ([ef0a69f](https://www.github.com/grain-lang/grain/commit/ef0a69fb4418d318b3227e5db7e743a026762274))
53
+ * **stdlib:** Fixed memory leak in String.explode ([#1001](https://www.github.com/grain-lang/grain/issues/1001)) ([c479a05](https://www.github.com/grain-lang/grain/commit/c479a05f48abcc4c9e98d5cf0ba698230d41031b))
54
+
3
55
  ### [0.4.2](https://www.github.com/grain-lang/grain/compare/stdlib-v0.4.1...stdlib-v0.4.2) (2021-10-11)
4
56
 
5
57
 
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017-2021 Oscar Spencer <oscar@grain-lang.org> and Philip Blair <philip@grain-lang.org>
3
+ Copyright (c) 2017-2022 Oscar Spencer <oscar@grain-lang.org> and Philip Blair <philip@grain-lang.org>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/array.gr CHANGED
@@ -30,7 +30,7 @@ let initPtr = () => {
30
30
  initPtr()
31
31
 
32
32
  @disableGC
33
- let initLength = (length) => {
33
+ let initLength = length => {
34
34
  let length = WasmI32.fromGrain(length)
35
35
  if (WasmI32.eqz(WasmI32.and(length, 1n))) {
36
36
  throw Exception.InvalidArgument("Length argument must be an integer")
@@ -51,8 +51,8 @@ let initLength = (length) => {
51
51
  * @since v0.1.0
52
52
  */
53
53
  @disableGC
54
- export let rec length = (array) => {
55
- let ptr = WasmI32.fromGrain(array: Array<a>)
54
+ export let rec length = array => {
55
+ let ptr = WasmI32.fromGrain(array: (Array<a>))
56
56
  let ret = tagSimpleNumber(WasmI32.load(ptr, _ARRAY_LENGTH_OFFSET))
57
57
  Memory.decRef(ptr)
58
58
  Memory.decRef(WasmI32.fromGrain(length))
@@ -73,13 +73,21 @@ export let rec length = (array) => {
73
73
  * @since v0.1.0
74
74
  */
75
75
  @disableGC
76
- export let rec make /*: (Number, a) -> Array<a>*/ = (length: Number, item: a) => {
76
+ export let rec make /*: (Number, a) -> Array<a>*/ =
77
+ (
78
+ length: Number,
79
+ item: a,
80
+ ) => {
77
81
  let lengthArg = length
78
82
  let length = initLength(length)
79
83
  let byteLength = WasmI32.mul(length, 4n)
80
84
  let array = allocateArray(length)
81
85
  for (let mut i = 0n; WasmI32.ltS(i, byteLength); i = WasmI32.add(i, 4n)) {
82
- WasmI32.store(WasmI32.add(array, i), Memory.incRef(WasmI32.fromGrain(item)), _ARRAY_START_OFFSET)
86
+ WasmI32.store(
87
+ WasmI32.add(array, i),
88
+ Memory.incRef(WasmI32.fromGrain(item)),
89
+ _ARRAY_START_OFFSET
90
+ )
83
91
  }
84
92
  let ret = WasmI32.toGrain(array): (Array<a>)
85
93
  Memory.decRef(WasmI32.fromGrain(lengthArg))
@@ -102,16 +110,24 @@ export let rec make /*: (Number, a) -> Array<a>*/ = (length: Number, item: a) =
102
110
  * @since v0.1.0
103
111
  */
104
112
  @disableGC
105
- export let rec init /*: (Number, Number -> a) -> Array<a>*/ = (length: Number, fn: Number -> a) => {
113
+ export let rec init /*: (Number, Number -> a) -> Array<a>*/ =
114
+ (
115
+ length: Number,
116
+ fn: Number -> a,
117
+ ) => {
106
118
  let length = initLength(length)
107
119
  let byteLength = WasmI32.mul(length, 4n)
108
120
  let array = allocateArray(length)
109
121
  let mut index = 0n
110
122
  for (let mut i = 0n; WasmI32.ltS(i, byteLength); i = WasmI32.add(i, 4n)) {
111
- Memory.incRef(WasmI32.fromGrain(fn));
123
+ Memory.incRef(WasmI32.fromGrain(fn))
112
124
  // [FIXME] This line fails the array/map test suite (#815)
113
125
  //assert !WasmI32.eqz(WasmI32.and(WasmI32.fromGrain(index), 1n)) // must be a simple int for next line to be correct
114
- WasmI32.store(WasmI32.add(array, i), WasmI32.fromGrain(fn(tagSimpleNumber(index))), _ARRAY_START_OFFSET)
126
+ WasmI32.store(
127
+ WasmI32.add(array, i),
128
+ WasmI32.fromGrain(fn(tagSimpleNumber(index))),
129
+ _ARRAY_START_OFFSET
130
+ )
115
131
  //WasmI32.store(WasmI32.add(array, i), WasmI32.fromGrain(4), _ARRAY_START_OFFSET)
116
132
  index = WasmI32.add(index, 1n)
117
133
  }
@@ -186,29 +202,29 @@ export let append = (array1, array2) => {
186
202
  *
187
203
  * @since v0.1.0
188
204
  */
189
- export let concat = (arrays) => {
205
+ export let concat = arrays => {
190
206
  // This function is slightly verbose to avoid depending on the List stdlib.
191
207
 
192
208
  let rec findLength = (arrays, acc) => {
193
209
  match (arrays) {
194
210
  [fst, ...rest] => findLength(rest, acc + length(fst)),
195
- [] => acc
211
+ [] => acc,
196
212
  }
197
213
  }
198
214
 
199
215
  let mut offset = 0
200
216
  let mut arrs = arrays
201
217
 
202
- let rec next = (index) => {
218
+ let rec next = index => {
203
219
  let array = match (arrs) {
204
220
  [fst, ..._] => fst,
205
- [] => fail "end of arrays list"
221
+ [] => fail "end of arrays list",
206
222
  }
207
223
  if (index - offset == length(array)) {
208
224
  offset += length(array)
209
225
  arrs = match (arrs) {
210
226
  [_, ...rest] => rest,
211
- [] => fail "end of arrays list"
227
+ [] => fail "end of arrays list",
212
228
  }
213
229
  next(index)
214
230
  } else {
@@ -228,10 +244,28 @@ export let concat = (arrays) => {
228
244
  *
229
245
  * @since v0.1.0
230
246
  */
231
- export let copy = (array) => {
247
+ export let copy = array => {
232
248
  init(length(array), n => array[n])
233
249
  }
234
250
 
251
+ /**
252
+ * Iterates an array a given number of times, calling an iterator function on each element.
253
+ *
254
+ * @param fn: The iterator function to call with each element
255
+ * @param n: The number of times to iterate the given array
256
+ * @param array: The array to iterate
257
+ *
258
+ * @since v0.4.4
259
+ */
260
+ export let cycle = (fn, n, array) => {
261
+ let length = length(array)
262
+ for (let mut iteration = 0; iteration < n; iteration += 1) {
263
+ for (let mut count = 0; count < length; count += 1) {
264
+ fn(array[count]): Void
265
+ }
266
+ }
267
+ }
268
+
235
269
  /**
236
270
  * Iterates an array, calling an iterator function on each element.
237
271
  *
@@ -243,10 +277,8 @@ export let copy = (array) => {
243
277
  */
244
278
  export let forEach = (fn, array) => {
245
279
  let length = length(array)
246
- let mut count = 0
247
- while (count < length) {
280
+ for (let mut count = 0; count < length; count += 1) {
248
281
  fn(array[count]): Void
249
- count = incr(count)
250
282
  }
251
283
  }
252
284
 
@@ -262,10 +294,8 @@ export let forEach = (fn, array) => {
262
294
  */
263
295
  export let forEachi = (fn, array) => {
264
296
  let length = length(array)
265
- let mut count = 0
266
- while (count < length) {
267
- fn(array[count], count): (Void)
268
- count = incr(count)
297
+ for (let mut count = 0; count < length; count += 1) {
298
+ fn(array[count], count): Void
269
299
  }
270
300
  }
271
301
 
@@ -282,7 +312,7 @@ export let forEachi = (fn, array) => {
282
312
  */
283
313
  export let map = (fn, array) => {
284
314
  let length = length(array)
285
- init(length, (i) => {
315
+ init(length, i => {
286
316
  fn(array[i])
287
317
  })
288
318
  }
@@ -299,7 +329,7 @@ export let map = (fn, array) => {
299
329
  */
300
330
  export let mapi = (fn, array) => {
301
331
  let length = length(array)
302
- init(length, (index) => {
332
+ init(length, index => {
303
333
  fn(array[index], index)
304
334
  })
305
335
  }
@@ -324,7 +354,7 @@ export let mapi = (fn, array) => {
324
354
  */
325
355
  export let reduce = (fn, initial, array) => {
326
356
  let mut acc = initial
327
- forEach((el) => acc = fn(acc, el), array)
357
+ forEach(el => acc = fn(acc, el), array)
328
358
  acc
329
359
  }
330
360
 
@@ -378,7 +408,9 @@ export let flatMap = (fn, array) => {
378
408
  * @since v0.3.0
379
409
  */
380
410
  export let every = (fn, array) => {
381
- reduce((acc, value) => { acc && fn(value) }, true, array)
411
+ reduce((acc, value) => {
412
+ acc && fn(value)
413
+ }, true, array)
382
414
  }
383
415
 
384
416
  /**
@@ -392,7 +424,9 @@ export let every = (fn, array) => {
392
424
  * @since v0.3.0
393
425
  */
394
426
  export let some = (fn, array) => {
395
- reduce((acc, value) => { acc || fn(value) }, false, array)
427
+ reduce((acc, value) => {
428
+ acc || fn(value)
429
+ }, false, array)
396
430
  }
397
431
 
398
432
  /**
@@ -435,9 +469,12 @@ export let fillRange = (value, start, stop, array) => {
435
469
  }
436
470
 
437
471
  let mut index = startIndex
438
- while (index < stopIndex && index < length) {
439
- array[index] = value
472
+ for (
473
+ let mut index = startIndex;
474
+ index < stopIndex && index < length;
440
475
  index += 1
476
+ ) {
477
+ array[index] = value
441
478
  }
442
479
  void
443
480
  }
@@ -450,9 +487,9 @@ export let fillRange = (value, start, stop, array) => {
450
487
  *
451
488
  * @since v0.4.0
452
489
  */
453
- export let reverse = (array) => {
490
+ export let reverse = array => {
454
491
  let len = length(array)
455
- init(len, (index) => {
492
+ init(len, index => {
456
493
  let last = len - index - 1
457
494
  array[last]
458
495
  })
@@ -466,7 +503,7 @@ export let reverse = (array) => {
466
503
  *
467
504
  * @since v0.1.0
468
505
  */
469
- export let toList = (array) => {
506
+ export let toList = array => {
470
507
  let rec buildList = (acc, index) => {
471
508
  let index = index - 1
472
509
  if (index < 0) {
@@ -486,22 +523,22 @@ export let toList = (array) => {
486
523
  *
487
524
  * @since v0.1.0
488
525
  */
489
- export let fromList = (list) => {
526
+ export let fromList = list => {
490
527
  let rec listLength = (list, acc) => {
491
528
  match (list) {
492
529
  [_, ...rest] => listLength(rest, acc + 1),
493
- [] => acc
530
+ [] => acc,
494
531
  }
495
532
  }
496
533
 
497
534
  let mut lst = list
498
- let rec next = (index) => {
535
+ let rec next = index => {
499
536
  match (lst) {
500
537
  [fst, ...rest] => {
501
538
  lst = rest
502
539
  fst
503
540
  },
504
- [] => next(index)
541
+ [] => next(index),
505
542
  }
506
543
  }
507
544
  init(listLength(list, 0), next)
@@ -520,11 +557,9 @@ export let fromList = (list) => {
520
557
  export let contains = (search, array) => {
521
558
  // TODO: This should use recursion when we can pattern match arrays
522
559
  let len = length(array)
523
- let mut index = 0
524
560
  let mut found = false
525
- while ((!found) && (index < len)) {
526
- found = (array[index] == search)
527
- index += 1
561
+ for (let mut index = 0; !found && index < len; index += 1) {
562
+ found = array[index] == search
528
563
  }
529
564
  found
530
565
  }
@@ -540,22 +575,22 @@ export let contains = (search, array) => {
540
575
  */
541
576
  export let find = (fn, array) => {
542
577
  let length = length(array)
543
- if(length == 0){
578
+ if (length == 0) {
544
579
  None
545
580
  } else {
546
581
  let mut count = 0
547
582
  let mut matching = false
548
583
  let mut matchedItem = array[0]
549
584
  while (count < length) {
550
- if(fn(array[count])) {
585
+ if (fn(array[count])) {
551
586
  matching = true
552
587
  matchedItem = array[count]
553
588
  count = length
554
589
  } else {
555
- count = incr(count)
590
+ count += 1
556
591
  }
557
592
  }
558
- if(!matching) {
593
+ if (!matching) {
559
594
  None
560
595
  } else {
561
596
  Some(matchedItem)
@@ -574,22 +609,22 @@ export let find = (fn, array) => {
574
609
  */
575
610
  export let findIndex = (fn, array) => {
576
611
  let length = length(array)
577
- if(length == 0){
612
+ if (length == 0) {
578
613
  None
579
614
  } else {
580
615
  let mut count = 0
581
616
  let mut matching = false
582
617
  let mut matchedIndex = 0
583
618
  while (count < length) {
584
- if(fn(array[count])) {
619
+ if (fn(array[count])) {
585
620
  matching = true
586
621
  matchedIndex = count
587
622
  count = length
588
623
  } else {
589
- count = incr(count)
624
+ count += 1
590
625
  }
591
626
  }
592
- if(!matching) {
627
+ if (!matching) {
593
628
  None
594
629
  } else {
595
630
  Some(matchedIndex)
@@ -613,8 +648,8 @@ export let product = (array1: Array<a>, array2: Array<b>) => {
613
648
  let mut indexA = -1
614
649
 
615
650
  init(lenA * lenB, n => {
616
- if(n % lenB == 0){
617
- indexA = incr(indexA)
651
+ if (n % lenB == 0) {
652
+ indexA += 1
618
653
  } else {
619
654
  indexA = indexA
620
655
  }
@@ -635,12 +670,9 @@ export let count = (fn, array) => {
635
670
  let length = length(array)
636
671
  let mut position = 0
637
672
  let mut count = 0
638
- while (position < length) {
639
- if(fn(array[position])) {
640
- count = incr(count)
641
- position = incr(position)
642
- } else {
643
- position = incr(position)
673
+ for (let mut position = 0; position < length; position += 1) {
674
+ if (fn(array[position])) {
675
+ count += 1
644
676
  }
645
677
  }
646
678
  count
@@ -658,14 +690,10 @@ export let count = (fn, array) => {
658
690
  */
659
691
  export let counti = (fn, array) => {
660
692
  let length = length(array)
661
- let mut position = 0
662
693
  let mut count = 0
663
- while (position < length) {
664
- if(fn(array[position], position)) {
665
- count = incr(count)
666
- position = incr(position)
667
- } else {
668
- position = incr(position)
694
+ for (let mut position = 0; position < length; position += 1) {
695
+ if (fn(array[position], position)) {
696
+ count += 1
669
697
  }
670
698
  }
671
699
  count
@@ -685,13 +713,13 @@ export let counti = (fn, array) => {
685
713
  export let filter = (fn, array) => {
686
714
  let filtered = copy(array)
687
715
  let mut position = 0
688
- forEach((el) => {
716
+ forEach(el => {
689
717
  if (fn(el)) {
690
718
  filtered[position] = el
691
- position = incr(position)
719
+ position += 1
692
720
  }
693
721
  }, array)
694
- init(position, (index) => {
722
+ init(position, index => {
695
723
  filtered[index]
696
724
  })
697
725
  }
@@ -713,10 +741,10 @@ export let filteri = (fn, array) => {
713
741
  forEachi((el, index) => {
714
742
  if (fn(el, index)) {
715
743
  filtered[position] = el
716
- position = incr(position)
744
+ position += 1
717
745
  }
718
746
  }, array)
719
- init(position, (index) => {
747
+ init(position, index => {
720
748
  filtered[index]
721
749
  })
722
750
  }
@@ -730,11 +758,9 @@ export let filteri = (fn, array) => {
730
758
  *
731
759
  * @since v0.3.0
732
760
  */
733
- export let unique = (array) => {
734
- filteri(
735
- (el, index) => findIndex(value => value == el, array) == Some(index),
736
- array
737
- )
761
+ export let unique = array => {
762
+ filteri((el, index) =>
763
+ findIndex(value => value == el, array) == Some(index), array)
738
764
  }
739
765
 
740
766
  /**
@@ -769,15 +795,17 @@ export let zip = (array1: Array<a>, array2: Array<b>) => {
769
795
  *
770
796
  * @since v0.4.0
771
797
  */
772
- export let unzip = (array) => {
798
+ export let unzip = array => {
773
799
  let lenArr = length(array)
774
800
 
775
801
  let a = init(lenArr, n => {
776
- let (fst, _) = array[n]; fst
802
+ let (fst, _) = array[n]
803
+ fst
777
804
  })
778
805
 
779
806
  let b = init(lenArr, n => {
780
- let (_, snd) = array[n]; snd
807
+ let (_, snd) = array[n]
808
+ snd
781
809
  })
782
810
 
783
811
  (a, b)
@@ -796,15 +824,27 @@ export let join = (separator: String, items: Array<String>) => {
796
824
  let iter = (acc, str) => {
797
825
  match (acc) {
798
826
  None => Some(str),
799
- Some(prev) => Some(prev ++ separator ++ str)
827
+ Some(prev) => Some(prev ++ separator ++ str),
800
828
  }
801
829
  }
802
- match(reduce(iter, None, items)) {
830
+ match (reduce(iter, None, items)) {
803
831
  None => "",
804
832
  Some(s) => s,
805
833
  }
806
834
  }
807
835
 
836
+ /**
837
+ * A simple helper function to convert a negative array index
838
+ * number to its positive positional equivalent.
839
+ */
840
+ let wrapNegativeIndex = (arrLen, idx) => {
841
+ if (idx >= 0) {
842
+ idx
843
+ } else {
844
+ arrLen + idx
845
+ }
846
+ }
847
+
808
848
  /**
809
849
  * Slices an array given zero-based start and end indexes. The value
810
850
  * at the end index will not be included in the result.
@@ -821,17 +861,8 @@ export let join = (separator: String, items: Array<String>) => {
821
861
  */
822
862
  export let slice = (startIndex, endIndex, array) => {
823
863
  let arrayLength = length(array)
824
-
825
- let wrapNegativeIndex = idx => {
826
- if (idx >= 0) {
827
- idx
828
- } else {
829
- arrayLength + idx
830
- }
831
- }
832
-
833
- let startIndex = wrapNegativeIndex(startIndex)
834
- let endIndex = wrapNegativeIndex(endIndex)
864
+ let startIndex = wrapNegativeIndex(arrayLength, startIndex)
865
+ let endIndex = wrapNegativeIndex(arrayLength, endIndex)
835
866
  // Ensure we aren't working with an `end` value that is too big
836
867
  let endIndex = if (endIndex > arrayLength) {
837
868
  arrayLength
@@ -839,7 +870,7 @@ export let slice = (startIndex, endIndex, array) => {
839
870
  endIndex
840
871
  }
841
872
 
842
- let newLength = endIndex - startIndex;
873
+ let newLength = endIndex - startIndex
843
874
  if (newLength < 0) {
844
875
  [>]
845
876
  } else if (newLength > arrayLength) {
@@ -848,3 +879,83 @@ export let slice = (startIndex, endIndex, array) => {
848
879
  init(newLength, n => array[startIndex + n])
849
880
  }
850
881
  }
882
+
883
+ /**
884
+ * Sorts an array in-place.
885
+ *
886
+ * Ordering is calculated using a comparator function which takes two array elements and must return 0 if both are equal, a positive number if the first is greater, and a negative number if the first is smaller.
887
+ * @param comp: The comparator function used to indicate sort order
888
+ * @param array: The array to be sorted
889
+ * @since v0.4.5
890
+ */
891
+ export let sort = (comp, array) => {
892
+ let partition = (low, high) => {
893
+ let pivot = array[high]
894
+ let mut i = low - 1
895
+ for (let mut j = low; j < high; j += 1) {
896
+ if (comp(array[j], pivot) < 0) {
897
+ i += 1
898
+ let temp = array[i]
899
+ array[i] = array[j]
900
+ array[j] = temp
901
+ }
902
+ }
903
+ let temp = array[i + 1]
904
+ array[i + 1] = array[high]
905
+ array[high] = temp
906
+ i + 1
907
+ }
908
+ let rec quicksort = (low, high) => {
909
+ if (low < high) {
910
+ let partitionIndex = partition(low, high)
911
+ quicksort(partitionIndex + 1, high)
912
+ quicksort(low, partitionIndex - 1)
913
+ }
914
+ }
915
+ let len = length(array)
916
+ quicksort(0, len - 1)
917
+ }
918
+
919
+ /**
920
+ * Rotates an array by n elements to the right, in place.
921
+ *
922
+ * If n is negative, the array will be rotated by n elements
923
+ * to the left. See examples.
924
+ *
925
+ * @param n: The number of elements to rotate by
926
+ * @param arr: The array to be rotated
927
+ *
928
+ * @example let array = [> 1, 2, 3, 4, 5]; rotate(2, arr); arr == [> 4, 5, 1, 2, 3]
929
+ * @example let array = [> 1, 2, 3, 4, 5]; rotate(-1, arr); arr == [> 2, 3, 4, 5, 1]
930
+ * @since v0.4.5
931
+ */
932
+ export let rotate = (n, arr) => {
933
+ let rec gcd = (a, b) => {
934
+ if (b == 0) {
935
+ a
936
+ } else {
937
+ gcd(b, a % b)
938
+ }
939
+ }
940
+
941
+ let arrLen = length(arr)
942
+ if (arrLen > 0) {
943
+ let k = n % arrLen
944
+ let mut d = -1
945
+ let mut j = 0
946
+ for (let mut i = 0; i < gcd(arrLen, k); i += 1) {
947
+ j = i
948
+ let temp = arr[i]
949
+ while (true) {
950
+ d = (j - k) % arrLen
951
+ if (d == i) {
952
+ break
953
+ }
954
+ let newVal = arr[d]
955
+ arr[j] = newVal
956
+ j = d
957
+ }
958
+ arr[j] = temp
959
+ }
960
+ }
961
+ }