@grain/stdlib 0.4.0 → 0.4.4
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 +65 -0
- package/LICENSE +21 -0
- package/README.md +34 -0
- package/array.gr +136 -44
- package/array.md +97 -21
- package/buffer.gr +495 -424
- package/buffer.md +850 -0
- package/bytes.gr +512 -407
- package/bytes.md +621 -0
- package/char.gr +11 -3
- package/hash.gr +26 -3
- package/hash.md +44 -0
- package/list.gr +54 -0
- package/number.gr +24 -6
- package/number.md +49 -17
- package/option.gr +244 -37
- package/option.md +579 -0
- package/package.json +33 -29
- package/queue.gr +98 -29
- package/queue.md +191 -0
- package/range.md +1 -1
- package/regex.gr +3055 -0
- package/regex.md +449 -0
- package/result.gr +216 -70
- package/result.md +446 -0
- package/runtime/gc.gr +2 -2
- package/runtime/string.gr +56 -24
- package/runtime/stringUtils.gr +172 -0
- package/runtime/unsafe/conv.gr +43 -0
- package/set.gr +172 -5
- package/set.md +502 -0
- package/stack.md +143 -0
- package/string.gr +444 -230
- package/string.md +815 -0
- package/sys/file.gr +3 -2
- package/sys/file.md +2 -2
package/string.gr
CHANGED
|
@@ -1,24 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module String: Utilities for working with strings.
|
|
3
|
+
* @example import String from "string"
|
|
4
|
+
*
|
|
5
|
+
* @since v0.2.0
|
|
6
|
+
* @history v0.1.0: Originally named `strings`
|
|
7
|
+
* @history v0.2.0: Renamed to `string`
|
|
8
|
+
*/
|
|
1
9
|
import WasmI32 from "runtime/unsafe/wasmi32"
|
|
2
10
|
import Memory from "runtime/unsafe/memory"
|
|
3
11
|
import Exception from "runtime/exception"
|
|
4
12
|
import { tagSimpleNumber, allocateArray, allocateChar, allocateString, allocateBytes } from "runtime/dataStructures"
|
|
5
13
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
/**
|
|
15
|
+
* @section Types: Type declarations included in the String module.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Byte encodings
|
|
20
|
+
*/
|
|
21
|
+
export enum Encoding {
|
|
22
|
+
UTF8,
|
|
23
|
+
UTF16_BE,
|
|
24
|
+
UTF16_LE,
|
|
25
|
+
UTF32_BE,
|
|
26
|
+
UTF32_LE,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @section Values: Functions for working with the String data type.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Concatenate two strings.
|
|
35
|
+
*
|
|
36
|
+
* @param str1: The beginning string
|
|
37
|
+
* @param str2: The ending string
|
|
38
|
+
* @returns The combined string
|
|
39
|
+
*
|
|
40
|
+
* @example String.concat("Foo", " Bar") == "FooBar"
|
|
41
|
+
*
|
|
42
|
+
* @since v0.1.0
|
|
43
|
+
*/
|
|
10
44
|
export let concat = (++)
|
|
11
45
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Returns the character length of the input string.
|
|
48
|
+
*
|
|
49
|
+
* @param string: The string to inspect
|
|
50
|
+
* @returns The number of characters in the string
|
|
51
|
+
*
|
|
52
|
+
* @example String.length("Hello world") == 11
|
|
53
|
+
*
|
|
54
|
+
* @since v0.1.0
|
|
55
|
+
*/
|
|
15
56
|
@disableGC
|
|
16
|
-
export let rec length = (
|
|
17
|
-
let
|
|
18
|
-
let size = WasmI32.load(
|
|
57
|
+
export let rec length = (string: String) => {
|
|
58
|
+
let string = WasmI32.fromGrain(string)
|
|
59
|
+
let size = WasmI32.load(string, 4n)
|
|
19
60
|
|
|
20
61
|
let mut len = 0n
|
|
21
|
-
let mut ptr = WasmI32.add(
|
|
62
|
+
let mut ptr = WasmI32.add(string, 8n)
|
|
22
63
|
let end = WasmI32.add(ptr, size)
|
|
23
64
|
|
|
24
65
|
while (WasmI32.ltU(ptr, end)) {
|
|
@@ -31,7 +72,7 @@ export let rec length = (s: String) => {
|
|
|
31
72
|
|
|
32
73
|
let ret = tagSimpleNumber(len)
|
|
33
74
|
Memory.decRef(WasmI32.fromGrain(length))
|
|
34
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
75
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
35
76
|
ret
|
|
36
77
|
}
|
|
37
78
|
|
|
@@ -43,38 +84,51 @@ let wasmSafeLength = (s: String) => {
|
|
|
43
84
|
length(s)
|
|
44
85
|
}
|
|
45
86
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Returns the byte length of the input string.
|
|
89
|
+
*
|
|
90
|
+
* @param string: The string to inspect
|
|
91
|
+
* @returns The number of bytes in the string
|
|
92
|
+
*
|
|
93
|
+
* @example String.byteLength("🌾") == 4
|
|
94
|
+
*
|
|
95
|
+
* @since v0.1.0
|
|
96
|
+
*/
|
|
49
97
|
@disableGC
|
|
50
|
-
export let rec byteLength = (
|
|
51
|
-
let
|
|
52
|
-
let ret = tagSimpleNumber(WasmI32.load(
|
|
98
|
+
export let rec byteLength = (string: String) => {
|
|
99
|
+
let string = WasmI32.fromGrain(string)
|
|
100
|
+
let ret = tagSimpleNumber(WasmI32.load(string, 4n))
|
|
53
101
|
Memory.decRef(WasmI32.fromGrain(byteLength))
|
|
54
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
102
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
55
103
|
ret
|
|
56
104
|
}
|
|
57
105
|
|
|
58
|
-
|
|
59
106
|
// @disableGC-safe wrapper
|
|
60
107
|
@disableGC
|
|
61
|
-
let wasmSafeByteLength = (
|
|
108
|
+
let wasmSafeByteLength = (string: String) => {
|
|
62
109
|
Memory.incRef(WasmI32.fromGrain(byteLength))
|
|
63
|
-
Memory.incRef(WasmI32.fromGrain(
|
|
64
|
-
byteLength(
|
|
110
|
+
Memory.incRef(WasmI32.fromGrain(string))
|
|
111
|
+
byteLength(string)
|
|
65
112
|
}
|
|
66
113
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
114
|
+
/**
|
|
115
|
+
* Finds the position of a substring in the input string.
|
|
116
|
+
*
|
|
117
|
+
* @param search: The substring to find
|
|
118
|
+
* @param string: The string to inspect
|
|
119
|
+
* @returns `Some(position)` containing the starting position of the substring if found or `None` otherwise
|
|
120
|
+
*
|
|
121
|
+
* @example String.indexOf("world", "Hello world") == Some(6)
|
|
122
|
+
*
|
|
123
|
+
* @since v0.3.0
|
|
124
|
+
*/
|
|
71
125
|
@disableGC
|
|
72
|
-
export let rec indexOf = (
|
|
73
|
-
let
|
|
74
|
-
let
|
|
126
|
+
export let rec indexOf = (search: String, string: String) => {
|
|
127
|
+
let search = WasmI32.fromGrain(search)
|
|
128
|
+
let string = WasmI32.fromGrain(string)
|
|
75
129
|
|
|
76
|
-
let size = WasmI32.load(
|
|
77
|
-
let psize = WasmI32.load(
|
|
130
|
+
let size = WasmI32.load(string, 4n)
|
|
131
|
+
let psize = WasmI32.load(search, 4n)
|
|
78
132
|
|
|
79
133
|
let (>) = WasmI32.gtU
|
|
80
134
|
let (<) = WasmI32.ltU
|
|
@@ -89,8 +143,8 @@ export let rec indexOf = (p: String, s: String) => {
|
|
|
89
143
|
none
|
|
90
144
|
} else {
|
|
91
145
|
let mut idx = 0n
|
|
92
|
-
let mut ptr =
|
|
93
|
-
let mut pptr =
|
|
146
|
+
let mut ptr = string + 8n
|
|
147
|
+
let mut pptr = search + 8n
|
|
94
148
|
let end = ptr + size - psize + 1n
|
|
95
149
|
|
|
96
150
|
let mut result = -1n
|
|
@@ -122,19 +176,30 @@ export let rec indexOf = (p: String, s: String) => {
|
|
|
122
176
|
Some(tagSimpleNumber(result))
|
|
123
177
|
}
|
|
124
178
|
}
|
|
125
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
126
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
179
|
+
Memory.decRef(WasmI32.fromGrain(search))
|
|
180
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
127
181
|
Memory.decRef(WasmI32.fromGrain(indexOf))
|
|
128
182
|
ret
|
|
129
183
|
}
|
|
130
184
|
|
|
185
|
+
/**
|
|
186
|
+
* Get the character at the position in the input string.
|
|
187
|
+
*
|
|
188
|
+
* @param position: The position to check
|
|
189
|
+
* @param string: The string to search
|
|
190
|
+
* @returns The character at the provided position
|
|
191
|
+
*
|
|
192
|
+
* @example String.charAt(5, "Hello world") == ' '
|
|
193
|
+
*
|
|
194
|
+
* @since v0.4.0
|
|
195
|
+
*/
|
|
131
196
|
@disableGC
|
|
132
|
-
export let rec charAt = (
|
|
197
|
+
export let rec charAt = (position, string: String) => {
|
|
133
198
|
Memory.incRef(WasmI32.fromGrain((<=)))
|
|
134
|
-
if (wasmSafeLength(
|
|
199
|
+
if (wasmSafeLength(string) <= position || {Memory.incRef(WasmI32.fromGrain((<))); position < 0}) {
|
|
135
200
|
Memory.incRef(WasmI32.fromGrain((++)))
|
|
136
201
|
Memory.incRef(WasmI32.fromGrain(toString))
|
|
137
|
-
fail ("Invalid offset: " ++ toString(
|
|
202
|
+
fail ("Invalid offset: " ++ toString(position))
|
|
138
203
|
}
|
|
139
204
|
// Implementation is similar to explodeHelp, but doesn't perform unneeded memory allocations
|
|
140
205
|
let (>>>) = WasmI32.shrU
|
|
@@ -142,11 +207,11 @@ export let rec charAt = (idx, s: String) => {
|
|
|
142
207
|
let (&) = WasmI32.and
|
|
143
208
|
let (<) = WasmI32.ltU
|
|
144
209
|
let (==) = WasmI32.eq
|
|
145
|
-
let size = WasmI32.fromGrain(wasmSafeByteLength(
|
|
146
|
-
let len = WasmI32.fromGrain(wasmSafeLength(
|
|
147
|
-
let
|
|
148
|
-
let
|
|
149
|
-
let mut ptr =
|
|
210
|
+
let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >>> 1n
|
|
211
|
+
let len = WasmI32.fromGrain(wasmSafeLength(string)) >>> 1n
|
|
212
|
+
let position = WasmI32.fromGrain(position) >>> 1n
|
|
213
|
+
let string = WasmI32.fromGrain(string)
|
|
214
|
+
let mut ptr = string + 8n;
|
|
150
215
|
let end = ptr + size;
|
|
151
216
|
let mut counter = 0n;
|
|
152
217
|
let mut result = 0n
|
|
@@ -161,7 +226,7 @@ export let rec charAt = (idx, s: String) => {
|
|
|
161
226
|
} else {
|
|
162
227
|
2n
|
|
163
228
|
}
|
|
164
|
-
if (counter ==
|
|
229
|
+
if (counter == position) {
|
|
165
230
|
let c = allocateChar()
|
|
166
231
|
Memory.copy(c + 4n, ptr, n)
|
|
167
232
|
result = c
|
|
@@ -174,7 +239,7 @@ export let rec charAt = (idx, s: String) => {
|
|
|
174
239
|
fail "charAt: should be impossible (please report)"
|
|
175
240
|
}
|
|
176
241
|
let ret = WasmI32.toGrain(result): Char
|
|
177
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
242
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
178
243
|
Memory.decRef(WasmI32.fromGrain(charAt))
|
|
179
244
|
ret
|
|
180
245
|
}
|
|
@@ -228,17 +293,37 @@ let explodeHelp = (s: String, chars) => {
|
|
|
228
293
|
arr
|
|
229
294
|
}
|
|
230
295
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
296
|
+
/**
|
|
297
|
+
* Split a string into its Unicode characters.
|
|
298
|
+
*
|
|
299
|
+
* @param string: The string to split
|
|
300
|
+
* @returns An array containing all characters in the string
|
|
301
|
+
*
|
|
302
|
+
* @example String.explode("Hello") == [> 'H', 'e', 'l', 'l', 'o']
|
|
303
|
+
*
|
|
304
|
+
* @since v0.3.0
|
|
305
|
+
*/
|
|
234
306
|
@disableGC
|
|
235
|
-
export let explode = (
|
|
236
|
-
|
|
307
|
+
export let rec explode = (string) => {
|
|
308
|
+
// `explodeHelp` and `string` do not need to be incRef'd as they are not
|
|
309
|
+
// decRef'd in `explodeHelp`
|
|
310
|
+
let ret = WasmI32.toGrain(explodeHelp(string, true)) : (Array<Char>)
|
|
311
|
+
|
|
312
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
313
|
+
Memory.decRef(WasmI32.fromGrain(explode))
|
|
314
|
+
ret
|
|
237
315
|
}
|
|
238
316
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
317
|
+
/**
|
|
318
|
+
* Create a string from an array of characters.
|
|
319
|
+
*
|
|
320
|
+
* @param arr: The array to combine
|
|
321
|
+
* @returns A string representation of the array of characters
|
|
322
|
+
*
|
|
323
|
+
* @example String.implode([> 'H', 'e', 'l', 'l', 'o']) == "Hello"
|
|
324
|
+
*
|
|
325
|
+
* @since v0.3.0
|
|
326
|
+
*/
|
|
242
327
|
@disableGC
|
|
243
328
|
export let rec implode = (arr: Array<Char>) => {
|
|
244
329
|
let (+) = WasmI32.add
|
|
@@ -297,12 +382,44 @@ export let rec implode = (arr: Array<Char>) => {
|
|
|
297
382
|
ret
|
|
298
383
|
}
|
|
299
384
|
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
385
|
+
// Helper to get the length in constant time without depending on Array
|
|
386
|
+
primitive arrayLength : Array<a> -> Number = "@array.length"
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Create a string that is the given string reversed.
|
|
390
|
+
*
|
|
391
|
+
* @param string: The string to reverse
|
|
392
|
+
* @returns A string whose characters are in the reverse order of the given string
|
|
393
|
+
*
|
|
394
|
+
* @example String.reverse("olleH") == "Hello"
|
|
395
|
+
*
|
|
396
|
+
* @since v0.4.5
|
|
397
|
+
*/
|
|
398
|
+
export let reverse = (string) => {
|
|
399
|
+
let mut arr = explode(string)
|
|
400
|
+
let len = arrayLength(arr)
|
|
401
|
+
let halfLen = len / 2
|
|
402
|
+
for (let mut i = 0; i < halfLen; i += 1) {
|
|
403
|
+
let lastIdx = len - i - 1
|
|
404
|
+
let last = arr[lastIdx]
|
|
405
|
+
let first = arr[i]
|
|
406
|
+
arr[i] = last
|
|
407
|
+
arr[lastIdx] = first
|
|
408
|
+
}
|
|
409
|
+
implode(arr)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Split a string by the given separator.
|
|
414
|
+
*
|
|
415
|
+
* @param separator: The separator to split on
|
|
416
|
+
* @param string: The string to split
|
|
417
|
+
* @returns An array of substrings from the initial string
|
|
418
|
+
*
|
|
419
|
+
* @example String.split(" ", "Hello world") == [> "Hello", "world"]
|
|
420
|
+
*/
|
|
304
421
|
@disableGC
|
|
305
|
-
export let rec split = (
|
|
422
|
+
export let rec split = (separator: String, string: String) => {
|
|
306
423
|
let (+) = WasmI32.add
|
|
307
424
|
let (-) = WasmI32.sub
|
|
308
425
|
let (==) = WasmI32.eq
|
|
@@ -312,22 +429,22 @@ export let rec split = (p: String, s: String) => {
|
|
|
312
429
|
let (>>) = WasmI32.shrS
|
|
313
430
|
let (&) = WasmI32.and
|
|
314
431
|
|
|
315
|
-
let size = WasmI32.fromGrain(wasmSafeByteLength(
|
|
316
|
-
let psize = WasmI32.fromGrain(wasmSafeByteLength(
|
|
432
|
+
let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n
|
|
433
|
+
let psize = WasmI32.fromGrain(wasmSafeByteLength(separator)) >> 1n
|
|
317
434
|
|
|
318
435
|
let ret = if (psize == 0n) {
|
|
319
|
-
WasmI32.toGrain(explodeHelp(
|
|
436
|
+
WasmI32.toGrain(explodeHelp(string, false)): Array<String>
|
|
320
437
|
} else if (psize > size) {
|
|
321
|
-
let
|
|
438
|
+
let string = WasmI32.fromGrain(string)
|
|
322
439
|
let ptr = allocateArray(1n)
|
|
323
|
-
WasmI32.store(ptr, Memory.incRef(
|
|
440
|
+
WasmI32.store(ptr, Memory.incRef(string), 8n)
|
|
324
441
|
WasmI32.toGrain(ptr): Array<String>
|
|
325
442
|
} else {
|
|
326
|
-
let
|
|
327
|
-
let
|
|
443
|
+
let string = WasmI32.fromGrain(string)
|
|
444
|
+
let separator = WasmI32.fromGrain(separator)
|
|
328
445
|
|
|
329
|
-
let mut ptr =
|
|
330
|
-
let mut pptr =
|
|
446
|
+
let mut ptr = string + 8n
|
|
447
|
+
let mut pptr = separator + 8n
|
|
331
448
|
let end = ptr + size - psize + 1n
|
|
332
449
|
|
|
333
450
|
let mut numStrings = 1n
|
|
@@ -348,7 +465,7 @@ export let rec split = (p: String, s: String) => {
|
|
|
348
465
|
}
|
|
349
466
|
}
|
|
350
467
|
|
|
351
|
-
ptr =
|
|
468
|
+
ptr = string + 8n
|
|
352
469
|
let mut last = ptr
|
|
353
470
|
let arr = allocateArray(numStrings)
|
|
354
471
|
let mut arrIdx = 0n
|
|
@@ -377,26 +494,33 @@ export let rec split = (p: String, s: String) => {
|
|
|
377
494
|
}
|
|
378
495
|
|
|
379
496
|
// Grab last string
|
|
380
|
-
let strSize =
|
|
497
|
+
let strSize = string + 8n + size - last
|
|
381
498
|
let lastStr = allocateString(strSize)
|
|
382
499
|
Memory.copy(lastStr + 8n, last, strSize)
|
|
383
500
|
WasmI32.store(arr + arrIdx, lastStr, 8n)
|
|
384
501
|
|
|
385
502
|
WasmI32.toGrain(arr): Array<String>
|
|
386
503
|
}
|
|
387
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
388
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
504
|
+
Memory.decRef(WasmI32.fromGrain(separator))
|
|
505
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
389
506
|
Memory.decRef(WasmI32.fromGrain(split))
|
|
390
507
|
ret
|
|
391
508
|
}
|
|
392
509
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
510
|
+
/**
|
|
511
|
+
* Get a portion of a string.
|
|
512
|
+
*
|
|
513
|
+
* @param start: The start position of the substring
|
|
514
|
+
* @param to: The end position of the substring, exclusive
|
|
515
|
+
* @param string: The input string
|
|
516
|
+
* @returns The substring from the initial string
|
|
517
|
+
*
|
|
518
|
+
* @example String.slice(0, 5, "Hello world") == "Hello"
|
|
519
|
+
*
|
|
520
|
+
* @since v0.1.0
|
|
521
|
+
*/
|
|
398
522
|
@disableGC
|
|
399
|
-
export let rec slice = (start: Number, to: Number,
|
|
523
|
+
export let rec slice = (start: Number, to: Number, string: String) => {
|
|
400
524
|
let (+) = WasmI32.add
|
|
401
525
|
let (-) = WasmI32.sub
|
|
402
526
|
let (==) = WasmI32.eq
|
|
@@ -409,10 +533,10 @@ export let rec slice = (start: Number, to: Number, s: String) => {
|
|
|
409
533
|
let startOrig = start
|
|
410
534
|
let toOrig = to
|
|
411
535
|
|
|
412
|
-
let len = WasmI32.fromGrain(wasmSafeLength(
|
|
413
|
-
let size = WasmI32.fromGrain(wasmSafeByteLength(
|
|
536
|
+
let len = WasmI32.fromGrain(wasmSafeLength(string)) >> 1n
|
|
537
|
+
let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n
|
|
414
538
|
|
|
415
|
-
let
|
|
539
|
+
let string = WasmI32.fromGrain(string)
|
|
416
540
|
|
|
417
541
|
let mut start = WasmI32.fromGrain(start)
|
|
418
542
|
if ((start & 1n) != 1n) {
|
|
@@ -441,7 +565,7 @@ export let rec slice = (start: Number, to: Number, s: String) => {
|
|
|
441
565
|
throw InvalidArgument("Start index exceeds end index")
|
|
442
566
|
}
|
|
443
567
|
|
|
444
|
-
let mut ptr =
|
|
568
|
+
let mut ptr = string + 8n
|
|
445
569
|
let mut begin = ptr
|
|
446
570
|
let mut end = ptr
|
|
447
571
|
let stop = ptr + size
|
|
@@ -462,7 +586,7 @@ export let rec slice = (start: Number, to: Number, s: String) => {
|
|
|
462
586
|
ptr += 1n
|
|
463
587
|
}
|
|
464
588
|
if (to == len) {
|
|
465
|
-
end =
|
|
589
|
+
end = string + 8n + size
|
|
466
590
|
}
|
|
467
591
|
if (start == to) {
|
|
468
592
|
begin = end
|
|
@@ -476,17 +600,24 @@ export let rec slice = (start: Number, to: Number, s: String) => {
|
|
|
476
600
|
let ret = WasmI32.toGrain(newString): String
|
|
477
601
|
Memory.decRef(WasmI32.fromGrain(startOrig))
|
|
478
602
|
Memory.decRef(WasmI32.fromGrain(toOrig))
|
|
479
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
603
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
480
604
|
Memory.decRef(WasmI32.fromGrain(slice))
|
|
481
605
|
ret
|
|
482
606
|
}
|
|
483
607
|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
608
|
+
/**
|
|
609
|
+
* Check if a string contains a substring.
|
|
610
|
+
*
|
|
611
|
+
* @param search: The substring to check
|
|
612
|
+
* @param string: The string to search
|
|
613
|
+
* @returns `true` if the input string contains the search value or `false` otherwise
|
|
614
|
+
*
|
|
615
|
+
* @example String.contains("world", "Hello world") == true
|
|
616
|
+
*
|
|
617
|
+
* @since v0.1.0
|
|
618
|
+
*/
|
|
488
619
|
@disableGC
|
|
489
|
-
export let rec contains = (
|
|
620
|
+
export let rec contains = (search: String, string: String) => {
|
|
490
621
|
// "Not So Naive" string search algorithm
|
|
491
622
|
// searching phase in O(nm) time complexity
|
|
492
623
|
// slightly (by coefficient) sub-linear in the average case
|
|
@@ -500,17 +631,17 @@ export let rec contains = (p: String, s: String) => {
|
|
|
500
631
|
let (<=) = WasmI32.leU
|
|
501
632
|
let (>) = WasmI32.gtU
|
|
502
633
|
let (>>) = WasmI32.shrS
|
|
503
|
-
let pOrig =
|
|
504
|
-
let sOrig =
|
|
634
|
+
let pOrig = search
|
|
635
|
+
let sOrig = string
|
|
505
636
|
|
|
506
|
-
let n = WasmI32.fromGrain(wasmSafeByteLength(
|
|
507
|
-
let m = WasmI32.fromGrain(wasmSafeByteLength(
|
|
637
|
+
let n = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n
|
|
638
|
+
let m = WasmI32.fromGrain(wasmSafeByteLength(search)) >> 1n
|
|
508
639
|
|
|
509
|
-
let mut
|
|
510
|
-
let mut
|
|
640
|
+
let mut string = WasmI32.fromGrain(string)
|
|
641
|
+
let mut search = WasmI32.fromGrain(search)
|
|
511
642
|
|
|
512
|
-
|
|
513
|
-
|
|
643
|
+
string += 8n
|
|
644
|
+
search += 8n
|
|
514
645
|
|
|
515
646
|
let mut j = 0n, k = 0n, ell = 0n
|
|
516
647
|
|
|
@@ -522,10 +653,10 @@ export let rec contains = (p: String, s: String) => {
|
|
|
522
653
|
if (m == 0n) {
|
|
523
654
|
true
|
|
524
655
|
} else {
|
|
525
|
-
let pat = WasmI32.load8U(
|
|
656
|
+
let pat = WasmI32.load8U(search, 0n)
|
|
526
657
|
let mut result = false
|
|
527
658
|
while (j < n) {
|
|
528
|
-
if (pat == WasmI32.load8U(
|
|
659
|
+
if (pat == WasmI32.load8U(string + j, 0n)) {
|
|
529
660
|
result = true
|
|
530
661
|
break
|
|
531
662
|
} else {
|
|
@@ -536,7 +667,7 @@ export let rec contains = (p: String, s: String) => {
|
|
|
536
667
|
}
|
|
537
668
|
} else {
|
|
538
669
|
// NSM preprocessing
|
|
539
|
-
if (WasmI32.load8U(
|
|
670
|
+
if (WasmI32.load8U(search, 0n) == WasmI32.load8U(search, 1n)) {
|
|
540
671
|
k = 2n
|
|
541
672
|
ell = 1n
|
|
542
673
|
} else {
|
|
@@ -547,10 +678,10 @@ export let rec contains = (p: String, s: String) => {
|
|
|
547
678
|
let mut result = false
|
|
548
679
|
// NSM searching
|
|
549
680
|
while (j <= n - m) {
|
|
550
|
-
if (WasmI32.load8U(
|
|
681
|
+
if (WasmI32.load8U(search, 1n) != WasmI32.load8U(string + j, 1n)) {
|
|
551
682
|
j += k
|
|
552
683
|
} else {
|
|
553
|
-
if (Memory.compare(
|
|
684
|
+
if (Memory.compare(search + 2n, string + j + 2n, m - 2n) == 0n && WasmI32.load8U(search, 0n) == WasmI32.load8U(string + j, 0n)) {
|
|
554
685
|
result = true
|
|
555
686
|
break
|
|
556
687
|
}
|
|
@@ -565,32 +696,39 @@ export let rec contains = (p: String, s: String) => {
|
|
|
565
696
|
ret
|
|
566
697
|
}
|
|
567
698
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
699
|
+
/**
|
|
700
|
+
* Check if a string begins with another string.
|
|
701
|
+
*
|
|
702
|
+
* @param search: The string to compare to the start
|
|
703
|
+
* @param string: The string to search
|
|
704
|
+
* @returns `true` if the input string starts with the search value or `false` otherwise
|
|
705
|
+
*
|
|
706
|
+
* @example String.startsWith("Hello", "Hello world") == true
|
|
707
|
+
*
|
|
708
|
+
* @since v0.1.0
|
|
709
|
+
*/
|
|
572
710
|
@disableGC
|
|
573
|
-
export let rec startsWith = (
|
|
711
|
+
export let rec startsWith = (search: String, string: String) => {
|
|
574
712
|
let (+) = WasmI32.add
|
|
575
713
|
let (>) = WasmI32.gtU
|
|
576
714
|
let (==) = WasmI32.eq
|
|
577
|
-
let pOrig =
|
|
578
|
-
let sOrig =
|
|
715
|
+
let pOrig = search
|
|
716
|
+
let sOrig = string
|
|
579
717
|
|
|
580
|
-
let mut
|
|
581
|
-
let mut
|
|
718
|
+
let mut search = WasmI32.fromGrain(search)
|
|
719
|
+
let mut string = WasmI32.fromGrain(string)
|
|
582
720
|
|
|
583
|
-
let n = WasmI32.load(
|
|
584
|
-
let m = WasmI32.load(
|
|
721
|
+
let n = WasmI32.load(string, 4n)
|
|
722
|
+
let m = WasmI32.load(search, 4n)
|
|
585
723
|
|
|
586
|
-
|
|
587
|
-
|
|
724
|
+
string += 8n
|
|
725
|
+
search += 8n
|
|
588
726
|
|
|
589
727
|
// Bail if pattern length is longer than input length
|
|
590
728
|
let ret = if (m > n) {
|
|
591
729
|
false
|
|
592
730
|
} else {
|
|
593
|
-
Memory.compare(
|
|
731
|
+
Memory.compare(search, string, m) == 0n
|
|
594
732
|
}
|
|
595
733
|
Memory.decRef(WasmI32.fromGrain(pOrig))
|
|
596
734
|
Memory.decRef(WasmI32.fromGrain(sOrig))
|
|
@@ -598,33 +736,40 @@ export let rec startsWith = (p: String, s: String) => {
|
|
|
598
736
|
ret
|
|
599
737
|
}
|
|
600
738
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
739
|
+
/**
|
|
740
|
+
* Check if a string ends with another string.
|
|
741
|
+
*
|
|
742
|
+
* @param search: The string to compare to the end
|
|
743
|
+
* @param string: The string to search
|
|
744
|
+
* @returns `true` if the input string ends with the search value or `false` otherwise
|
|
745
|
+
*
|
|
746
|
+
* @example String.endsWith("world", "Hello world") == true
|
|
747
|
+
*
|
|
748
|
+
* @since v0.1.0
|
|
749
|
+
*/
|
|
605
750
|
@disableGC
|
|
606
|
-
export let rec endsWith = (
|
|
751
|
+
export let rec endsWith = (search: String, string: String) => {
|
|
607
752
|
let (+) = WasmI32.add
|
|
608
753
|
let (-) = WasmI32.sub
|
|
609
754
|
let (>) = WasmI32.gtU
|
|
610
755
|
let (==) = WasmI32.eq
|
|
611
|
-
let pOrig =
|
|
612
|
-
let sOrig =
|
|
756
|
+
let pOrig = search
|
|
757
|
+
let sOrig = string
|
|
613
758
|
|
|
614
|
-
let mut
|
|
615
|
-
let mut
|
|
759
|
+
let mut search = WasmI32.fromGrain(search)
|
|
760
|
+
let mut string = WasmI32.fromGrain(string)
|
|
616
761
|
|
|
617
|
-
let n = WasmI32.load(
|
|
618
|
-
let m = WasmI32.load(
|
|
762
|
+
let n = WasmI32.load(string, 4n)
|
|
763
|
+
let m = WasmI32.load(search, 4n)
|
|
619
764
|
|
|
620
|
-
|
|
621
|
-
|
|
765
|
+
string += 8n
|
|
766
|
+
search += 8n
|
|
622
767
|
|
|
623
768
|
// Bail if pattern length is longer than input length
|
|
624
769
|
let ret = if (m > n) {
|
|
625
770
|
false
|
|
626
771
|
} else {
|
|
627
|
-
Memory.compare(
|
|
772
|
+
Memory.compare(search, string + n - m, m) == 0n
|
|
628
773
|
}
|
|
629
774
|
Memory.decRef(WasmI32.fromGrain(pOrig))
|
|
630
775
|
Memory.decRef(WasmI32.fromGrain(sOrig))
|
|
@@ -632,14 +777,6 @@ export let rec endsWith = (p: String, s: String) => {
|
|
|
632
777
|
ret
|
|
633
778
|
}
|
|
634
779
|
|
|
635
|
-
export enum Encoding {
|
|
636
|
-
UTF8,
|
|
637
|
-
UTF16_BE,
|
|
638
|
-
UTF16_LE,
|
|
639
|
-
UTF32_BE,
|
|
640
|
-
UTF32_LE,
|
|
641
|
-
}
|
|
642
|
-
|
|
643
780
|
// String->Byte encoding and helper functions:
|
|
644
781
|
|
|
645
782
|
// these are globals to avoid memory leaks
|
|
@@ -775,7 +912,6 @@ let getCodePoint = (ptr: WasmI32) => {
|
|
|
775
912
|
}
|
|
776
913
|
continue
|
|
777
914
|
}
|
|
778
|
-
Memory.incRef(WasmI32.fromGrain((!)))
|
|
779
915
|
if (!(lowerBoundary <= byte && byte <= upperBoundary)) {
|
|
780
916
|
throw MalformedUnicode
|
|
781
917
|
}
|
|
@@ -804,15 +940,8 @@ let initPtr = () => {
|
|
|
804
940
|
}
|
|
805
941
|
initPtr();
|
|
806
942
|
|
|
807
|
-
// Encodes the given string using the given encoding scheme
|
|
808
|
-
// @param s: String - The input string
|
|
809
|
-
// @param encoding: Encoding - The encoding to use
|
|
810
|
-
// @param includeBom: Bool - Whether to include the byte-order marker in the encoded output
|
|
811
|
-
// @param dest: Bytes - The bytes object to write the encoded output into
|
|
812
|
-
// @param destPos: Number - The location in the byte array to write the output
|
|
813
|
-
// @returns Bytes - Returns `dest`
|
|
814
943
|
@disableGC
|
|
815
|
-
let rec encodeAtHelp = (
|
|
944
|
+
let rec encodeAtHelp = (string: String, encoding: Encoding, includeBom: Bool, dest: Bytes, destPos: Number) => {
|
|
816
945
|
let (>>>) = WasmI32.shrU
|
|
817
946
|
let (-) = WasmI32.sub
|
|
818
947
|
let (&) = WasmI32.and
|
|
@@ -821,12 +950,12 @@ let rec encodeAtHelp = (s: String, encoding: Encoding, includeBom: Bool, dest: B
|
|
|
821
950
|
let (<=) = WasmI32.leU
|
|
822
951
|
let (==) = WasmI32.eq
|
|
823
952
|
let (+) = WasmI32.add
|
|
824
|
-
let byteSize = WasmI32.fromGrain(wasmSafeByteLength(
|
|
825
|
-
let len = WasmI32.fromGrain(wasmSafeLength(
|
|
953
|
+
let byteSize = WasmI32.fromGrain(wasmSafeByteLength(string)) >>> 1n
|
|
954
|
+
let len = WasmI32.fromGrain(wasmSafeLength(string)) >>> 1n
|
|
826
955
|
|
|
827
|
-
let
|
|
956
|
+
let string = WasmI32.fromGrain(string)
|
|
828
957
|
|
|
829
|
-
let mut ptr =
|
|
958
|
+
let mut ptr = string + 8n
|
|
830
959
|
let end = ptr + byteSize
|
|
831
960
|
|
|
832
961
|
let bytes = WasmI32.fromGrain(dest)
|
|
@@ -995,45 +1124,50 @@ let rec encodeAtHelp = (s: String, encoding: Encoding, includeBom: Bool, dest: B
|
|
|
995
1124
|
}
|
|
996
1125
|
}
|
|
997
1126
|
|
|
998
|
-
|
|
999
|
-
Memory.decRef(WasmI32.fromGrain(s))
|
|
1127
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
1000
1128
|
Memory.decRef(WasmI32.fromGrain(encoding))
|
|
1001
1129
|
Memory.decRef(WasmI32.fromGrain(includeBom))
|
|
1002
|
-
Memory.decRef(WasmI32.fromGrain(dest))
|
|
1003
1130
|
Memory.decRef(WasmI32.fromGrain(destPos))
|
|
1004
1131
|
Memory.decRef(WasmI32.fromGrain(encodeAtHelp))
|
|
1005
|
-
|
|
1132
|
+
|
|
1133
|
+
// We don't decRef `dest` because we're returning it
|
|
1134
|
+
dest
|
|
1006
1135
|
}
|
|
1007
1136
|
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1137
|
+
/**
|
|
1138
|
+
* Encodes the given string into a byte sequence at the supplied position, excluding any byte-order marker, using the encoding scheme provided.
|
|
1139
|
+
*
|
|
1140
|
+
* @param string: The input string
|
|
1141
|
+
* @param encoding: The encoding to use
|
|
1142
|
+
* @param dest: The byte sequence that will be copied
|
|
1143
|
+
* @param destPos: The location in the byte sequence to write the output
|
|
1144
|
+
* @returns A copy of the input bytes with the encoded string replaced at the given position
|
|
1145
|
+
*
|
|
1146
|
+
* @since v0.4.0
|
|
1147
|
+
*/
|
|
1148
|
+
export let encodeAt = (string, encoding, dest, destPos) => {
|
|
1149
|
+
encodeAtHelp(string, encoding, false, dest, destPos)
|
|
1016
1150
|
}
|
|
1017
1151
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1152
|
+
/**
|
|
1153
|
+
* Encodes the given string into a byte sequence at the supplied position, including any byte-order marker, using the encoding scheme provided.
|
|
1154
|
+
*
|
|
1155
|
+
* @param string: The input string
|
|
1156
|
+
* @param encoding: The encoding to use
|
|
1157
|
+
* @param dest: The byte sequence that will be copied
|
|
1158
|
+
* @param destPos: The location in the byte sequence to write the output
|
|
1159
|
+
* @returns A copy of the input bytes with the encoded string replaced at the given position
|
|
1160
|
+
*
|
|
1161
|
+
* @since v0.4.0
|
|
1162
|
+
*/
|
|
1163
|
+
export let encodeAtWithBom = (string, encoding, dest, destPos) => {
|
|
1164
|
+
encodeAtHelp(string, encoding, true, dest, destPos)
|
|
1026
1165
|
}
|
|
1027
1166
|
|
|
1028
|
-
// Encodes the given string using the given encoding scheme
|
|
1029
|
-
// @param s: String - The input string
|
|
1030
|
-
// @param encoding: Encoding - The encoding to use
|
|
1031
|
-
// @param includeBom: Bool - Whether to include the byte-order marker in the encoded output
|
|
1032
|
-
// @returns Bytes
|
|
1033
1167
|
@disableGC
|
|
1034
|
-
let rec encodeHelp = (
|
|
1168
|
+
let rec encodeHelp = (string: String, encoding: Encoding, includeBom: Bool) => {
|
|
1035
1169
|
Memory.incRef(WasmI32.fromGrain((+)))
|
|
1036
|
-
let size = encodedLength(
|
|
1170
|
+
let size = encodedLength(string, encoding) + if (includeBom) {
|
|
1037
1171
|
match(encoding) {
|
|
1038
1172
|
UTF8 => 3,
|
|
1039
1173
|
UTF16_LE => 2,
|
|
@@ -1045,33 +1179,42 @@ let rec encodeHelp = (s: String, encoding: Encoding, includeBom: Bool) => {
|
|
|
1045
1179
|
let (>>>) = WasmI32.shrU
|
|
1046
1180
|
let bytes = WasmI32.toGrain(allocateBytes(WasmI32.fromGrain(size) >>> 1n))
|
|
1047
1181
|
Memory.incRef(WasmI32.fromGrain(encodeAtHelp))
|
|
1048
|
-
Memory.incRef(WasmI32.fromGrain(
|
|
1182
|
+
Memory.incRef(WasmI32.fromGrain(string))
|
|
1049
1183
|
Memory.incRef(WasmI32.fromGrain(encoding))
|
|
1050
1184
|
Memory.incRef(WasmI32.fromGrain(includeBom))
|
|
1051
1185
|
Memory.incRef(WasmI32.fromGrain(bytes))
|
|
1052
|
-
let ret = encodeAtHelp(
|
|
1053
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
1186
|
+
let ret = encodeAtHelp(string, encoding, includeBom, bytes, 0)
|
|
1187
|
+
Memory.decRef(WasmI32.fromGrain(string))
|
|
1054
1188
|
Memory.decRef(WasmI32.fromGrain(encoding))
|
|
1055
1189
|
Memory.decRef(WasmI32.fromGrain(includeBom))
|
|
1056
1190
|
Memory.decRef(WasmI32.fromGrain(encodeHelp))
|
|
1057
1191
|
ret
|
|
1058
1192
|
}
|
|
1059
1193
|
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1194
|
+
/**
|
|
1195
|
+
* Encodes the given string using the given encoding scheme, excluding any byte-order marker.
|
|
1196
|
+
*
|
|
1197
|
+
* @param string: The input string
|
|
1198
|
+
* @param encoding: The encoding to use
|
|
1199
|
+
* @returns The byte representation of the string in the given encoding
|
|
1200
|
+
*
|
|
1201
|
+
* @since v0.4.0
|
|
1202
|
+
*/
|
|
1203
|
+
export let encode = (string: String, encoding: Encoding) => {
|
|
1204
|
+
encodeHelp(string, encoding, false)
|
|
1067
1205
|
}
|
|
1068
1206
|
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1207
|
+
/**
|
|
1208
|
+
* Encodes the given string using the given encoding scheme, including any byte-order marker.
|
|
1209
|
+
*
|
|
1210
|
+
* @param string: The input string
|
|
1211
|
+
* @param encoding: The encoding to use
|
|
1212
|
+
* @returns The byte representation of the string in the given encoding
|
|
1213
|
+
*
|
|
1214
|
+
* @since v0.4.0
|
|
1215
|
+
*/
|
|
1216
|
+
export let encodeWithBom = (string: String, encoding: Encoding) => {
|
|
1217
|
+
encodeHelp(string, encoding, true)
|
|
1075
1218
|
}
|
|
1076
1219
|
|
|
1077
1220
|
// Byte->String decoding and helper functions:
|
|
@@ -1315,13 +1458,6 @@ let decodedLength = (bytes: Bytes, encoding: Encoding, start: WasmI32, size: Was
|
|
|
1315
1458
|
}
|
|
1316
1459
|
}
|
|
1317
1460
|
|
|
1318
|
-
// Decodes the given byte sequence into a string using the given encoding scheme
|
|
1319
|
-
// @param bytes: Bytes - The input bytes
|
|
1320
|
-
// @param encoding: Encoding - The encoding to use
|
|
1321
|
-
// @param skipBom: Bool - Whether to include the byte-order marker (if present) in the decoded output
|
|
1322
|
-
// @param start: Number - The byte offset to begin decoding from
|
|
1323
|
-
// @param size: Number - The maximum number of bytes to decode
|
|
1324
|
-
// @returns String
|
|
1325
1461
|
@disableGC
|
|
1326
1462
|
let rec decodeRangeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool, start: Number, size: Number) => {
|
|
1327
1463
|
let (+) = WasmI32.add
|
|
@@ -1438,33 +1574,36 @@ let rec decodeRangeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool, star
|
|
|
1438
1574
|
ret
|
|
1439
1575
|
}
|
|
1440
1576
|
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1577
|
+
/**
|
|
1578
|
+
* Decodes the given byte sequence of the specified range into a string, excluding any byte-order marker, using encoding scheme provided.
|
|
1579
|
+
*
|
|
1580
|
+
* @param bytes: The input bytes
|
|
1581
|
+
* @param encoding: The encoding to use
|
|
1582
|
+
* @param start: The byte offset to begin decoding from
|
|
1583
|
+
* @param size: The maximum number of bytes to decode
|
|
1584
|
+
* @returns The decoded string
|
|
1585
|
+
*
|
|
1586
|
+
* @since v0.4.0
|
|
1587
|
+
*/
|
|
1448
1588
|
export let decodeRange = (bytes: Bytes, encoding: Encoding, start: Number, size: Number) => {
|
|
1449
1589
|
decodeRangeHelp(bytes, encoding, true, start, size)
|
|
1450
1590
|
}
|
|
1451
1591
|
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1592
|
+
/**
|
|
1593
|
+
* Decodes the given byte sequence of the specified range into a string, including any byte-order marker, using encoding scheme provided.
|
|
1594
|
+
*
|
|
1595
|
+
* @param bytes: The input bytes
|
|
1596
|
+
* @param encoding: The encoding to use
|
|
1597
|
+
* @param start: The byte offset to begin decoding from
|
|
1598
|
+
* @param size: The maximum number of bytes to decode
|
|
1599
|
+
* @returns The decoded string
|
|
1600
|
+
*
|
|
1601
|
+
* @since v0.4.0
|
|
1602
|
+
*/
|
|
1459
1603
|
export let decodeRangeKeepBom = (bytes: Bytes, encoding: Encoding, start: Number, size: Number) => {
|
|
1460
1604
|
decodeRangeHelp(bytes, encoding, false, start, size)
|
|
1461
1605
|
}
|
|
1462
1606
|
|
|
1463
|
-
// Decodes the given byte sequence into a string using the given encoding scheme
|
|
1464
|
-
// @param bytes: Bytes - The input bytes
|
|
1465
|
-
// @param encoding: Encoding - The encoding to use
|
|
1466
|
-
// @param skipBom: Bool - Whether to include the byte-order marker (if present) in the decoded output
|
|
1467
|
-
// @returns String
|
|
1468
1607
|
@disableGC
|
|
1469
1608
|
let rec decodeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool) => {
|
|
1470
1609
|
let bytesPtr = WasmI32.fromGrain(bytes)
|
|
@@ -1479,20 +1618,28 @@ let rec decodeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool) => {
|
|
|
1479
1618
|
ret
|
|
1480
1619
|
}
|
|
1481
1620
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1621
|
+
/**
|
|
1622
|
+
* Decodes the given byte sequence into a string using the given encoding scheme, excluding any byte-order marker.
|
|
1623
|
+
*
|
|
1624
|
+
* @param bytes: The input bytes
|
|
1625
|
+
* @param encoding: The encoding to use
|
|
1626
|
+
* @returns The decoded string
|
|
1627
|
+
*
|
|
1628
|
+
* @since v0.4.0
|
|
1629
|
+
*/
|
|
1487
1630
|
export let decode = (bytes: Bytes, encoding: Encoding) => {
|
|
1488
1631
|
decodeHelp(bytes, encoding, true)
|
|
1489
1632
|
}
|
|
1490
1633
|
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1634
|
+
/**
|
|
1635
|
+
* Decodes the given byte sequence into a string using the given encoding scheme, including any byte-order marker.
|
|
1636
|
+
*
|
|
1637
|
+
* @param bytes: The input bytes
|
|
1638
|
+
* @param encoding: The encoding to use
|
|
1639
|
+
* @returns The decoded string
|
|
1640
|
+
*
|
|
1641
|
+
* @since v0.4.0
|
|
1642
|
+
*/
|
|
1496
1643
|
export let decodeKeepBom = (bytes: Bytes, encoding: Encoding) => {
|
|
1497
1644
|
decodeHelp(bytes, encoding, false)
|
|
1498
1645
|
}
|
|
@@ -1502,6 +1649,10 @@ export let decodeKeepBom = (bytes: Bytes, encoding: Encoding) => {
|
|
|
1502
1649
|
*
|
|
1503
1650
|
* @param fn: The iterator function
|
|
1504
1651
|
* @param str: The string to iterate
|
|
1652
|
+
*
|
|
1653
|
+
* @example String.forEachCodePoint(print, "Hello world")
|
|
1654
|
+
*
|
|
1655
|
+
* @since v0.4.0
|
|
1505
1656
|
*/
|
|
1506
1657
|
@disableGC
|
|
1507
1658
|
export let rec forEachCodePoint = (fn: (Number) -> Void, str: String) => {
|
|
@@ -1560,6 +1711,10 @@ export let rec forEachCodePoint = (fn: (Number) -> Void, str: String) => {
|
|
|
1560
1711
|
*
|
|
1561
1712
|
* @param fn: The iterator function
|
|
1562
1713
|
* @param str: The string to iterate
|
|
1714
|
+
*
|
|
1715
|
+
* @example String.forEachCodePointi((codepoint, index) => print((codepoint, index)), "Hello world")
|
|
1716
|
+
*
|
|
1717
|
+
* @since v0.4.0
|
|
1563
1718
|
*/
|
|
1564
1719
|
@disableGC
|
|
1565
1720
|
export let rec forEachCodePointi = (fn: (Number, Number) -> Void, str: String) => {
|
|
@@ -1610,3 +1765,62 @@ export let rec forEachCodePointi = (fn: (Number, Number) -> Void, str: String) =
|
|
|
1610
1765
|
Memory.decRef(WasmI32.fromGrain(forEachCodePointi))
|
|
1611
1766
|
void
|
|
1612
1767
|
}
|
|
1768
|
+
let trimString = (str: String, end: Bool) => {
|
|
1769
|
+
let chars = explode(str), charsLength = length(str)
|
|
1770
|
+
let mut i = 0, offset = 1
|
|
1771
|
+
if (end) {
|
|
1772
|
+
i = charsLength-1
|
|
1773
|
+
offset = -1
|
|
1774
|
+
}
|
|
1775
|
+
for (; i < charsLength && i > -1; i += offset) {
|
|
1776
|
+
let currentChar = chars[i];
|
|
1777
|
+
// TODO: Use unicode whitespace property and unicode line terminator once github issue #661 is completed
|
|
1778
|
+
if (
|
|
1779
|
+
// Spacing
|
|
1780
|
+
currentChar != '\u{0009}' && // Tab
|
|
1781
|
+
currentChar != '\u{000B}' && // LINE TABULATION
|
|
1782
|
+
currentChar != '\u{000C}' && // FORM FEED (FF)
|
|
1783
|
+
currentChar != '\u{0020}' && // Space
|
|
1784
|
+
currentChar != '\u{00A0}' && // No Break Space
|
|
1785
|
+
currentChar != '\u{FEFF}' && // ZERO WIDTH NO-BREAK SPACE
|
|
1786
|
+
// Line Terminators
|
|
1787
|
+
currentChar != '\n' && // LF
|
|
1788
|
+
currentChar != '\r' // CR
|
|
1789
|
+
) break
|
|
1790
|
+
}
|
|
1791
|
+
if (end) slice(0, i+1, str)
|
|
1792
|
+
else slice(i, charsLength, str)
|
|
1793
|
+
}
|
|
1794
|
+
/**
|
|
1795
|
+
* Trims the beginning of a string—removing any leading whitespace characters.
|
|
1796
|
+
*
|
|
1797
|
+
* @param string: The string to be trimmed
|
|
1798
|
+
* @returns The trimmed string
|
|
1799
|
+
*
|
|
1800
|
+
* @example String.trimStart(" Hello World") == "Hello World"
|
|
1801
|
+
*
|
|
1802
|
+
* @since v0.4.2
|
|
1803
|
+
*/
|
|
1804
|
+
export let trimStart = (string: String) => trimString(string, false)
|
|
1805
|
+
/**
|
|
1806
|
+
* Trims the end of a string—removing any trailing whitespace characters.
|
|
1807
|
+
*
|
|
1808
|
+
* @param string: The string to be trimmed
|
|
1809
|
+
* @returns The trimmed string
|
|
1810
|
+
*
|
|
1811
|
+
* @example String.trimEnd("Hello World ") == "Hello World"
|
|
1812
|
+
*
|
|
1813
|
+
* @since v0.4.2
|
|
1814
|
+
*/
|
|
1815
|
+
export let trimEnd = (string: String) => trimString(string, true)
|
|
1816
|
+
/**
|
|
1817
|
+
* Trims a string—removing all leading and trailing whitespace characters.
|
|
1818
|
+
*
|
|
1819
|
+
* @param string: The string to be trimmed
|
|
1820
|
+
* @returns The trimmed string
|
|
1821
|
+
*
|
|
1822
|
+
* @example String.trim(" Hello World ") == "Hello World"
|
|
1823
|
+
*
|
|
1824
|
+
* @since v0.4.2
|
|
1825
|
+
*/
|
|
1826
|
+
export let trim = (string: String) => trimEnd(trimStart(string))
|