@grain/stdlib 0.5.12 → 0.6.0
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.
- package/CHANGELOG.md +200 -0
- package/LICENSE +1 -1
- package/README.md +25 -2
- package/array.gr +1512 -199
- package/array.md +2032 -94
- package/bigint.gr +239 -140
- package/bigint.md +450 -106
- package/buffer.gr +595 -102
- package/buffer.md +903 -145
- package/bytes.gr +401 -110
- package/bytes.md +551 -63
- package/char.gr +228 -49
- package/char.md +373 -7
- package/exception.gr +26 -12
- package/exception.md +29 -5
- package/float32.gr +130 -109
- package/float32.md +185 -57
- package/float64.gr +112 -99
- package/float64.md +185 -57
- package/hash.gr +47 -37
- package/hash.md +21 -3
- package/int16.gr +430 -0
- package/int16.md +618 -0
- package/int32.gr +200 -269
- package/int32.md +254 -289
- package/int64.gr +142 -225
- package/int64.md +254 -289
- package/int8.gr +511 -0
- package/int8.md +786 -0
- package/json.gr +2084 -0
- package/json.md +608 -0
- package/list.gr +120 -68
- package/list.md +125 -80
- package/map.gr +560 -57
- package/map.md +672 -56
- package/marshal.gr +239 -227
- package/marshal.md +36 -4
- package/number.gr +626 -676
- package/number.md +738 -153
- package/option.gr +33 -35
- package/option.md +58 -42
- package/package.json +2 -2
- package/path.gr +148 -187
- package/path.md +47 -96
- package/pervasives.gr +75 -416
- package/pervasives.md +85 -180
- package/priorityqueue.gr +433 -74
- package/priorityqueue.md +422 -54
- package/queue.gr +362 -80
- package/queue.md +433 -38
- package/random.gr +67 -75
- package/random.md +68 -40
- package/range.gr +135 -63
- package/range.md +198 -43
- package/rational.gr +284 -0
- package/rational.md +545 -0
- package/regex.gr +933 -1066
- package/regex.md +59 -60
- package/result.gr +23 -25
- package/result.md +54 -39
- package/runtime/atof/common.gr +78 -82
- package/runtime/atof/common.md +22 -10
- package/runtime/atof/decimal.gr +102 -127
- package/runtime/atof/decimal.md +28 -7
- package/runtime/atof/lemire.gr +56 -71
- package/runtime/atof/lemire.md +9 -1
- package/runtime/atof/parse.gr +83 -110
- package/runtime/atof/parse.md +12 -2
- package/runtime/atof/slow.gr +28 -35
- package/runtime/atof/slow.md +9 -1
- package/runtime/atof/table.gr +19 -18
- package/runtime/atof/table.md +10 -2
- package/runtime/atoi/parse.gr +153 -136
- package/runtime/atoi/parse.md +50 -1
- package/runtime/bigint.gr +410 -517
- package/runtime/bigint.md +71 -57
- package/runtime/compare.gr +176 -85
- package/runtime/compare.md +31 -1
- package/runtime/dataStructures.gr +144 -32
- package/runtime/dataStructures.md +267 -31
- package/runtime/debugPrint.gr +34 -15
- package/runtime/debugPrint.md +37 -5
- package/runtime/equal.gr +53 -52
- package/runtime/equal.md +30 -1
- package/runtime/exception.gr +38 -47
- package/runtime/exception.md +10 -8
- package/runtime/gc.gr +23 -152
- package/runtime/gc.md +13 -17
- package/runtime/malloc.gr +31 -31
- package/runtime/malloc.md +11 -3
- package/runtime/numberUtils.gr +191 -172
- package/runtime/numberUtils.md +17 -9
- package/runtime/numbers.gr +1695 -1021
- package/runtime/numbers.md +1098 -134
- package/runtime/string.gr +540 -242
- package/runtime/string.md +76 -6
- package/runtime/unsafe/constants.gr +30 -13
- package/runtime/unsafe/constants.md +80 -0
- package/runtime/unsafe/conv.gr +55 -28
- package/runtime/unsafe/conv.md +41 -9
- package/runtime/unsafe/memory.gr +10 -30
- package/runtime/unsafe/memory.md +15 -19
- package/runtime/unsafe/tags.gr +37 -21
- package/runtime/unsafe/tags.md +88 -8
- package/runtime/unsafe/wasmf32.gr +30 -36
- package/runtime/unsafe/wasmf32.md +64 -56
- package/runtime/unsafe/wasmf64.gr +30 -36
- package/runtime/unsafe/wasmf64.md +64 -56
- package/runtime/unsafe/wasmi32.gr +49 -66
- package/runtime/unsafe/wasmi32.md +102 -94
- package/runtime/unsafe/wasmi64.gr +52 -79
- package/runtime/unsafe/wasmi64.md +108 -100
- package/runtime/utils/printing.gr +13 -15
- package/runtime/utils/printing.md +11 -3
- package/runtime/wasi.gr +294 -295
- package/runtime/wasi.md +62 -42
- package/set.gr +574 -64
- package/set.md +634 -54
- package/stack.gr +181 -64
- package/stack.md +271 -42
- package/string.gr +453 -533
- package/string.md +241 -151
- package/uint16.gr +369 -0
- package/uint16.md +585 -0
- package/uint32.gr +470 -0
- package/uint32.md +737 -0
- package/uint64.gr +471 -0
- package/uint64.md +737 -0
- package/uint8.gr +369 -0
- package/uint8.md +585 -0
- package/uri.gr +1093 -0
- package/uri.md +477 -0
- package/{sys → wasi}/file.gr +914 -500
- package/{sys → wasi}/file.md +454 -50
- package/wasi/process.gr +292 -0
- package/{sys → wasi}/process.md +164 -6
- package/wasi/random.gr +77 -0
- package/wasi/random.md +80 -0
- package/{sys → wasi}/time.gr +15 -22
- package/{sys → wasi}/time.md +5 -5
- package/immutablearray.gr +0 -929
- package/immutablearray.md +0 -1038
- package/immutablemap.gr +0 -493
- package/immutablemap.md +0 -479
- package/immutablepriorityqueue.gr +0 -360
- package/immutablepriorityqueue.md +0 -291
- package/immutableset.gr +0 -498
- package/immutableset.md +0 -449
- package/runtime/debug.gr +0 -2
- package/runtime/debug.md +0 -6
- package/runtime/unsafe/errors.gr +0 -36
- package/runtime/unsafe/errors.md +0 -204
- package/sys/process.gr +0 -254
- package/sys/random.gr +0 -79
- package/sys/random.md +0 -66
package/immutablearray.gr
DELETED
|
@@ -1,929 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module ImmutableArray: An immutable array implementation, providing fast arbitrary lookups and modifications.
|
|
3
|
-
*
|
|
4
|
-
* @example import ImmutableArray from "immutablearray"
|
|
5
|
-
*
|
|
6
|
-
* @since v0.6.0
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import List from "list"
|
|
10
|
-
import Array from "array"
|
|
11
|
-
import Set from "set"
|
|
12
|
-
import Buffer from "buffer"
|
|
13
|
-
import Option from "option"
|
|
14
|
-
import Number from "number"
|
|
15
|
-
import Exception from "runtime/exception"
|
|
16
|
-
|
|
17
|
-
// Immutable arrays implemented as relaxed radix balanced trees. This data
|
|
18
|
-
// structure allows access and updating in O(log(n)) time, but since the tree
|
|
19
|
-
// branching factor is chosen to be a large number (32), these operations run
|
|
20
|
-
// in effectively constant time in most practical situations.
|
|
21
|
-
|
|
22
|
-
// This implementation was adapted from Elm's Array module
|
|
23
|
-
// https://github.com/elm/core/blob/master/src/Array.elm
|
|
24
|
-
// license of software used:
|
|
25
|
-
|
|
26
|
-
// Copyright 2014-present Evan Czaplicki
|
|
27
|
-
//
|
|
28
|
-
// Redistribution and use in source and binary forms, with or without
|
|
29
|
-
// modification, are permitted provided that the following conditions are met:
|
|
30
|
-
//
|
|
31
|
-
// 1. Redistributions of source code must retain the above copyright notice,
|
|
32
|
-
// this list of conditions and the following disclaimer.
|
|
33
|
-
//
|
|
34
|
-
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
35
|
-
// this list of conditions and the following disclaimer in the documentation
|
|
36
|
-
// and/or other materials provided with the distribution.
|
|
37
|
-
//
|
|
38
|
-
// 3. Neither the name of the copyright holder nor the names of its
|
|
39
|
-
// contributors may be used to endorse or promote products derived from this
|
|
40
|
-
// software without specific prior written permission.
|
|
41
|
-
//
|
|
42
|
-
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
43
|
-
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
44
|
-
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
45
|
-
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
46
|
-
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
47
|
-
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
48
|
-
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
49
|
-
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
50
|
-
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
51
|
-
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
52
|
-
// POSSIBILITY OF SUCH DAMAGE.
|
|
53
|
-
|
|
54
|
-
// Maximum number of children each tree node can have;
|
|
55
|
-
// an arbitrary multiple of 2 that gives a good performance tradeoff
|
|
56
|
-
let branchingFactor = 32
|
|
57
|
-
// 32 = 2^5
|
|
58
|
-
let branchingBits = 5
|
|
59
|
-
// To be applied to numbers to bring them within the range [0, 32)
|
|
60
|
-
let bitmask = branchingFactor - 1
|
|
61
|
-
|
|
62
|
-
type Tree<a> = Array<Node<a>>,
|
|
63
|
-
enum Node<a> {
|
|
64
|
-
Tree(Tree<a>),
|
|
65
|
-
Leaf(Array<a>),
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// a helper data structure used for building an array piece by piece
|
|
69
|
-
record Builder<a> {
|
|
70
|
-
btail: Array<a>,
|
|
71
|
-
nodes: List<Node<a>>,
|
|
72
|
-
numNodes: Number,
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* @section Types: Type declarations included in the ImmutableArray module.
|
|
77
|
-
*/
|
|
78
|
-
|
|
79
|
-
// A "tail" of < 32 values at the end of the array is kept as a performance
|
|
80
|
-
// optimization
|
|
81
|
-
record ImmutableArray<a> {
|
|
82
|
-
length: Number,
|
|
83
|
-
shift: Number,
|
|
84
|
-
root: Tree<a>,
|
|
85
|
-
tail: Array<a>,
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* @section Values: Functions and constants for working with immutable arrays.
|
|
90
|
-
*/
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* An empty array.
|
|
94
|
-
*
|
|
95
|
-
* @since v0.6.0
|
|
96
|
-
*/
|
|
97
|
-
export let empty = {
|
|
98
|
-
let empty = { length: 0, shift: branchingBits, root: [>], tail: [>] }
|
|
99
|
-
empty
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Determines if the array contains no elements.
|
|
104
|
-
*
|
|
105
|
-
* @param array: The array to check
|
|
106
|
-
* @returns `true` if the array is empty and `false` otherwise
|
|
107
|
-
*
|
|
108
|
-
* @since v0.6.0
|
|
109
|
-
*/
|
|
110
|
-
export let isEmpty = array => array.length == 0
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Provides the length of the input array.
|
|
114
|
-
*
|
|
115
|
-
* @param array: The array to inspect
|
|
116
|
-
* @returns The number of elements in the array
|
|
117
|
-
*
|
|
118
|
-
* @example length(fromList([1, 2, 3, 4, 5])) == 5
|
|
119
|
-
* @since v0.6.0
|
|
120
|
-
*/
|
|
121
|
-
export let length = array => array.length
|
|
122
|
-
|
|
123
|
-
let tailIndex = length => {
|
|
124
|
-
let shiftedRight = length >> branchingBits
|
|
125
|
-
shiftedRight << branchingBits
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
let wrapNegativeIndex = (len, index) => {
|
|
129
|
-
if (index >= 0) index else len + index
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
let arraySetCopy = (index, value, array) => {
|
|
133
|
-
let copy = Array.copy(array)
|
|
134
|
-
copy[index] = value
|
|
135
|
-
copy
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Appends 2 arrays together, truncating to a max size of 32 for storage in
|
|
139
|
-
// a tree node. Also returns number of elements truncated.
|
|
140
|
-
let arrayAppendMax32 = (array1, array2) => {
|
|
141
|
-
let len1 = Array.length(array1)
|
|
142
|
-
let len2 = Array.length(array2)
|
|
143
|
-
|
|
144
|
-
let numToAppend = Number.min(len2, branchingFactor - len1)
|
|
145
|
-
let toAppend = if (numToAppend < len2) {
|
|
146
|
-
Array.slice(0, numToAppend, array2)
|
|
147
|
-
} else {
|
|
148
|
-
array2
|
|
149
|
-
}
|
|
150
|
-
let numNotAppended = len1 + len2 - branchingFactor
|
|
151
|
-
|
|
152
|
-
(Array.append(array1, toAppend), numNotAppended)
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
let log32floor = num => {
|
|
156
|
-
let mut val = -1
|
|
157
|
-
let mut num = num
|
|
158
|
-
while (num > 0) {
|
|
159
|
-
val += 1
|
|
160
|
-
num = num >> branchingBits
|
|
161
|
-
}
|
|
162
|
-
val
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Retrieves the element from the array at the specified index.
|
|
167
|
-
* A negative index is treated as an offset from the end of the array.
|
|
168
|
-
*
|
|
169
|
-
* @param index: The index to access
|
|
170
|
-
* @param array: The array to access
|
|
171
|
-
* @returns The element from the array
|
|
172
|
-
* @throws IndexOutOfBounds: When the index being accessed is outside the array's bounds
|
|
173
|
-
*
|
|
174
|
-
* @example get(1, fromList([1, 2, 3, 4])) == 2
|
|
175
|
-
* @example get(-1, fromList([1, 2, 3, 4])) == 4
|
|
176
|
-
*
|
|
177
|
-
* @since v0.6.0
|
|
178
|
-
*/
|
|
179
|
-
export let get = (index, array) => {
|
|
180
|
-
let index = wrapNegativeIndex(array.length, index)
|
|
181
|
-
|
|
182
|
-
let rec getInner = (shift, node) => {
|
|
183
|
-
let pos = index >> shift & bitmask
|
|
184
|
-
match (node[pos]) {
|
|
185
|
-
Tree(subTree) => getInner(shift - branchingBits, subTree),
|
|
186
|
-
Leaf(vals) => vals[index & bitmask],
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
let { length, shift, root, tail } = array
|
|
191
|
-
if (index < 0 || index >= length) {
|
|
192
|
-
throw Exception.IndexOutOfBounds
|
|
193
|
-
} else if (index >= tailIndex(length)) {
|
|
194
|
-
tail[index & bitmask]
|
|
195
|
-
} else {
|
|
196
|
-
getInner(shift, root)
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Creates a new array in which the element at the specified index is set to a
|
|
202
|
-
* new value. A negative index is treated as an offset from the end of the array.
|
|
203
|
-
*
|
|
204
|
-
* @param index: The index to update
|
|
205
|
-
* @param value: The value to store
|
|
206
|
-
* @param array: The array to update
|
|
207
|
-
* @returns A new array containing the new element at the given index
|
|
208
|
-
* @throws IndexOutOfBounds: When the index being updated is outside the array's bounds
|
|
209
|
-
*
|
|
210
|
-
* @example set(1, 9, fromList([1, 2, 3, 4, 5])) == fromList([1, 9, 3, 4, 5])
|
|
211
|
-
*
|
|
212
|
-
* @since v0.6.0
|
|
213
|
-
*/
|
|
214
|
-
export let set = (index, value, array) => {
|
|
215
|
-
let index = wrapNegativeIndex(array.length, index)
|
|
216
|
-
|
|
217
|
-
let rec setInner = (shift, node) => {
|
|
218
|
-
let pos = index >> shift & bitmask
|
|
219
|
-
let newVal = match (node[pos]) {
|
|
220
|
-
Tree(subTree) => {
|
|
221
|
-
Tree(setInner(shift - branchingBits, subTree))
|
|
222
|
-
},
|
|
223
|
-
Leaf(vals) => {
|
|
224
|
-
Leaf(arraySetCopy(index & bitmask, value, vals))
|
|
225
|
-
},
|
|
226
|
-
}
|
|
227
|
-
arraySetCopy(pos, newVal, node)
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
let { length, shift, root, tail } = array
|
|
231
|
-
if (index < 0 || index >= length) {
|
|
232
|
-
throw Exception.IndexOutOfBounds
|
|
233
|
-
} else if (index >= tailIndex(length)) {
|
|
234
|
-
{ length, shift, root, tail: arraySetCopy(index & bitmask, value, tail) }
|
|
235
|
-
} else {
|
|
236
|
-
{ length, shift, root: setInner(shift, root), tail }
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Inserts a new tail into the array. If the length of the tail equals the
|
|
241
|
-
// branching factor, it is instead inserted into the main tree rather than
|
|
242
|
-
// the tail
|
|
243
|
-
let replaceTail = (newTail, array) => {
|
|
244
|
-
let rec insertTailInTree = (shift, node) => {
|
|
245
|
-
let pos = array.length >> shift & bitmask
|
|
246
|
-
if (pos >= Array.length(node)) {
|
|
247
|
-
let newElem = if (shift == branchingBits) {
|
|
248
|
-
Leaf(newTail)
|
|
249
|
-
} else {
|
|
250
|
-
Tree(insertTailInTree(shift - branchingBits, [>]))
|
|
251
|
-
}
|
|
252
|
-
Array.append(node, [> newElem])
|
|
253
|
-
} else {
|
|
254
|
-
let newSubTree = match (node[pos]) {
|
|
255
|
-
Tree(subTree) => subTree,
|
|
256
|
-
Leaf(_) => [> node[pos]],
|
|
257
|
-
}
|
|
258
|
-
let newNode = Tree(insertTailInTree(shift - branchingBits, newSubTree))
|
|
259
|
-
arraySetCopy(pos, newNode, node)
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
let { length, shift, root, tail } = array
|
|
264
|
-
let newArrayLen = length + (Array.length(newTail) - Array.length(tail))
|
|
265
|
-
if (Array.length(newTail) == branchingFactor) {
|
|
266
|
-
let overflow = newArrayLen >> branchingBits > 1 << shift
|
|
267
|
-
if (overflow) {
|
|
268
|
-
let newShift = shift + branchingBits
|
|
269
|
-
let newRoot = insertTailInTree(newShift, [> Tree(root)])
|
|
270
|
-
{ length: newArrayLen, shift: newShift, root: newRoot, tail: [>] }
|
|
271
|
-
} else {
|
|
272
|
-
let newRoot = insertTailInTree(shift, root)
|
|
273
|
-
{ length: newArrayLen, shift, root: newRoot, tail: [>] }
|
|
274
|
-
}
|
|
275
|
-
} else {
|
|
276
|
-
{ length: newArrayLen, shift, root, tail: newTail }
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
let appendTree = (toAppend, array) => {
|
|
281
|
-
let (appended, numNotAppended) = arrayAppendMax32(array.tail, toAppend)
|
|
282
|
-
let newArray = replaceTail(appended, array)
|
|
283
|
-
if (numNotAppended > 0) {
|
|
284
|
-
let appendLen = Array.length(toAppend)
|
|
285
|
-
let newTail = Array.slice(appendLen - numNotAppended, appendLen, toAppend)
|
|
286
|
-
replaceTail(newTail, newArray)
|
|
287
|
-
} else {
|
|
288
|
-
newArray
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
// Flatten an array into a builder
|
|
293
|
-
let arrayToBuilder = array => {
|
|
294
|
-
let rec reduceFn = (acc, node) => {
|
|
295
|
-
match (node) {
|
|
296
|
-
Tree(subTree) => Array.reduce(reduceFn, acc, subTree),
|
|
297
|
-
Leaf(_) => [node, ...acc],
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
let { tail, root, length, _ } = array
|
|
301
|
-
{
|
|
302
|
-
btail: tail,
|
|
303
|
-
nodes: Array.reduce(reduceFn, [], root),
|
|
304
|
-
numNodes: length >> branchingBits,
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// For use to compress a large (> 32) list of nodes into subtrees
|
|
309
|
-
let rec compressNodes = (nodes, acc) => {
|
|
310
|
-
let node = Array.fromList(List.take(branchingFactor, nodes))
|
|
311
|
-
let remaining = List.drop(branchingFactor, nodes)
|
|
312
|
-
let newAcc = [Tree(node), ...acc]
|
|
313
|
-
match (remaining) {
|
|
314
|
-
[] => List.reverse(newAcc),
|
|
315
|
-
_ => compressNodes(remaining, newAcc),
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
let builderToArray = builder => {
|
|
320
|
-
// Builds the non-tail portion of an array
|
|
321
|
-
let rec buildTree = (nodes, numNodes) => {
|
|
322
|
-
let newNodeSize = Number.ceil(numNodes / branchingFactor)
|
|
323
|
-
match (newNodeSize) {
|
|
324
|
-
1 => Array.fromList(nodes),
|
|
325
|
-
_ => buildTree(compressNodes(nodes, []), newNodeSize),
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
let { btail, nodes, numNodes } = builder
|
|
330
|
-
match (numNodes) {
|
|
331
|
-
0 =>
|
|
332
|
-
{
|
|
333
|
-
length: Array.length(btail),
|
|
334
|
-
shift: branchingBits,
|
|
335
|
-
root: [>],
|
|
336
|
-
tail: btail,
|
|
337
|
-
},
|
|
338
|
-
_ => {
|
|
339
|
-
let treeSize = numNodes * branchingFactor
|
|
340
|
-
let depth = log32floor(treeSize - 1)
|
|
341
|
-
{
|
|
342
|
-
length: treeSize + Array.length(btail),
|
|
343
|
-
shift: Number.max(1, depth) * branchingBits,
|
|
344
|
-
root: buildTree(nodes, numNodes),
|
|
345
|
-
tail: btail,
|
|
346
|
-
}
|
|
347
|
-
},
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
// Append a chunk of <= 32 values to a builder
|
|
352
|
-
let appendBuilder = (toAppend, builder) => {
|
|
353
|
-
let { btail, nodes, numNodes } = builder
|
|
354
|
-
let (appended, numNotAppended) = arrayAppendMax32(btail, toAppend)
|
|
355
|
-
|
|
356
|
-
if (numNotAppended >= 0) {
|
|
357
|
-
let appendLen = Array.length(toAppend)
|
|
358
|
-
{
|
|
359
|
-
btail: Array.slice(appendLen - numNotAppended, appendLen, toAppend),
|
|
360
|
-
nodes: [Leaf(appended), ...nodes],
|
|
361
|
-
numNodes: numNodes + 1,
|
|
362
|
-
}
|
|
363
|
-
} else {
|
|
364
|
-
{ btail: appended, nodes, numNodes }
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
/**
|
|
369
|
-
* Creates a new array with the elements of the first array followed by
|
|
370
|
-
* the elements of the second array.
|
|
371
|
-
*
|
|
372
|
-
* @param array1: The array containing elements to appear first
|
|
373
|
-
* @param array2: The array containing elements to appear second
|
|
374
|
-
* @returns The new array containing elements from `array1` followed by elements from `array2`
|
|
375
|
-
*
|
|
376
|
-
* @example append(fromList([1, 2]), fromList([3, 4, 5])) == fromList([1, 2, 3, 4, 5])
|
|
377
|
-
*
|
|
378
|
-
* @since v0.6.0
|
|
379
|
-
*/
|
|
380
|
-
export let append = (array1, array2) => {
|
|
381
|
-
// Magic number of 4 determined best from benchmarks according to Elm's
|
|
382
|
-
// Array implementation
|
|
383
|
-
if (array2.length <= branchingFactor * 4) {
|
|
384
|
-
let rec reduceFn = (array, node) => {
|
|
385
|
-
match (node) {
|
|
386
|
-
Tree(subTree) => Array.reduce(reduceFn, array, subTree),
|
|
387
|
-
Leaf(vals) => appendTree(vals, array),
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
let withoutTail = Array.reduce(reduceFn, array1, array2.root)
|
|
391
|
-
appendTree(array2.tail, withoutTail)
|
|
392
|
-
} else {
|
|
393
|
-
let rec reduceFn = (builder, node) => {
|
|
394
|
-
match (node) {
|
|
395
|
-
Tree(subTree) => Array.reduce(reduceFn, builder, subTree),
|
|
396
|
-
Leaf(vals) => appendBuilder(vals, builder),
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
let withoutTail = Array.reduce(
|
|
400
|
-
reduceFn,
|
|
401
|
-
arrayToBuilder(array1),
|
|
402
|
-
array2.root
|
|
403
|
-
)
|
|
404
|
-
let { btail, nodes, numNodes } = appendBuilder(array2.tail, withoutTail)
|
|
405
|
-
builderToArray({ btail, nodes: List.reverse(nodes), numNodes })
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Creates a single array containing the elements of all arrays in the
|
|
411
|
-
* provided list.
|
|
412
|
-
*
|
|
413
|
-
* @param arrays: A list containing all arrays to combine
|
|
414
|
-
* @returns The new array
|
|
415
|
-
*
|
|
416
|
-
* @example concat([fromList([1, 2]), fromList([3, 4]), fromList([5, 6])]) == fromList([1, 2, 3, 4, 5, 6])
|
|
417
|
-
*
|
|
418
|
-
* @since v0.6.0
|
|
419
|
-
*/
|
|
420
|
-
export let concat = arrays => {
|
|
421
|
-
List.reduce(append, empty, arrays)
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
/**
|
|
425
|
-
* Creates a new array of the specified length where each element is
|
|
426
|
-
* initialized with the result of an initializer function. The initializer
|
|
427
|
-
* is called with the index of each array element.
|
|
428
|
-
*
|
|
429
|
-
* @param length: The length of the new array
|
|
430
|
-
* @param fn: The initializer function to call with each index, where the value returned will be used to initialize the element
|
|
431
|
-
* @returns The new array
|
|
432
|
-
*
|
|
433
|
-
* @example init(5, i => i + 3) == fromList([3, 4, 5, 6, 7])
|
|
434
|
-
*
|
|
435
|
-
* @since v0.6.0
|
|
436
|
-
*/
|
|
437
|
-
export let init = (length, fn) => {
|
|
438
|
-
let tailLen = length % branchingFactor
|
|
439
|
-
let btail = Array.init(tailLen, i => fn(length - tailLen + i))
|
|
440
|
-
|
|
441
|
-
let rec initInner = (beginI, nodes) => {
|
|
442
|
-
if (beginI < 0) {
|
|
443
|
-
builderToArray({ btail, nodes, numNodes: length >> branchingBits })
|
|
444
|
-
} else {
|
|
445
|
-
let leaf = Leaf(Array.init(branchingFactor, i => fn(beginI + i)))
|
|
446
|
-
initInner(beginI - branchingFactor, [leaf, ...nodes])
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
initInner(length - tailLen - branchingFactor, [])
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/**
|
|
453
|
-
* Creates a new array of the specified length with each element being
|
|
454
|
-
* initialized with the given value.
|
|
455
|
-
*
|
|
456
|
-
* @param length: The length of the new array
|
|
457
|
-
* @param value: The value to store at each index
|
|
458
|
-
* @returns The new array
|
|
459
|
-
*
|
|
460
|
-
* @example make(5, "foo") == fromList(["foo", "foo", "foo", "foo", "foo"])
|
|
461
|
-
*
|
|
462
|
-
* @since v0.6.0
|
|
463
|
-
*/
|
|
464
|
-
export let make = (length, value) => {
|
|
465
|
-
init(length, (_) => value)
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
/**
|
|
469
|
-
* Iterates an array, calling an iterator function on each element.
|
|
470
|
-
*
|
|
471
|
-
* @param fn: The iterator function to call with each element
|
|
472
|
-
* @param array: The array to iterate
|
|
473
|
-
*
|
|
474
|
-
* @since v0.6.0
|
|
475
|
-
*/
|
|
476
|
-
export let forEach = (fn, array) => {
|
|
477
|
-
let rec forEachFn = node => {
|
|
478
|
-
match (node) {
|
|
479
|
-
Tree(subTree) => Array.forEach(forEachFn, subTree),
|
|
480
|
-
Leaf(vals) => Array.forEach(fn, vals),
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
let { tail, root, _ } = array
|
|
484
|
-
Array.forEach(forEachFn, root)
|
|
485
|
-
Array.forEach(fn, tail)
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
/**
|
|
489
|
-
* Iterates an array a given number of times, calling an iterator function on each element.
|
|
490
|
-
*
|
|
491
|
-
* @param fn: The iterator function to call with each element
|
|
492
|
-
* @param n: The number of times to iterate the given array
|
|
493
|
-
* @param array: The array to iterate
|
|
494
|
-
*
|
|
495
|
-
* @since v0.6.0
|
|
496
|
-
*/
|
|
497
|
-
export let cycle = (fn, n, array) => {
|
|
498
|
-
for (let mut i = 0; i < n; i += 1) {
|
|
499
|
-
forEach(fn, array)
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
/**
|
|
504
|
-
* Produces a new array initialized with the results of a mapper function
|
|
505
|
-
* called on each element of the input array.
|
|
506
|
-
*
|
|
507
|
-
* @param fn: The mapper function to call on each element, where the value returned will be used to initialize the element in the new array
|
|
508
|
-
* @param array: The array to iterate
|
|
509
|
-
* @returns The new array with mapped values
|
|
510
|
-
*
|
|
511
|
-
* @since v0.6.0
|
|
512
|
-
*/
|
|
513
|
-
export let map = (fn, array) => {
|
|
514
|
-
let rec mapFn = node => {
|
|
515
|
-
match (node) {
|
|
516
|
-
Tree(subTree) => Tree(Array.map(mapFn, subTree)),
|
|
517
|
-
Leaf(vals) => Leaf(Array.map(fn, vals)),
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
let { length, shift, root, tail } = array
|
|
521
|
-
let newRoot = Array.map(mapFn, root)
|
|
522
|
-
let newTail = Array.map(fn, tail)
|
|
523
|
-
{ length, shift, root: newRoot, tail: newTail }
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Combines all elements of an array using a reducer function,
|
|
528
|
-
* starting from the "head", or left side, of the array.
|
|
529
|
-
*
|
|
530
|
-
* In `ImmutableArray.reduce(fn, initial, array)`, `fn` is called with
|
|
531
|
-
* an accumulator and each element of the array, and returns
|
|
532
|
-
* a new accumulator. The final value is the last accumulator
|
|
533
|
-
* returned. The accumulator starts with value `initial`.
|
|
534
|
-
*
|
|
535
|
-
* @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
|
|
536
|
-
* @param initial: The initial value to use for the accumulator on the first iteration
|
|
537
|
-
* @param array: The array to iterate
|
|
538
|
-
* @returns The final accumulator returned from `fn`
|
|
539
|
-
*
|
|
540
|
-
* @example reduce((acc, x) => acc + x, 0, fromList([1, 2, 3])) == 6
|
|
541
|
-
*
|
|
542
|
-
* @since v0.6.0
|
|
543
|
-
*/
|
|
544
|
-
export let reduce = (fn, initial, array) => {
|
|
545
|
-
let rec reduceFn = (acc, node) => {
|
|
546
|
-
match (node) {
|
|
547
|
-
Tree(subTree) => Array.reduce(reduceFn, acc, subTree),
|
|
548
|
-
Leaf(vals) => Array.reduce(fn, acc, vals),
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
let { tail, root, _ } = array
|
|
552
|
-
let withoutTail = Array.reduce(reduceFn, initial, root)
|
|
553
|
-
Array.reduce(fn, withoutTail, tail)
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
/**
|
|
557
|
-
* Combines all elements of an array using a reducer function,
|
|
558
|
-
* starting from the "end", or right side, of the array.
|
|
559
|
-
*
|
|
560
|
-
* In `ImmutableArray.reduceRight(fn, initial, array)`, `fn` is called with
|
|
561
|
-
* each element of the array and an accumulator, and returns
|
|
562
|
-
* a new accumulator. The final value is the last accumulator
|
|
563
|
-
* returned. The accumulator starts with value `initial`.
|
|
564
|
-
*
|
|
565
|
-
* @param fn: The reducer function to call on each element, where the value returned will be the next accumulator value
|
|
566
|
-
* @param initial: The initial value to use for the accumulator on the first iteration
|
|
567
|
-
* @param array: The array to iterate
|
|
568
|
-
* @returns The final accumulator returned from `fn`
|
|
569
|
-
*
|
|
570
|
-
* @example reduceRight((x, acc) => acc ++ x, "", fromList(["baz", "bar", "foo"])) == "foobarbaz"
|
|
571
|
-
*
|
|
572
|
-
* @since v0.6.0
|
|
573
|
-
*/
|
|
574
|
-
export let reduceRight = (fn, initial, array) => {
|
|
575
|
-
let rec reduceFn = (node, acc) => {
|
|
576
|
-
match (node) {
|
|
577
|
-
Tree(subTree) => Array.reduceRight(reduceFn, acc, subTree),
|
|
578
|
-
Leaf(vals) => Array.reduceRight(fn, acc, vals),
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
let { tail, root, _ } = array
|
|
582
|
-
let tailVal = Array.reduceRight(fn, initial, tail)
|
|
583
|
-
Array.reduceRight(reduceFn, tailVal, root)
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Produces a new array by calling a function on each element
|
|
588
|
-
* of the input array. Each iteration produces an intermediate
|
|
589
|
-
* array, which are all appended to produce a "flattened" array
|
|
590
|
-
* of all results.
|
|
591
|
-
*
|
|
592
|
-
* @param fn: The function to be called on each element, where the value returned will be an array that gets appended to the new array
|
|
593
|
-
* @param array: The array to iterate
|
|
594
|
-
* @returns The new array
|
|
595
|
-
*
|
|
596
|
-
* @example flatMap(n => fromList([n, n + 1]), fromList([1, 3, 5])) == fromList([1, 2, 3, 4, 5, 6])
|
|
597
|
-
*
|
|
598
|
-
* @since v0.6.0
|
|
599
|
-
*/
|
|
600
|
-
export let flatMap = (fn, array) => {
|
|
601
|
-
reduce((acc, x) => append(acc, fn(x)), empty, array)
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Converts the input list to an array.
|
|
606
|
-
*
|
|
607
|
-
* @param list: The list to convert
|
|
608
|
-
* @returns The array containing all elements from the list
|
|
609
|
-
*
|
|
610
|
-
* @since v0.6.0
|
|
611
|
-
*/
|
|
612
|
-
export let fromList = list => {
|
|
613
|
-
let rec fromListInner = (list, nodes, numNodes) => {
|
|
614
|
-
let node = Array.fromList(List.take(branchingFactor, list))
|
|
615
|
-
let remaining = List.drop(branchingFactor, list)
|
|
616
|
-
if (Array.length(node) < branchingFactor) {
|
|
617
|
-
builderToArray({ btail: node, nodes: List.reverse(nodes), numNodes })
|
|
618
|
-
} else {
|
|
619
|
-
fromListInner(remaining, [Leaf(node), ...nodes], numNodes + 1)
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
fromListInner(list, [], 0)
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
/**
|
|
627
|
-
* Converts the input array to a list.
|
|
628
|
-
*
|
|
629
|
-
* @param array: The array to convert
|
|
630
|
-
* @returns The list containing all elements from the array
|
|
631
|
-
*
|
|
632
|
-
* @since v0.6.0
|
|
633
|
-
*/
|
|
634
|
-
export let toList = array => {
|
|
635
|
-
reduceRight((val, list) => [val, ...list], [], array)
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
/**
|
|
639
|
-
* Produces a new array by calling a function on each element of
|
|
640
|
-
* the input array and only including it in the result array if the element satisfies
|
|
641
|
-
* the condition.
|
|
642
|
-
*
|
|
643
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
644
|
-
* @param array: The array to iterate
|
|
645
|
-
* @returns The new array containing elements where `fn` returned `true`
|
|
646
|
-
*
|
|
647
|
-
* @since v0.6.0
|
|
648
|
-
*/
|
|
649
|
-
export let filter = (fn, array) => {
|
|
650
|
-
fromList(reduceRight((x, arr) => if (fn(x)) [x, ...arr] else arr, [], array))
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/**
|
|
654
|
-
* Checks that the given condition is satisfied for all
|
|
655
|
-
* elements in the input array.
|
|
656
|
-
*
|
|
657
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
658
|
-
* @param array: The array to check
|
|
659
|
-
* @returns `true` if all elements satify the condition or `false` otherwise
|
|
660
|
-
*
|
|
661
|
-
* @since v0.6.0
|
|
662
|
-
*/
|
|
663
|
-
export let every = (fn, array) => {
|
|
664
|
-
reduce((acc, x) => acc && fn(x), true, array)
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Checks that the given condition is satisfied **at least
|
|
669
|
-
* once** by an element in the input array.
|
|
670
|
-
*
|
|
671
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
672
|
-
* @param array: The array to iterate
|
|
673
|
-
* @returns `true` if one or more elements satify the condition or `false` otherwise
|
|
674
|
-
*
|
|
675
|
-
* @since v0.6.0
|
|
676
|
-
*/
|
|
677
|
-
export let some = (fn, array) => {
|
|
678
|
-
reduce((acc, x) => acc || fn(x), false, array)
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/**
|
|
682
|
-
* Creates a new array with all elements in reverse order.
|
|
683
|
-
*
|
|
684
|
-
* @param array: The array to reverse
|
|
685
|
-
* @returns The new array
|
|
686
|
-
*
|
|
687
|
-
* @since v0.6.0
|
|
688
|
-
*/
|
|
689
|
-
export let reverse = array => {
|
|
690
|
-
fromList(reduce((acc, x) => [x, ...acc], [], array))
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
/**
|
|
694
|
-
* Checks if the value is an element of the input array.
|
|
695
|
-
* Uses the generic `==` structural equality operator.
|
|
696
|
-
*
|
|
697
|
-
* @param search: The value to compare
|
|
698
|
-
* @param array: The array to inspect
|
|
699
|
-
* @returns `true` if the value exists in the array or `false` otherwise
|
|
700
|
-
*
|
|
701
|
-
* @since v0.6.0
|
|
702
|
-
*/
|
|
703
|
-
export let contains = (value, array) => {
|
|
704
|
-
reduce((acc, x) => acc || x == value, false, array)
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
/**
|
|
708
|
-
* Finds the first element in an array that satifies the given condition.
|
|
709
|
-
*
|
|
710
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
711
|
-
* @param array: The array to search
|
|
712
|
-
* @returns `Some(element)` containing the first value found or `None` otherwise
|
|
713
|
-
*
|
|
714
|
-
* @since v0.6.0
|
|
715
|
-
*/
|
|
716
|
-
export let find = (fn, array) => {
|
|
717
|
-
reduce((acc, x) => if (acc == None && fn(x)) Some(x) else acc, None, array)
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
/**
|
|
721
|
-
* Finds the first index in an array where the element satifies the given condition.
|
|
722
|
-
*
|
|
723
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
724
|
-
* @param array: The array to search
|
|
725
|
-
* @returns `Some(index)` containing the index of the first element found or `None` otherwise
|
|
726
|
-
*
|
|
727
|
-
* @since v0.6.0
|
|
728
|
-
*/
|
|
729
|
-
export let findIndex = (fn, array) => {
|
|
730
|
-
let mut i = -1
|
|
731
|
-
reduce((acc, x) => {
|
|
732
|
-
i += 1
|
|
733
|
-
if (acc == None && fn(x)) Some(i) else acc
|
|
734
|
-
}, None, array)
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
/**
|
|
738
|
-
* Combines two arrays into a Cartesian product of tuples containing
|
|
739
|
-
* all ordered pairs `(a, b)`.
|
|
740
|
-
*
|
|
741
|
-
* @param array1: The array to provide values for the first tuple element
|
|
742
|
-
* @param array2: The array to provide values for the second tuple element
|
|
743
|
-
* @returns The new array containing all pairs of `(a, b)`
|
|
744
|
-
*
|
|
745
|
-
* @since v0.6.0
|
|
746
|
-
*/
|
|
747
|
-
export let product = (array1, array2) => {
|
|
748
|
-
fromList(
|
|
749
|
-
reduceRight((x1, list) => {
|
|
750
|
-
reduceRight((x2, list) => [(x1, x2), ...list], list, array2)
|
|
751
|
-
}, [], array1)
|
|
752
|
-
)
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
/**
|
|
756
|
-
* Counts the number of elements in an array that satisfy the given condition.
|
|
757
|
-
*
|
|
758
|
-
* @param fn: The function to call on each element, where the returned value indicates if the element satisfies the condition
|
|
759
|
-
* @param array: The array to iterate
|
|
760
|
-
* @returns The total number of elements that satisfy the condition
|
|
761
|
-
*
|
|
762
|
-
* @since v0.6.0
|
|
763
|
-
*/
|
|
764
|
-
export let count = (fn, array) => {
|
|
765
|
-
reduce((acc, x) => if (fn(x)) acc + 1 else acc, 0, array)
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* Produces a new array with any duplicates removed.
|
|
770
|
-
* Uses the generic `==` structural equality operator.
|
|
771
|
-
*
|
|
772
|
-
* @param array: The array to filter
|
|
773
|
-
* @returns The new array with only unique values
|
|
774
|
-
*
|
|
775
|
-
* @since v0.6.0
|
|
776
|
-
*/
|
|
777
|
-
export let unique = array => {
|
|
778
|
-
let set = Set.fromList(toList(array))
|
|
779
|
-
filter(x => {
|
|
780
|
-
let good = Set.contains(x, set)
|
|
781
|
-
if (good) {
|
|
782
|
-
Set.remove(x, set)
|
|
783
|
-
}
|
|
784
|
-
good
|
|
785
|
-
}, array)
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
/**
|
|
789
|
-
* Produces a new array filled with tuples of elements from both given arrays.
|
|
790
|
-
* The first tuple will contain the first item of each array, the second tuple
|
|
791
|
-
* will contain the second item of each array, and so on.
|
|
792
|
-
*
|
|
793
|
-
* Calling this function with arrays of different sizes will cause the returned
|
|
794
|
-
* array to have the length of the smaller array.
|
|
795
|
-
*
|
|
796
|
-
* @param array1: The array to provide values for the first tuple element
|
|
797
|
-
* @param array2: The array to provide values for the second tuple element
|
|
798
|
-
* @returns The new array containing indexed pairs of `(a, b)`
|
|
799
|
-
*
|
|
800
|
-
* @since v0.6.0
|
|
801
|
-
*/
|
|
802
|
-
export let zip = (array1, array2) => {
|
|
803
|
-
fromList(List.zip(toList(array1), toList(array2)))
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
/**
|
|
807
|
-
* Produces a new array filled with elements defined by applying a function on
|
|
808
|
-
* pairs from both given arrays. The first element will contain the result of
|
|
809
|
-
* applying the function to the first elements of each array, the second element
|
|
810
|
-
* will contain the result of applying the function to the second elements of
|
|
811
|
-
* each array, and so on.
|
|
812
|
-
*
|
|
813
|
-
* Calling this function with arrays of different sizes will cause the returned
|
|
814
|
-
* array to have the length of the smaller array.
|
|
815
|
-
*
|
|
816
|
-
* @param fn: The function to apply to pairs of elements
|
|
817
|
-
* @param array1: The array whose elements will each be passed to the function as the first argument
|
|
818
|
-
* @param array2: The array whose elements will each be passed to the function as the second argument
|
|
819
|
-
* @returns The new array containing elements derived from applying the function to pairs of input array elements
|
|
820
|
-
*
|
|
821
|
-
* @example zipWith((a, b) => a + b, fromList([1, 2, 3]), fromList([4, 5, 6])) == fromList([5, 7, 9])
|
|
822
|
-
* @example zipWith((a, b) => a * b, fromList([1, 2, 3]), fromList([4, 5])) == fromList([4, 10])
|
|
823
|
-
*
|
|
824
|
-
* @since v0.6.0
|
|
825
|
-
*/
|
|
826
|
-
export let zipWith = (fn, array1, array2) => {
|
|
827
|
-
fromList(List.zipWith(fn, toList(array1), toList(array2)))
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
/**
|
|
831
|
-
* Produces two arrays by splitting apart an array of tuples.
|
|
832
|
-
*
|
|
833
|
-
* @param array: The array of tuples to split
|
|
834
|
-
* @returns An array containing all elements from the first tuple element and an array containing all elements from the second tuple element
|
|
835
|
-
*
|
|
836
|
-
* @since v0.6.0
|
|
837
|
-
*/
|
|
838
|
-
export let unzip = array => {
|
|
839
|
-
let (list1, list2) = List.unzip(toList(array))
|
|
840
|
-
(fromList(list1), fromList(list2))
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
/**
|
|
844
|
-
* Concatenates an array of strings into a single string, separated by a separator string.
|
|
845
|
-
*
|
|
846
|
-
* @param separator: The separator to insert between items in the string
|
|
847
|
-
* @param array: The input strings
|
|
848
|
-
* @returns The concatenated string
|
|
849
|
-
*
|
|
850
|
-
* @since v0.6.0
|
|
851
|
-
*/
|
|
852
|
-
export let join = (separator, array) => {
|
|
853
|
-
let buf = Buffer.make(16)
|
|
854
|
-
let mut i = 0
|
|
855
|
-
forEach(x => {
|
|
856
|
-
let toAdd = if (i != array.length - 1) x ++ separator else x
|
|
857
|
-
i += 1
|
|
858
|
-
Buffer.addString(toAdd, buf)
|
|
859
|
-
}, array)
|
|
860
|
-
Buffer.toString(buf)
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
let clampIndex = (len, index) => {
|
|
864
|
-
Number.min(len, Number.max(0, wrapNegativeIndex(len, index)))
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
/**
|
|
868
|
-
* Slices an array given zero-based start and end indexes. The value
|
|
869
|
-
* at the end index will not be included in the result.
|
|
870
|
-
*
|
|
871
|
-
* If either index is a negative number, it will be treated as a reverse index from
|
|
872
|
-
* the end of the array.
|
|
873
|
-
*
|
|
874
|
-
* @param start: The index of the array where the slice will begin (inclusive)
|
|
875
|
-
* @param end: The index of the array where the slice will end (exclusive)
|
|
876
|
-
* @param array: The array to be sliced
|
|
877
|
-
* @returns The subset of the array that was sliced
|
|
878
|
-
*
|
|
879
|
-
* @example slice(0, 2, fromList(['a', 'b', 'c'])) == fromList(['a', 'b'])
|
|
880
|
-
* @example slice(1, -1, fromList(['a', 'b', 'c'])) == fromList(['b'])
|
|
881
|
-
*
|
|
882
|
-
* @since v0.6.0
|
|
883
|
-
*/
|
|
884
|
-
export let slice = (start, end, array) => {
|
|
885
|
-
let begin = clampIndex(array.length, start)
|
|
886
|
-
let end = clampIndex(array.length, end)
|
|
887
|
-
let mut i = array.length
|
|
888
|
-
fromList(
|
|
889
|
-
reduceRight((x, acc) => {
|
|
890
|
-
i -= 1
|
|
891
|
-
if (i >= begin && i < end) [x, ...acc] else acc
|
|
892
|
-
}, [], array)
|
|
893
|
-
)
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
/**
|
|
897
|
-
* Sorts the given array based on a given comparator function.
|
|
898
|
-
*
|
|
899
|
-
* 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.
|
|
900
|
-
* @param comp: The comparator function used to indicate sort order
|
|
901
|
-
* @param array: The array to be sorted
|
|
902
|
-
* @returns The sorted array
|
|
903
|
-
*
|
|
904
|
-
* @since v0.6.0
|
|
905
|
-
*/
|
|
906
|
-
export let sort = (comp, array) => {
|
|
907
|
-
fromList(List.sort(comp, toList(array)))
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
/**
|
|
911
|
-
* Rotates array elements by the specified amount to the left.
|
|
912
|
-
*
|
|
913
|
-
* If value is negative, array elements will be rotated by the
|
|
914
|
-
* specified amount to the right. See examples.
|
|
915
|
-
*
|
|
916
|
-
* @param n: The number of elements to rotate by
|
|
917
|
-
* @param array: The array to be rotated
|
|
918
|
-
*
|
|
919
|
-
* @example rotate(2, fromList([1, 2, 3, 4, 5])) == fromList([3, 4, 5, 1, 2])
|
|
920
|
-
* @example rotate(-1, fromList([1, 2, 3, 4, 5])) == fromList([5, 1, 2, 3, 4])
|
|
921
|
-
*
|
|
922
|
-
* @since v0.6.0
|
|
923
|
-
*/
|
|
924
|
-
export let rotate = (n, array) => {
|
|
925
|
-
let sliceI = if (array.length == 0) 0 else n % array.length
|
|
926
|
-
let before = slice(0, sliceI, array)
|
|
927
|
-
let after = slice(sliceI, array.length, array)
|
|
928
|
-
append(after, before)
|
|
929
|
-
}
|