@grain/stdlib 0.5.13 → 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 +193 -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/string.gr
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Utilities for working with strings.
|
|
3
|
+
*
|
|
4
|
+
* @example from "string" include String
|
|
4
5
|
*
|
|
5
6
|
* @since v0.2.0
|
|
6
7
|
* @history v0.1.0: Originally named `strings`
|
|
7
8
|
* @history v0.2.0: Renamed to `string`
|
|
8
9
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
module String
|
|
11
|
+
|
|
12
|
+
from "char" include Char
|
|
13
|
+
from "runtime/unsafe/wasmi32" include WasmI32
|
|
14
|
+
from "runtime/unsafe/memory" include Memory
|
|
15
|
+
from "runtime/exception" include Exception
|
|
16
|
+
from "runtime/unsafe/conv" include Conv
|
|
17
|
+
from "runtime/dataStructures" include DataStructures
|
|
18
|
+
use DataStructures.{
|
|
14
19
|
untagSimpleNumber,
|
|
15
20
|
tagSimpleNumber,
|
|
16
21
|
tagChar,
|
|
@@ -18,16 +23,12 @@ import {
|
|
|
18
23
|
allocateArray,
|
|
19
24
|
allocateString,
|
|
20
25
|
allocateBytes,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* @section Types: Type declarations included in the String module.
|
|
25
|
-
*/
|
|
26
|
+
}
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Byte encodings
|
|
29
30
|
*/
|
|
30
|
-
|
|
31
|
+
provide enum Encoding {
|
|
31
32
|
UTF8,
|
|
32
33
|
UTF16_BE,
|
|
33
34
|
UTF16_LE,
|
|
@@ -37,10 +38,6 @@ export enum Encoding {
|
|
|
37
38
|
|
|
38
39
|
exception MalformedUnicode
|
|
39
40
|
|
|
40
|
-
/**
|
|
41
|
-
* @section Values: Functions for working with the String data type.
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
41
|
/**
|
|
45
42
|
* Concatenate two strings.
|
|
46
43
|
*
|
|
@@ -52,7 +49,7 @@ exception MalformedUnicode
|
|
|
52
49
|
*
|
|
53
50
|
* @since v0.2.0
|
|
54
51
|
*/
|
|
55
|
-
|
|
52
|
+
provide let concat = (++)
|
|
56
53
|
|
|
57
54
|
/**
|
|
58
55
|
* Returns the character length of the input string.
|
|
@@ -65,20 +62,21 @@ export let concat = (++)
|
|
|
65
62
|
* @since v0.1.0
|
|
66
63
|
*/
|
|
67
64
|
@unsafe
|
|
68
|
-
|
|
65
|
+
provide let length = (string: String) => {
|
|
66
|
+
use WasmI32.{ (+), (&), (!=) }
|
|
69
67
|
let string = WasmI32.fromGrain(string)
|
|
70
68
|
let size = WasmI32.load(string, 4n)
|
|
71
69
|
|
|
72
70
|
let mut len = 0n
|
|
73
|
-
let mut ptr =
|
|
74
|
-
let end =
|
|
71
|
+
let mut ptr = string + 8n
|
|
72
|
+
let end = ptr + size
|
|
75
73
|
|
|
76
74
|
while (WasmI32.ltU(ptr, end)) {
|
|
77
75
|
let byte = WasmI32.load8U(ptr, 0n)
|
|
78
|
-
if (
|
|
79
|
-
len
|
|
76
|
+
if ((byte & 0xC0n) != 0x80n) {
|
|
77
|
+
len += 1n
|
|
80
78
|
}
|
|
81
|
-
ptr
|
|
79
|
+
ptr += 1n
|
|
82
80
|
}
|
|
83
81
|
|
|
84
82
|
Conv.wasmI32ToNumber(len)
|
|
@@ -95,11 +93,26 @@ export let length = (string: String) => {
|
|
|
95
93
|
* @since v0.1.0
|
|
96
94
|
*/
|
|
97
95
|
@unsafe
|
|
98
|
-
|
|
96
|
+
provide let byteLength = (string: String) => {
|
|
99
97
|
let string = WasmI32.fromGrain(string)
|
|
100
98
|
Conv.wasmI32ToNumber(WasmI32.load(string, 4n))
|
|
101
99
|
}
|
|
102
100
|
|
|
101
|
+
/**
|
|
102
|
+
* Determines if the string contains no characters.
|
|
103
|
+
*
|
|
104
|
+
* @param string: The string to inspect
|
|
105
|
+
* @returns `true` if the string is empty and `false` otherwise
|
|
106
|
+
*
|
|
107
|
+
* @since v0.6.0
|
|
108
|
+
*/
|
|
109
|
+
@unsafe
|
|
110
|
+
provide let isEmpty = (string: String) => {
|
|
111
|
+
use WasmI32.{ (==) }
|
|
112
|
+
let strPtr = WasmI32.fromGrain(string)
|
|
113
|
+
WasmI32.load(strPtr, 4n) == 0n
|
|
114
|
+
}
|
|
115
|
+
|
|
103
116
|
/**
|
|
104
117
|
* Finds the first position of a substring in the input string.
|
|
105
118
|
*
|
|
@@ -112,54 +125,40 @@ export let byteLength = (string: String) => {
|
|
|
112
125
|
* @since v0.3.0
|
|
113
126
|
*/
|
|
114
127
|
@unsafe
|
|
115
|
-
|
|
128
|
+
provide let indexOf = (search: String, string: String) => {
|
|
116
129
|
let search = WasmI32.fromGrain(search)
|
|
117
130
|
let string = WasmI32.fromGrain(string)
|
|
118
131
|
|
|
119
132
|
let size = WasmI32.load(string, 4n)
|
|
120
133
|
let psize = WasmI32.load(search, 4n)
|
|
121
|
-
|
|
122
|
-
let (>) = WasmI32.gtU
|
|
123
|
-
let (<) = WasmI32.ltU
|
|
124
|
-
let (==) = WasmI32.eq
|
|
125
|
-
let (+) = WasmI32.add
|
|
126
|
-
let (-) = WasmI32.sub
|
|
127
|
-
let (&) = WasmI32.and
|
|
134
|
+
use WasmI32.{ (+), (-), (&), ltU as (<), gtU as (>), (==) }
|
|
128
135
|
|
|
129
136
|
if (psize > size) {
|
|
130
|
-
None
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
let mut result = -1n
|
|
137
|
+
return None
|
|
138
|
+
}
|
|
139
|
+
let mut idx = 0n
|
|
140
|
+
let mut ptr = string + 8n
|
|
141
|
+
let pptr = search + 8n
|
|
142
|
+
let end = ptr + size - psize + 1n
|
|
138
143
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
break
|
|
143
|
-
}
|
|
144
|
-
idx += 1n
|
|
145
|
-
let byte = WasmI32.load8U(ptr, 0n)
|
|
146
|
-
if ((byte & 0x80n) == 0x00n) {
|
|
147
|
-
ptr += 1n
|
|
148
|
-
} else if ((byte & 0xF0n) == 0xF0n) {
|
|
149
|
-
ptr += 4n
|
|
150
|
-
} else if ((byte & 0xE0n) == 0xE0n) {
|
|
151
|
-
ptr += 3n
|
|
152
|
-
} else {
|
|
153
|
-
ptr += 2n
|
|
154
|
-
}
|
|
144
|
+
while (ptr < end) {
|
|
145
|
+
if (Memory.compare(ptr, pptr, psize) == 0n) {
|
|
146
|
+
return Some(tagSimpleNumber(idx))
|
|
155
147
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
148
|
+
idx += 1n
|
|
149
|
+
let byte = WasmI32.load8U(ptr, 0n)
|
|
150
|
+
if ((byte & 0x80n) == 0x00n) {
|
|
151
|
+
ptr += 1n
|
|
152
|
+
} else if ((byte & 0xF0n) == 0xF0n) {
|
|
153
|
+
ptr += 4n
|
|
154
|
+
} else if ((byte & 0xE0n) == 0xE0n) {
|
|
155
|
+
ptr += 3n
|
|
159
156
|
} else {
|
|
160
|
-
|
|
157
|
+
ptr += 2n
|
|
161
158
|
}
|
|
162
159
|
}
|
|
160
|
+
|
|
161
|
+
return None
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
/**
|
|
@@ -174,63 +173,45 @@ export let indexOf = (search: String, string: String) => {
|
|
|
174
173
|
* @since v0.5.3
|
|
175
174
|
*/
|
|
176
175
|
@unsafe
|
|
177
|
-
|
|
176
|
+
provide let lastIndexOf = (search: String, string: String) => {
|
|
178
177
|
// The last possible index in the string given the length of the search
|
|
179
178
|
let lastIndex = length(string) - length(search)
|
|
180
179
|
|
|
181
|
-
|
|
182
|
-
let (>=) = WasmI32.geU
|
|
183
|
-
let (==) = WasmI32.eq
|
|
184
|
-
let (!=) = WasmI32.ne
|
|
185
|
-
let (+) = WasmI32.add
|
|
186
|
-
let (-) = WasmI32.sub
|
|
187
|
-
let (&) = WasmI32.and
|
|
180
|
+
use WasmI32.{ (+), (-), (&), gtU as (>), geU as (>=), (==), (!=) }
|
|
188
181
|
|
|
189
182
|
let search = WasmI32.fromGrain(search)
|
|
190
183
|
let string = WasmI32.fromGrain(string)
|
|
191
184
|
let searchSize = WasmI32.load(search, 4n)
|
|
192
185
|
let stringSize = WasmI32.load(string, 4n)
|
|
193
186
|
if (searchSize > stringSize) {
|
|
194
|
-
None
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
continue
|
|
209
|
-
}
|
|
210
|
-
if (Memory.compare(stringPtr, searchPtr, searchSize) == 0n) {
|
|
211
|
-
matchIndex = stringIndex
|
|
212
|
-
break
|
|
213
|
-
}
|
|
214
|
-
stringIndex -= 1n
|
|
187
|
+
return None
|
|
188
|
+
}
|
|
189
|
+
let mut stringIndex = untagSimpleNumber(lastIndex)
|
|
190
|
+
let searchPtr = search + 8n
|
|
191
|
+
let stringStartPtr = string + 8n
|
|
192
|
+
for (
|
|
193
|
+
let mut stringPtr = stringStartPtr + stringSize - searchSize;
|
|
194
|
+
stringPtr >= stringStartPtr;
|
|
195
|
+
stringPtr -= 1n
|
|
196
|
+
) {
|
|
197
|
+
let byte = WasmI32.load8U(stringPtr, 0n)
|
|
198
|
+
if ((byte & 0xC0n) == 0x80n) {
|
|
199
|
+
// We're not at the start of a codepoint, so move on
|
|
200
|
+
continue
|
|
215
201
|
}
|
|
216
|
-
if (
|
|
217
|
-
|
|
218
|
-
} else {
|
|
219
|
-
Some(tagSimpleNumber(matchIndex))
|
|
202
|
+
if (Memory.compare(stringPtr, searchPtr, searchSize) == 0n) {
|
|
203
|
+
return Some(tagSimpleNumber(stringIndex))
|
|
220
204
|
}
|
|
205
|
+
stringIndex -= 1n
|
|
221
206
|
}
|
|
207
|
+
|
|
208
|
+
return None
|
|
222
209
|
}
|
|
223
210
|
|
|
224
211
|
@unsafe
|
|
225
212
|
let getCodePoint = (ptr: WasmI32) => {
|
|
226
213
|
// Algorithm from https://encoding.spec.whatwg.org/#utf-8-decoder
|
|
227
|
-
|
|
228
|
-
let (==) = WasmI32.eq
|
|
229
|
-
let (>=) = WasmI32.geU
|
|
230
|
-
let (<=) = WasmI32.leU
|
|
231
|
-
let (<<) = WasmI32.shl
|
|
232
|
-
let (&) = WasmI32.and
|
|
233
|
-
let (|) = WasmI32.or
|
|
214
|
+
use WasmI32.{ (+), (&), (|), (<<), leU as (<=), geU as (>=), (==) }
|
|
234
215
|
|
|
235
216
|
let mut codePoint = 0n
|
|
236
217
|
let mut bytesSeen = 0n
|
|
@@ -240,15 +221,12 @@ let getCodePoint = (ptr: WasmI32) => {
|
|
|
240
221
|
|
|
241
222
|
let mut offset = 0n
|
|
242
223
|
|
|
243
|
-
let mut result = 0n
|
|
244
|
-
|
|
245
224
|
while (true) {
|
|
246
225
|
let byte = WasmI32.load8U(ptr + offset, 0n)
|
|
247
226
|
offset += 1n
|
|
248
227
|
if (bytesNeeded == 0n) {
|
|
249
228
|
if (byte >= 0x00n && byte <= 0x7Fn) {
|
|
250
|
-
|
|
251
|
-
break
|
|
229
|
+
return byte
|
|
252
230
|
} else if (byte >= 0xC2n && byte <= 0xDFn) {
|
|
253
231
|
bytesNeeded = 1n
|
|
254
232
|
codePoint = byte & 0x1Fn
|
|
@@ -275,11 +253,10 @@ let getCodePoint = (ptr: WasmI32) => {
|
|
|
275
253
|
codePoint = codePoint << 6n | byte & 0x3Fn
|
|
276
254
|
bytesSeen += 1n
|
|
277
255
|
if (bytesSeen == bytesNeeded) {
|
|
278
|
-
|
|
279
|
-
break
|
|
256
|
+
return codePoint
|
|
280
257
|
}
|
|
281
258
|
}
|
|
282
|
-
|
|
259
|
+
return 0n
|
|
283
260
|
}
|
|
284
261
|
|
|
285
262
|
@unsafe
|
|
@@ -288,22 +265,16 @@ let charAtHelp = (position, string: String) => {
|
|
|
288
265
|
fail "Invalid offset: " ++ toString(position)
|
|
289
266
|
}
|
|
290
267
|
// Implementation is similar to explodeHelp, but doesn't perform unneeded memory allocations
|
|
291
|
-
|
|
292
|
-
let (+) = WasmI32.add
|
|
293
|
-
let (&) = WasmI32.and
|
|
294
|
-
let (<) = WasmI32.ltU
|
|
295
|
-
let (==) = WasmI32.eq
|
|
268
|
+
use WasmI32.{ (+), (&), (>>>), ltU as (<), (==) }
|
|
296
269
|
let size = WasmI32.fromGrain(byteLength(string)) >>> 1n
|
|
297
270
|
let position = WasmI32.fromGrain(position) >>> 1n
|
|
298
271
|
let string = WasmI32.fromGrain(string)
|
|
299
272
|
let mut ptr = string + 8n
|
|
300
273
|
let end = ptr + size
|
|
301
274
|
let mut counter = 0n
|
|
302
|
-
let mut result = 0n
|
|
303
275
|
while (ptr < end) {
|
|
304
276
|
if (counter == position) {
|
|
305
|
-
|
|
306
|
-
break
|
|
277
|
+
return getCodePoint(ptr)
|
|
307
278
|
}
|
|
308
279
|
let byte = WasmI32.load8U(ptr, 0n)
|
|
309
280
|
let n = if ((byte & 0x80n) == 0x00n) {
|
|
@@ -318,10 +289,8 @@ let charAtHelp = (position, string: String) => {
|
|
|
318
289
|
counter += 1n
|
|
319
290
|
ptr += n
|
|
320
291
|
}
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
}
|
|
324
|
-
result
|
|
292
|
+
|
|
293
|
+
fail "charAt: should be impossible (please report)"
|
|
325
294
|
}
|
|
326
295
|
|
|
327
296
|
/**
|
|
@@ -331,12 +300,15 @@ let charAtHelp = (position, string: String) => {
|
|
|
331
300
|
* @param string: The string to search
|
|
332
301
|
* @returns The character code at the provided position
|
|
333
302
|
*
|
|
303
|
+
* @throws MalformedUnicode: When the `string` is malformed
|
|
304
|
+
* @throws Failure(String): When the `position` is out of bounds
|
|
305
|
+
*
|
|
334
306
|
* @example String.charCodeAt(5, "Hello world") == 32
|
|
335
307
|
*
|
|
336
308
|
* @since v0.5.3
|
|
337
309
|
*/
|
|
338
310
|
@unsafe
|
|
339
|
-
|
|
311
|
+
provide let charCodeAt = (position, string: String) => {
|
|
340
312
|
tagSimpleNumber(charAtHelp(position, string))
|
|
341
313
|
}
|
|
342
314
|
|
|
@@ -347,22 +319,21 @@ export let charCodeAt = (position, string: String) => {
|
|
|
347
319
|
* @param string: The string to search
|
|
348
320
|
* @returns The character at the provided position
|
|
349
321
|
*
|
|
322
|
+
* @throws MalformedUnicode: When the `string` is malformed
|
|
323
|
+
* @throws Failure(String): When the `position` is out of bounds
|
|
324
|
+
*
|
|
350
325
|
* @example String.charAt(5, "Hello world") == ' '
|
|
351
326
|
*
|
|
352
327
|
* @since v0.4.0
|
|
353
328
|
*/
|
|
354
329
|
@unsafe
|
|
355
|
-
|
|
330
|
+
provide let charAt = (position, string: String) => {
|
|
356
331
|
tagChar(charAtHelp(position, string))
|
|
357
332
|
}
|
|
358
333
|
|
|
359
334
|
@unsafe
|
|
360
335
|
let explodeHelp = (s: String, chars) => {
|
|
361
|
-
|
|
362
|
-
let (+) = WasmI32.add
|
|
363
|
-
let (&) = WasmI32.and
|
|
364
|
-
let (<) = WasmI32.ltU
|
|
365
|
-
let (==) = WasmI32.eq
|
|
336
|
+
use WasmI32.{ (+), (&), (>>>), ltU as (<), (==) }
|
|
366
337
|
|
|
367
338
|
let size = WasmI32.fromGrain(byteLength(s)) >>> 1n
|
|
368
339
|
let len = WasmI32.fromGrain(length(s)) >>> 1n
|
|
@@ -409,12 +380,14 @@ let explodeHelp = (s: String, chars) => {
|
|
|
409
380
|
* @param string: The string to split
|
|
410
381
|
* @returns An array containing all characters in the string
|
|
411
382
|
*
|
|
383
|
+
* @throws MalformedUnicode: When the `string` is malformed
|
|
384
|
+
*
|
|
412
385
|
* @example String.explode("Hello") == [> 'H', 'e', 'l', 'l', 'o']
|
|
413
386
|
*
|
|
414
387
|
* @since v0.3.0
|
|
415
388
|
*/
|
|
416
389
|
@unsafe
|
|
417
|
-
|
|
390
|
+
provide let explode = string => {
|
|
418
391
|
WasmI32.toGrain(explodeHelp(string, true)): Array<Char>
|
|
419
392
|
}
|
|
420
393
|
|
|
@@ -429,17 +402,19 @@ export let explode = string => {
|
|
|
429
402
|
* @since v0.3.0
|
|
430
403
|
*/
|
|
431
404
|
@unsafe
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
405
|
+
provide let implode = (arr: Array<Char>) => {
|
|
406
|
+
use WasmI32.{
|
|
407
|
+
(+),
|
|
408
|
+
(-),
|
|
409
|
+
(*),
|
|
410
|
+
(&),
|
|
411
|
+
(|),
|
|
412
|
+
(<<),
|
|
413
|
+
(>>>),
|
|
414
|
+
ltU as (<),
|
|
415
|
+
gtU as (>),
|
|
416
|
+
leU as (<=),
|
|
417
|
+
}
|
|
443
418
|
|
|
444
419
|
let arrLength = WasmI32.load(WasmI32.fromGrain(arr), 4n)
|
|
445
420
|
|
|
@@ -483,11 +458,11 @@ export let implode = (arr: Array<Char>) => {
|
|
|
483
458
|
count = 3n
|
|
484
459
|
marker = 0xF0n
|
|
485
460
|
}
|
|
486
|
-
WasmI32.store8(str + offset, (usv >>> 6n * count) + marker, 0n)
|
|
461
|
+
WasmI32.store8(str + offset, (usv >>> (6n * count)) + marker, 0n)
|
|
487
462
|
offset += 1n
|
|
488
463
|
|
|
489
464
|
while (count > 0n) {
|
|
490
|
-
let temp = usv >>> 6n * (count - 1n)
|
|
465
|
+
let temp = usv >>> (6n * (count - 1n))
|
|
491
466
|
WasmI32.store8(str + offset, 0x80n | temp & 0x3Fn, 0n)
|
|
492
467
|
count -= 1n
|
|
493
468
|
offset += 1n
|
|
@@ -499,7 +474,7 @@ export let implode = (arr: Array<Char>) => {
|
|
|
499
474
|
}
|
|
500
475
|
|
|
501
476
|
// Helper to get the length in constant time without depending on Array
|
|
502
|
-
primitive arrayLength
|
|
477
|
+
primitive arrayLength = "@array.length"
|
|
503
478
|
|
|
504
479
|
/**
|
|
505
480
|
* Create a string that is the given string reversed.
|
|
@@ -511,7 +486,7 @@ primitive arrayLength: Array<a> -> Number = "@array.length"
|
|
|
511
486
|
*
|
|
512
487
|
* @since v0.4.5
|
|
513
488
|
*/
|
|
514
|
-
|
|
489
|
+
provide let reverse = string => {
|
|
515
490
|
let mut arr = explode(string)
|
|
516
491
|
let len = arrayLength(arr)
|
|
517
492
|
let halfLen = len / 2
|
|
@@ -532,18 +507,13 @@ export let reverse = string => {
|
|
|
532
507
|
* @param string: The string to split
|
|
533
508
|
* @returns An array of substrings from the initial string
|
|
534
509
|
*
|
|
510
|
+
* @throws MalformedUnicode: When the `string` is malformed
|
|
511
|
+
*
|
|
535
512
|
* @example String.split(" ", "Hello world") == [> "Hello", "world"]
|
|
536
513
|
*/
|
|
537
514
|
@unsafe
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
let (-) = WasmI32.sub
|
|
541
|
-
let (==) = WasmI32.eq
|
|
542
|
-
let (<) = WasmI32.ltU
|
|
543
|
-
let (>) = WasmI32.gtU
|
|
544
|
-
let (<<) = WasmI32.shl
|
|
545
|
-
let (>>) = WasmI32.shrS
|
|
546
|
-
let (&) = WasmI32.and
|
|
515
|
+
provide let split = (separator: String, string: String) => {
|
|
516
|
+
use WasmI32.{ (+), (-), (&), (<<), (>>), ltU as (<), gtU as (>), (==) }
|
|
547
517
|
|
|
548
518
|
let size = WasmI32.fromGrain(byteLength(string)) >> 1n
|
|
549
519
|
let psize = WasmI32.fromGrain(byteLength(separator)) >> 1n
|
|
@@ -620,27 +590,25 @@ export let split = (separator: String, string: String) => {
|
|
|
620
590
|
* Get a portion of a string.
|
|
621
591
|
*
|
|
622
592
|
* @param start: The start position of the substring
|
|
623
|
-
* @param
|
|
593
|
+
* @param end: The end position of the substring, exclusive
|
|
624
594
|
* @param string: The input string
|
|
625
595
|
* @returns The substring from the initial string
|
|
626
596
|
*
|
|
627
|
-
* @
|
|
597
|
+
* @throws InvalidArgument(String): When the `start` index is not an integer
|
|
598
|
+
* @throws InvalidArgument(String): When the `to` index is not an integer
|
|
599
|
+
* @throws IndexOutOfBounds: When `start` is out of bounds
|
|
600
|
+
* @throws IndexOutOfBounds: When `end` is out of bounds
|
|
601
|
+
* @throws InvalidArgument(String): When `start` is greater than `end`
|
|
602
|
+
*
|
|
603
|
+
* @example String.slice(0, end=5, "Hello world") == "Hello"
|
|
604
|
+
* @example String.slice(0, "Hello world") == "Hello world"
|
|
628
605
|
*
|
|
629
606
|
* @since v0.1.0
|
|
607
|
+
* @history v0.6.0: Default `end` to the String length
|
|
630
608
|
*/
|
|
631
609
|
@unsafe
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
let (-) = WasmI32.sub
|
|
635
|
-
let (==) = WasmI32.eq
|
|
636
|
-
let (!=) = WasmI32.ne
|
|
637
|
-
let (<) = WasmI32.ltS
|
|
638
|
-
let (>) = WasmI32.gtS
|
|
639
|
-
let (<<) = WasmI32.shl
|
|
640
|
-
let (>>) = WasmI32.shrS
|
|
641
|
-
let (&) = WasmI32.and
|
|
642
|
-
let startOrig = start
|
|
643
|
-
let toOrig = to
|
|
610
|
+
provide let slice = (start: Number, end=length(string), string: String) => {
|
|
611
|
+
use WasmI32.{ (+), (-), (&), (<<), (>>), (<), (>), (==), (!=) }
|
|
644
612
|
|
|
645
613
|
let len = WasmI32.fromGrain(length(string)) >> 1n
|
|
646
614
|
let size = WasmI32.fromGrain(byteLength(string)) >> 1n
|
|
@@ -653,7 +621,7 @@ export let slice = (start: Number, to: Number, string: String) => {
|
|
|
653
621
|
}
|
|
654
622
|
start = start >> 1n
|
|
655
623
|
|
|
656
|
-
let mut to = WasmI32.fromGrain(
|
|
624
|
+
let mut to = WasmI32.fromGrain(end)
|
|
657
625
|
if ((to & 1n) != 1n) {
|
|
658
626
|
throw InvalidArgument("Invalid end index")
|
|
659
627
|
}
|
|
@@ -667,7 +635,7 @@ export let slice = (start: Number, to: Number, string: String) => {
|
|
|
667
635
|
}
|
|
668
636
|
|
|
669
637
|
if (start > len || to > len) {
|
|
670
|
-
throw
|
|
638
|
+
throw IndexOutOfBounds
|
|
671
639
|
}
|
|
672
640
|
|
|
673
641
|
if (to < start) {
|
|
@@ -721,20 +689,21 @@ export let slice = (start: Number, to: Number, string: String) => {
|
|
|
721
689
|
* @since v0.1.0
|
|
722
690
|
*/
|
|
723
691
|
@unsafe
|
|
724
|
-
|
|
692
|
+
provide let contains = (search: String, string: String) => {
|
|
725
693
|
// "Not So Naive" string search algorithm
|
|
726
694
|
// searching phase in O(nm) time complexity
|
|
727
695
|
// slightly (by coefficient) sub-linear in the average case
|
|
728
696
|
// http://igm.univ-mlv.fr/~lecroq/string/node13.html#SECTION00130
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
697
|
+
use WasmI32.{
|
|
698
|
+
(+),
|
|
699
|
+
(-),
|
|
700
|
+
(>>),
|
|
701
|
+
ltU as (<),
|
|
702
|
+
gtU as (>),
|
|
703
|
+
leU as (<=),
|
|
704
|
+
(==),
|
|
705
|
+
(!=),
|
|
706
|
+
}
|
|
738
707
|
let pOrig = search
|
|
739
708
|
let sOrig = string
|
|
740
709
|
|
|
@@ -747,56 +716,58 @@ export let contains = (search: String, string: String) => {
|
|
|
747
716
|
string += 8n
|
|
748
717
|
search += 8n
|
|
749
718
|
|
|
750
|
-
let mut j = 0n
|
|
719
|
+
let mut j = 0n
|
|
720
|
+
and k = 0n
|
|
721
|
+
and ell = 0n
|
|
751
722
|
|
|
752
723
|
if (m > n) {
|
|
753
724
|
// Bail if pattern length is longer than input length
|
|
754
|
-
false
|
|
755
|
-
}
|
|
725
|
+
return false
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
if (m < 2n) {
|
|
756
729
|
// Handle very small patterns
|
|
757
730
|
if (m == 0n) {
|
|
758
|
-
true
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
j += 1n
|
|
768
|
-
}
|
|
731
|
+
return true
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
let pat = WasmI32.load8U(search, 0n)
|
|
735
|
+
while (j < n) {
|
|
736
|
+
if (pat == WasmI32.load8U(string + j, 0n)) {
|
|
737
|
+
return true
|
|
738
|
+
} else {
|
|
739
|
+
j += 1n
|
|
769
740
|
}
|
|
770
|
-
result
|
|
771
741
|
}
|
|
742
|
+
|
|
743
|
+
return false
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// NSM preprocessing
|
|
747
|
+
if (WasmI32.load8U(search, 0n) == WasmI32.load8U(search, 1n)) {
|
|
748
|
+
k = 2n
|
|
749
|
+
ell = 1n
|
|
772
750
|
} else {
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
ell = 1n
|
|
777
|
-
} else {
|
|
778
|
-
k = 1n
|
|
779
|
-
ell = 2n
|
|
780
|
-
}
|
|
751
|
+
k = 1n
|
|
752
|
+
ell = 2n
|
|
753
|
+
}
|
|
781
754
|
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
result = true
|
|
793
|
-
break
|
|
794
|
-
}
|
|
795
|
-
j += ell
|
|
755
|
+
// NSM searching
|
|
756
|
+
while (j <= n - m) {
|
|
757
|
+
if (WasmI32.load8U(search, 1n) != WasmI32.load8U(string + j, 1n)) {
|
|
758
|
+
j += k
|
|
759
|
+
} else {
|
|
760
|
+
if (
|
|
761
|
+
Memory.compare(search + 2n, string + j + 2n, m - 2n) == 0n &&
|
|
762
|
+
WasmI32.load8U(search, 0n) == WasmI32.load8U(string + j, 0n)
|
|
763
|
+
) {
|
|
764
|
+
return true
|
|
796
765
|
}
|
|
766
|
+
j += ell
|
|
797
767
|
}
|
|
798
|
-
result
|
|
799
768
|
}
|
|
769
|
+
|
|
770
|
+
return false
|
|
800
771
|
}
|
|
801
772
|
|
|
802
773
|
/**
|
|
@@ -811,10 +782,8 @@ export let contains = (search: String, string: String) => {
|
|
|
811
782
|
* @since v0.1.0
|
|
812
783
|
*/
|
|
813
784
|
@unsafe
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
let (>) = WasmI32.gtU
|
|
817
|
-
let (==) = WasmI32.eq
|
|
785
|
+
provide let startsWith = (search: String, string: String) => {
|
|
786
|
+
use WasmI32.{ (+), gtU as (>), (==) }
|
|
818
787
|
let pOrig = search
|
|
819
788
|
let sOrig = string
|
|
820
789
|
|
|
@@ -847,11 +816,8 @@ export let startsWith = (search: String, string: String) => {
|
|
|
847
816
|
* @since v0.1.0
|
|
848
817
|
*/
|
|
849
818
|
@unsafe
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
let (-) = WasmI32.sub
|
|
853
|
-
let (>) = WasmI32.gtU
|
|
854
|
-
let (==) = WasmI32.eq
|
|
819
|
+
provide let endsWith = (search: String, string: String) => {
|
|
820
|
+
use WasmI32.{ (+), (-), gtU as (>), (==) }
|
|
855
821
|
let pOrig = search
|
|
856
822
|
let sOrig = string
|
|
857
823
|
|
|
@@ -885,17 +851,12 @@ export let endsWith = (search: String, string: String) => {
|
|
|
885
851
|
* @since v0.5.4
|
|
886
852
|
*/
|
|
887
853
|
@unsafe
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
)
|
|
894
|
-
let (+) = WasmI32.add
|
|
895
|
-
let (-) = WasmI32.sub
|
|
896
|
-
let (>) = WasmI32.gtU
|
|
897
|
-
let (<) = WasmI32.ltU
|
|
898
|
-
let (==) = WasmI32.eq
|
|
854
|
+
provide let replaceFirst = (
|
|
855
|
+
searchPattern: String,
|
|
856
|
+
replacement: String,
|
|
857
|
+
string: String,
|
|
858
|
+
) => {
|
|
859
|
+
use WasmI32.{ (+), (-), gtU as (>), ltU as (<), (==) }
|
|
899
860
|
|
|
900
861
|
let mut patternPtr = WasmI32.fromGrain(searchPattern)
|
|
901
862
|
let mut stringPtr = WasmI32.fromGrain(string)
|
|
@@ -906,25 +867,19 @@ export let replaceFirst =
|
|
|
906
867
|
let replacementLen = WasmI32.load(replacementPtr, 4n)
|
|
907
868
|
// Bail if search str is longer than the string
|
|
908
869
|
if (stringLen < patternLen) {
|
|
909
|
-
string
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
if (Memory.compare(i, patternPtr, patternLen) == 0n) {
|
|
923
|
-
found = true
|
|
924
|
-
break
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
if (found) {
|
|
870
|
+
return string
|
|
871
|
+
}
|
|
872
|
+
patternPtr += 8n
|
|
873
|
+
stringPtr += 8n
|
|
874
|
+
replacementPtr += 8n
|
|
875
|
+
|
|
876
|
+
// Search for an instance of the string
|
|
877
|
+
let mut foundIndex = -1n
|
|
878
|
+
let stringEndPtr = stringPtr + stringLen - patternLen + 1n
|
|
879
|
+
for (let mut i = stringPtr; i < stringEndPtr; i += 1n) {
|
|
880
|
+
// check for match
|
|
881
|
+
foundIndex += 1n
|
|
882
|
+
if (Memory.compare(i, patternPtr, patternLen) == 0n) {
|
|
928
883
|
// Create the new string
|
|
929
884
|
let str = allocateString(stringLen - patternLen + replacementLen)
|
|
930
885
|
let strPtr = str + 8n
|
|
@@ -936,11 +891,11 @@ export let replaceFirst =
|
|
|
936
891
|
stringLen - foundIndex
|
|
937
892
|
)
|
|
938
893
|
// Copy over the str
|
|
939
|
-
WasmI32.toGrain(str): String
|
|
940
|
-
} else {
|
|
941
|
-
string
|
|
894
|
+
return WasmI32.toGrain(str): String
|
|
942
895
|
}
|
|
943
896
|
}
|
|
897
|
+
|
|
898
|
+
return string
|
|
944
899
|
}
|
|
945
900
|
|
|
946
901
|
/**
|
|
@@ -956,17 +911,12 @@ export let replaceFirst =
|
|
|
956
911
|
* @since v0.5.4
|
|
957
912
|
*/
|
|
958
913
|
@unsafe
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
)
|
|
965
|
-
let (+) = WasmI32.add
|
|
966
|
-
let (-) = WasmI32.sub
|
|
967
|
-
let (>) = WasmI32.gtU
|
|
968
|
-
let (<) = WasmI32.ltU
|
|
969
|
-
let (==) = WasmI32.eq
|
|
914
|
+
provide let replaceLast = (
|
|
915
|
+
searchPattern: String,
|
|
916
|
+
replacement: String,
|
|
917
|
+
string: String,
|
|
918
|
+
) => {
|
|
919
|
+
use WasmI32.{ (+), (-), gtU as (>), ltU as (<), (==) }
|
|
970
920
|
|
|
971
921
|
let mut patternPtr = WasmI32.fromGrain(searchPattern)
|
|
972
922
|
let mut stringPtr = WasmI32.fromGrain(string)
|
|
@@ -978,25 +928,20 @@ export let replaceLast =
|
|
|
978
928
|
|
|
979
929
|
// Bail if search str is longer than the string
|
|
980
930
|
if (stringLen < patternLen) {
|
|
981
|
-
string
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
found = true
|
|
996
|
-
break
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
if (found) {
|
|
931
|
+
return string
|
|
932
|
+
}
|
|
933
|
+
patternPtr += 8n
|
|
934
|
+
stringPtr += 8n
|
|
935
|
+
replacementPtr += 8n
|
|
936
|
+
|
|
937
|
+
let mut found = false
|
|
938
|
+
// Search for an instance of the string
|
|
939
|
+
let stringEndPtr = stringPtr + stringLen - patternLen
|
|
940
|
+
let mut foundIndex = stringLen - patternLen + 1n
|
|
941
|
+
for (let mut i = stringEndPtr; i > stringPtr - 1n; i -= 1n) {
|
|
942
|
+
// check for match
|
|
943
|
+
foundIndex -= 1n
|
|
944
|
+
if (Memory.compare(i, patternPtr, patternLen) == 0n) {
|
|
1000
945
|
// Create the new string
|
|
1001
946
|
let str = allocateString(stringLen - patternLen + replacementLen)
|
|
1002
947
|
let strPtr = str + 8n
|
|
@@ -1008,11 +953,11 @@ export let replaceLast =
|
|
|
1008
953
|
stringLen - foundIndex
|
|
1009
954
|
)
|
|
1010
955
|
// Copy over the str
|
|
1011
|
-
WasmI32.toGrain(str): String
|
|
1012
|
-
} else {
|
|
1013
|
-
string
|
|
956
|
+
return WasmI32.toGrain(str): String
|
|
1014
957
|
}
|
|
1015
958
|
}
|
|
959
|
+
|
|
960
|
+
return string
|
|
1016
961
|
}
|
|
1017
962
|
|
|
1018
963
|
/**
|
|
@@ -1028,19 +973,12 @@ export let replaceLast =
|
|
|
1028
973
|
* @since v0.5.4
|
|
1029
974
|
*/
|
|
1030
975
|
@unsafe
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
)
|
|
1037
|
-
let (*) = WasmI32.mul
|
|
1038
|
-
let (+) = WasmI32.add
|
|
1039
|
-
let (-) = WasmI32.sub
|
|
1040
|
-
let (>) = WasmI32.gtU
|
|
1041
|
-
let (<) = WasmI32.ltU
|
|
1042
|
-
let (==) = WasmI32.eq
|
|
1043
|
-
let (>>) = WasmI32.shrS
|
|
976
|
+
provide let replaceAll = (
|
|
977
|
+
searchPattern: String,
|
|
978
|
+
replacement: String,
|
|
979
|
+
string: String,
|
|
980
|
+
) => {
|
|
981
|
+
use WasmI32.{ (+), (-), (*), (>>), gtU as (>), ltU as (<), (==) }
|
|
1044
982
|
|
|
1045
983
|
let mut patternPtr = WasmI32.fromGrain(searchPattern)
|
|
1046
984
|
let mut stringPtr = WasmI32.fromGrain(string)
|
|
@@ -1071,6 +1009,8 @@ export let replaceAll =
|
|
|
1071
1009
|
found = true
|
|
1072
1010
|
foundCount += 1n
|
|
1073
1011
|
foundIndexes = [tagSimpleNumber(foundIndex), ...foundIndexes]
|
|
1012
|
+
foundIndex -= patternLen - 1n
|
|
1013
|
+
i -= patternLen - 1n
|
|
1074
1014
|
}
|
|
1075
1015
|
}
|
|
1076
1016
|
if (found) {
|
|
@@ -1114,13 +1054,14 @@ let _OFFSET_NAME = "offset"
|
|
|
1114
1054
|
|
|
1115
1055
|
@unsafe
|
|
1116
1056
|
let grainToWasmNumber = (num, name) => {
|
|
1057
|
+
use WasmI32.{ (&), (>>), (<) }
|
|
1117
1058
|
let num = WasmI32.fromGrain(num)
|
|
1118
|
-
if (WasmI32.eqz(
|
|
1059
|
+
if (WasmI32.eqz(num & 1n)) {
|
|
1119
1060
|
let str = " argument must be an integer"
|
|
1120
1061
|
throw Exception.InvalidArgument(name ++ str)
|
|
1121
1062
|
}
|
|
1122
|
-
let num =
|
|
1123
|
-
if (
|
|
1063
|
+
let num = num >> 1n
|
|
1064
|
+
if (num < 0n) {
|
|
1124
1065
|
let str = " argument must be non-negative"
|
|
1125
1066
|
throw Exception.InvalidArgument(name ++ str)
|
|
1126
1067
|
}
|
|
@@ -1129,12 +1070,7 @@ let grainToWasmNumber = (num, name) => {
|
|
|
1129
1070
|
|
|
1130
1071
|
@unsafe
|
|
1131
1072
|
let utf16Length = (s: String) => {
|
|
1132
|
-
|
|
1133
|
-
let (<<) = WasmI32.shl
|
|
1134
|
-
let (+) = WasmI32.add
|
|
1135
|
-
let (&) = WasmI32.and
|
|
1136
|
-
let (<) = WasmI32.ltU
|
|
1137
|
-
let (==) = WasmI32.eq
|
|
1073
|
+
use WasmI32.{ (+), (&), (>>>), (<<), ltU as (<), (==) }
|
|
1138
1074
|
|
|
1139
1075
|
let size = WasmI32.fromGrain(byteLength(s)) >>> 1n
|
|
1140
1076
|
let len = WasmI32.fromGrain(length(s)) >>> 1n
|
|
@@ -1184,22 +1120,14 @@ let mut _BYTES_SIZE_OFFSET = 4n
|
|
|
1184
1120
|
let mut _BYTES_OFFSET = 8n
|
|
1185
1121
|
|
|
1186
1122
|
@unsafe
|
|
1187
|
-
let encodeAtHelp =
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
)
|
|
1195
|
-
let (>>>) = WasmI32.shrU
|
|
1196
|
-
let (-) = WasmI32.sub
|
|
1197
|
-
let (&) = WasmI32.and
|
|
1198
|
-
let (<) = WasmI32.ltU
|
|
1199
|
-
let (>) = WasmI32.gtS
|
|
1200
|
-
let (<=) = WasmI32.leU
|
|
1201
|
-
let (==) = WasmI32.eq
|
|
1202
|
-
let (+) = WasmI32.add
|
|
1123
|
+
let encodeAtHelp = (
|
|
1124
|
+
string: String,
|
|
1125
|
+
encoding: Encoding,
|
|
1126
|
+
includeBom: Bool,
|
|
1127
|
+
dest: Bytes,
|
|
1128
|
+
destPos: Number,
|
|
1129
|
+
) => {
|
|
1130
|
+
use WasmI32.{ (+), (-), (&), (>>>), ltU as (<), (>), leU as (<=), (==) }
|
|
1203
1131
|
let byteSize = WasmI32.fromGrain(byteLength(string)) >>> 1n
|
|
1204
1132
|
let len = WasmI32.fromGrain(length(string)) >>> 1n
|
|
1205
1133
|
|
|
@@ -1217,7 +1145,7 @@ let encodeAtHelp =
|
|
|
1217
1145
|
match (encoding) {
|
|
1218
1146
|
UTF8 => {
|
|
1219
1147
|
if (bytesIdx + 3n > destSize) {
|
|
1220
|
-
throw
|
|
1148
|
+
throw IndexOutOfBounds
|
|
1221
1149
|
}
|
|
1222
1150
|
WasmI32.store8(bytes + bytesIdx, 0xEFn, _BYTES_OFFSET)
|
|
1223
1151
|
WasmI32.store8(bytes + bytesIdx + 1n, 0xBBn, _BYTES_OFFSET)
|
|
@@ -1226,7 +1154,7 @@ let encodeAtHelp =
|
|
|
1226
1154
|
},
|
|
1227
1155
|
UTF16_BE => {
|
|
1228
1156
|
if (bytesIdx + 2n > destSize) {
|
|
1229
|
-
throw
|
|
1157
|
+
throw IndexOutOfBounds
|
|
1230
1158
|
}
|
|
1231
1159
|
WasmI32.store8(bytes + bytesIdx, 0xFEn, _BYTES_OFFSET)
|
|
1232
1160
|
WasmI32.store8(bytes + bytesIdx + 1n, 0xFFn, _BYTES_OFFSET)
|
|
@@ -1234,7 +1162,7 @@ let encodeAtHelp =
|
|
|
1234
1162
|
},
|
|
1235
1163
|
UTF16_LE => {
|
|
1236
1164
|
if (bytesIdx + 2n > destSize) {
|
|
1237
|
-
throw
|
|
1165
|
+
throw IndexOutOfBounds
|
|
1238
1166
|
}
|
|
1239
1167
|
WasmI32.store8(bytes + bytesIdx, 0xFFn, _BYTES_OFFSET)
|
|
1240
1168
|
WasmI32.store8(bytes + bytesIdx + 1n, 0xFEn, _BYTES_OFFSET)
|
|
@@ -1242,7 +1170,7 @@ let encodeAtHelp =
|
|
|
1242
1170
|
},
|
|
1243
1171
|
UTF32_BE => {
|
|
1244
1172
|
if (bytesIdx + 4n > destSize) {
|
|
1245
|
-
throw
|
|
1173
|
+
throw IndexOutOfBounds
|
|
1246
1174
|
}
|
|
1247
1175
|
WasmI32.store8(bytes + bytesIdx, 0n, _BYTES_OFFSET)
|
|
1248
1176
|
WasmI32.store8(bytes + bytesIdx + 1n, 0n, _BYTES_OFFSET)
|
|
@@ -1252,7 +1180,7 @@ let encodeAtHelp =
|
|
|
1252
1180
|
},
|
|
1253
1181
|
UTF32_LE => {
|
|
1254
1182
|
if (bytesIdx + 4n > destSize) {
|
|
1255
|
-
throw
|
|
1183
|
+
throw IndexOutOfBounds
|
|
1256
1184
|
}
|
|
1257
1185
|
WasmI32.store8(bytes + bytesIdx, 0xFFn, _BYTES_OFFSET)
|
|
1258
1186
|
WasmI32.store8(bytes + bytesIdx + 1n, 0xFEn, _BYTES_OFFSET)
|
|
@@ -1269,7 +1197,7 @@ let encodeAtHelp =
|
|
|
1269
1197
|
// the target encoding is UTF8 as well, then copy the entire memory range
|
|
1270
1198
|
// in bulk. No need to iterate individual characters.
|
|
1271
1199
|
if (bytesIdx + byteSize > destSize) {
|
|
1272
|
-
throw
|
|
1200
|
+
throw IndexOutOfBounds
|
|
1273
1201
|
}
|
|
1274
1202
|
Memory.copy(bytes + bytesIdx + _BYTES_OFFSET, ptr, byteSize)
|
|
1275
1203
|
},
|
|
@@ -1291,7 +1219,7 @@ let encodeAtHelp =
|
|
|
1291
1219
|
// With the optimization above for bulk memory copy, this match
|
|
1292
1220
|
// should never occur for the UTF8 case.
|
|
1293
1221
|
if (bytesIdx + n > destSize) {
|
|
1294
|
-
throw
|
|
1222
|
+
throw IndexOutOfBounds
|
|
1295
1223
|
}
|
|
1296
1224
|
Memory.copy(bytes + bytesIdx + _BYTES_OFFSET, ptr, n)
|
|
1297
1225
|
bytesIdx += n
|
|
@@ -1301,7 +1229,7 @@ let encodeAtHelp =
|
|
|
1301
1229
|
if (codePoint <= 0xFFFFn) {
|
|
1302
1230
|
// <hi><lo>
|
|
1303
1231
|
if (bytesIdx + 2n > destSize) {
|
|
1304
|
-
throw
|
|
1232
|
+
throw IndexOutOfBounds
|
|
1305
1233
|
}
|
|
1306
1234
|
WasmI32.store8(
|
|
1307
1235
|
bytes + bytesIdx,
|
|
@@ -1317,13 +1245,11 @@ let encodeAtHelp =
|
|
|
1317
1245
|
} else {
|
|
1318
1246
|
// https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF
|
|
1319
1247
|
if (bytesIdx + 4n > destSize) {
|
|
1320
|
-
throw
|
|
1248
|
+
throw IndexOutOfBounds
|
|
1321
1249
|
}
|
|
1322
1250
|
let uPrime = codePoint - 0x10000n
|
|
1323
|
-
let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) +
|
|
1324
|
-
|
|
1325
|
-
let w2 = (uPrime & 0b00000000001111111111n) +
|
|
1326
|
-
0xDC00n // Low surrogate
|
|
1251
|
+
let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) + 0xD800n // High surrogate
|
|
1252
|
+
let w2 = (uPrime & 0b00000000001111111111n) + 0xDC00n // Low surrogate
|
|
1327
1253
|
WasmI32.store8(
|
|
1328
1254
|
bytes + bytesIdx,
|
|
1329
1255
|
(w1 & 0xff00n) >>> 8n,
|
|
@@ -1343,7 +1269,7 @@ let encodeAtHelp =
|
|
|
1343
1269
|
let codePoint = getCodePoint(ptr)
|
|
1344
1270
|
if (codePoint <= 0xFFFFn) {
|
|
1345
1271
|
if (bytesIdx + 2n > destSize) {
|
|
1346
|
-
throw
|
|
1272
|
+
throw IndexOutOfBounds
|
|
1347
1273
|
}
|
|
1348
1274
|
// <lo><hi>
|
|
1349
1275
|
WasmI32.store8(bytes + bytesIdx, codePoint & 0xffn, _BYTES_OFFSET)
|
|
@@ -1356,13 +1282,11 @@ let encodeAtHelp =
|
|
|
1356
1282
|
} else {
|
|
1357
1283
|
// https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF
|
|
1358
1284
|
if (bytesIdx + 4n > destSize) {
|
|
1359
|
-
throw
|
|
1285
|
+
throw IndexOutOfBounds
|
|
1360
1286
|
}
|
|
1361
1287
|
let uPrime = codePoint - 0x10000n
|
|
1362
|
-
let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) +
|
|
1363
|
-
|
|
1364
|
-
let w2 = (uPrime & 0b00000000001111111111n) +
|
|
1365
|
-
0xDC00n // Low surrogate
|
|
1288
|
+
let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) + 0xD800n // High surrogate
|
|
1289
|
+
let w2 = (uPrime & 0b00000000001111111111n) + 0xDC00n // Low surrogate
|
|
1366
1290
|
WasmI32.store8(bytes + bytesIdx, w1 & 0xffn, _BYTES_OFFSET)
|
|
1367
1291
|
WasmI32.store8(
|
|
1368
1292
|
bytes + bytesIdx + 1n,
|
|
@@ -1380,7 +1304,7 @@ let encodeAtHelp =
|
|
|
1380
1304
|
},
|
|
1381
1305
|
UTF32_BE => {
|
|
1382
1306
|
if (bytesIdx + 4n > destSize) {
|
|
1383
|
-
throw
|
|
1307
|
+
throw IndexOutOfBounds
|
|
1384
1308
|
}
|
|
1385
1309
|
let codePoint = getCodePoint(ptr)
|
|
1386
1310
|
WasmI32.store8(
|
|
@@ -1407,7 +1331,7 @@ let encodeAtHelp =
|
|
|
1407
1331
|
},
|
|
1408
1332
|
UTF32_LE => {
|
|
1409
1333
|
if (bytesIdx + 4n > destSize) {
|
|
1410
|
-
throw
|
|
1334
|
+
throw IndexOutOfBounds
|
|
1411
1335
|
}
|
|
1412
1336
|
let codePoint = getCodePoint(ptr)
|
|
1413
1337
|
WasmI32.store8(bytes + bytesIdx, codePoint & 0xffn, _BYTES_OFFSET)
|
|
@@ -1438,92 +1362,63 @@ let encodeAtHelp =
|
|
|
1438
1362
|
}
|
|
1439
1363
|
|
|
1440
1364
|
/**
|
|
1441
|
-
* Encodes the given string into a byte sequence at the supplied position
|
|
1365
|
+
* Encodes the given string into a byte sequence at the supplied position using the encoding scheme provided.
|
|
1442
1366
|
*
|
|
1443
1367
|
* @param string: The input string
|
|
1444
1368
|
* @param encoding: The encoding to use
|
|
1445
1369
|
* @param dest: The byte sequence that will be copied
|
|
1446
1370
|
* @param destPos: The location in the byte sequence to write the output
|
|
1371
|
+
* @param includeBom: Whether or not to include a byte order marker (false by default)
|
|
1447
1372
|
* @returns A copy of the input bytes with the encoded string replaced at the given position
|
|
1448
1373
|
*
|
|
1449
|
-
* @
|
|
1450
|
-
|
|
1451
|
-
export let encodeAt = (string, encoding, dest, destPos) => {
|
|
1452
|
-
encodeAtHelp(string, encoding, false, dest, destPos)
|
|
1453
|
-
}
|
|
1454
|
-
|
|
1455
|
-
/**
|
|
1456
|
-
* Encodes the given string into a byte sequence at the supplied position, including any byte-order marker, using the encoding scheme provided.
|
|
1457
|
-
*
|
|
1458
|
-
* @param string: The input string
|
|
1459
|
-
* @param encoding: The encoding to use
|
|
1460
|
-
* @param dest: The byte sequence that will be copied
|
|
1461
|
-
* @param destPos: The location in the byte sequence to write the output
|
|
1462
|
-
* @returns A copy of the input bytes with the encoded string replaced at the given position
|
|
1374
|
+
* @throws InvalidArgument(String): When `destPos` is not an integer
|
|
1375
|
+
* @throws InvalidArgument(String): When `destPos` is negative
|
|
1463
1376
|
*
|
|
1464
1377
|
* @since v0.4.0
|
|
1378
|
+
* @history v0.6.0: Added `includeBom` default argument
|
|
1465
1379
|
*/
|
|
1466
|
-
|
|
1467
|
-
encodeAtHelp(string, encoding,
|
|
1380
|
+
provide let encodeAt = (string, encoding, dest, destPos, includeBom=false) => {
|
|
1381
|
+
encodeAtHelp(string, encoding, includeBom, dest, destPos)
|
|
1468
1382
|
}
|
|
1469
1383
|
|
|
1470
1384
|
@unsafe
|
|
1471
1385
|
let encodeHelp = (string: String, encoding: Encoding, includeBom: Bool) => {
|
|
1472
|
-
let size = encodedLength(string, encoding) +
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
let (>>>) = WasmI32.shrU
|
|
1386
|
+
let size = encodedLength(string, encoding) + (if (includeBom) {
|
|
1387
|
+
match (encoding) {
|
|
1388
|
+
UTF8 => 3,
|
|
1389
|
+
UTF16_LE => 2,
|
|
1390
|
+
UTF16_BE => 2,
|
|
1391
|
+
UTF32_LE => 4,
|
|
1392
|
+
UTF32_BE => 4,
|
|
1393
|
+
}
|
|
1394
|
+
} else {
|
|
1395
|
+
0
|
|
1396
|
+
})
|
|
1397
|
+
use WasmI32.{ (>>>) }
|
|
1485
1398
|
let bytes = WasmI32.toGrain(allocateBytes(WasmI32.fromGrain(size) >>> 1n))
|
|
1486
1399
|
encodeAtHelp(string, encoding, includeBom, bytes, 0)
|
|
1487
1400
|
}
|
|
1488
1401
|
|
|
1489
1402
|
/**
|
|
1490
|
-
* Encodes the given string using the given encoding scheme
|
|
1403
|
+
* Encodes the given string using the given encoding scheme.
|
|
1491
1404
|
*
|
|
1492
1405
|
* @param string: The input string
|
|
1493
1406
|
* @param encoding: The encoding to use
|
|
1407
|
+
* @param includeBom: Whether or not to include a byte order marker (false by default)
|
|
1494
1408
|
* @returns The byte representation of the string in the given encoding
|
|
1495
1409
|
*
|
|
1496
1410
|
* @since v0.4.0
|
|
1411
|
+
* @history v0.6.0: Added `includeBom` default argument
|
|
1497
1412
|
*/
|
|
1498
|
-
|
|
1499
|
-
encodeHelp(string, encoding,
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
/**
|
|
1503
|
-
* Encodes the given string using the given encoding scheme, including any byte-order marker.
|
|
1504
|
-
*
|
|
1505
|
-
* @param string: The input string
|
|
1506
|
-
* @param encoding: The encoding to use
|
|
1507
|
-
* @returns The byte representation of the string in the given encoding
|
|
1508
|
-
*
|
|
1509
|
-
* @since v0.4.0
|
|
1510
|
-
*/
|
|
1511
|
-
export let encodeWithBom = (string: String, encoding: Encoding) => {
|
|
1512
|
-
encodeHelp(string, encoding, true)
|
|
1413
|
+
provide let encode = (string: String, encoding: Encoding, includeBom=false) => {
|
|
1414
|
+
encodeHelp(string, encoding, includeBom)
|
|
1513
1415
|
}
|
|
1514
1416
|
|
|
1515
1417
|
// Byte->String decoding and helper functions:
|
|
1516
1418
|
|
|
1517
1419
|
@unsafe
|
|
1518
1420
|
let writeUtf8CodePoint = (ptr, codePoint) => {
|
|
1519
|
-
|
|
1520
|
-
let (-) = WasmI32.sub
|
|
1521
|
-
let (&) = WasmI32.and
|
|
1522
|
-
let (|) = WasmI32.or
|
|
1523
|
-
let (+) = WasmI32.add
|
|
1524
|
-
let (<) = WasmI32.ltU
|
|
1525
|
-
let (<=) = WasmI32.leU
|
|
1526
|
-
let (==) = WasmI32.eq
|
|
1421
|
+
use WasmI32.{ (+), (-), (&), (|), (>>>), ltU as (<), leU as (<=), (==) }
|
|
1527
1422
|
if (codePoint <= 0x007Fn) {
|
|
1528
1423
|
// Code points in the ASCII range are written as just one byte with the
|
|
1529
1424
|
// leading bit equal to zero (0xxxxxxx). Just store the value as one byte
|
|
@@ -1573,9 +1468,7 @@ let writeUtf8CodePoint = (ptr, codePoint) => {
|
|
|
1573
1468
|
|
|
1574
1469
|
@unsafe
|
|
1575
1470
|
let bytesHaveBom = (bytes: Bytes, encoding: Encoding, start: WasmI32) => {
|
|
1576
|
-
|
|
1577
|
-
let (==) = WasmI32.eq
|
|
1578
|
-
let (>=) = WasmI32.geU
|
|
1471
|
+
use WasmI32.{ (+), geU as (>=), (==) }
|
|
1579
1472
|
let ptr = WasmI32.fromGrain(bytes)
|
|
1580
1473
|
let bytesSize = WasmI32.load(ptr, 4n)
|
|
1581
1474
|
let ptr = ptr + start
|
|
@@ -1614,25 +1507,26 @@ let bytesHaveBom = (bytes: Bytes, encoding: Encoding, start: WasmI32) => {
|
|
|
1614
1507
|
}
|
|
1615
1508
|
|
|
1616
1509
|
@unsafe
|
|
1617
|
-
let decodedLength =
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1510
|
+
let decodedLength = (
|
|
1511
|
+
bytes: Bytes,
|
|
1512
|
+
encoding: Encoding,
|
|
1513
|
+
start: WasmI32,
|
|
1514
|
+
size: WasmI32,
|
|
1515
|
+
) => {
|
|
1516
|
+
use WasmI32.{
|
|
1517
|
+
(+),
|
|
1518
|
+
(-),
|
|
1519
|
+
(&),
|
|
1520
|
+
(|),
|
|
1521
|
+
(>>>),
|
|
1522
|
+
(<<),
|
|
1523
|
+
ltU as (<),
|
|
1524
|
+
gtU as (>),
|
|
1525
|
+
geU as (>=),
|
|
1526
|
+
leU as (<=),
|
|
1527
|
+
(==),
|
|
1528
|
+
(!=),
|
|
1529
|
+
}
|
|
1636
1530
|
let ptr = WasmI32.fromGrain(bytes)
|
|
1637
1531
|
let bytesSize = {
|
|
1638
1532
|
let tmp = WasmI32.load(ptr, 4n) - start
|
|
@@ -1783,24 +1677,25 @@ let decodedLength =
|
|
|
1783
1677
|
}
|
|
1784
1678
|
|
|
1785
1679
|
@unsafe
|
|
1786
|
-
let decodeRangeHelp =
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1680
|
+
let decodeRangeHelp = (
|
|
1681
|
+
bytes: Bytes,
|
|
1682
|
+
encoding: Encoding,
|
|
1683
|
+
skipBom: Bool,
|
|
1684
|
+
start: Number,
|
|
1685
|
+
size: Number,
|
|
1686
|
+
) => {
|
|
1687
|
+
use WasmI32.{
|
|
1688
|
+
(+),
|
|
1689
|
+
(-),
|
|
1690
|
+
(&),
|
|
1691
|
+
(|),
|
|
1692
|
+
(>>>),
|
|
1693
|
+
(<<),
|
|
1694
|
+
ltU as (<),
|
|
1695
|
+
geU as (>=),
|
|
1696
|
+
leU as (<=),
|
|
1697
|
+
(==),
|
|
1698
|
+
}
|
|
1804
1699
|
let start = grainToWasmNumber(start, _START_NAME)
|
|
1805
1700
|
let size = grainToWasmNumber(size, _SIZE_NAME)
|
|
1806
1701
|
let hasBom = bytesHaveBom(bytes, encoding, start)
|
|
@@ -1844,8 +1739,10 @@ let decodeRangeHelp =
|
|
|
1844
1739
|
let codeWord = if (w1 >= 0xD800n && w1 <= 0xDBFFn) {
|
|
1845
1740
|
// high surrogate. next character is low srurrogate
|
|
1846
1741
|
let w1 = (w1 & 0x03FFn) << 10n
|
|
1847
|
-
let w2 = (
|
|
1848
|
-
WasmI32.load8U(bytesPtr,
|
|
1742
|
+
let w2 = (
|
|
1743
|
+
WasmI32.load8U(bytesPtr, 2n) << 8n |
|
|
1744
|
+
WasmI32.load8U(bytesPtr, 3n)
|
|
1745
|
+
) &
|
|
1849
1746
|
0x03FFn
|
|
1850
1747
|
let codeWord = w1 + w2 + 0x10000n
|
|
1851
1748
|
// no problems, so go past both code words
|
|
@@ -1867,8 +1764,10 @@ let decodeRangeHelp =
|
|
|
1867
1764
|
let codeWord = if (w1 >= 0xD800n && w1 <= 0xDBFFn) {
|
|
1868
1765
|
// high surrogate. next character is low srurrogate
|
|
1869
1766
|
let w1 = (w1 & 0x03FFn) << 10n
|
|
1870
|
-
let w2 = (
|
|
1871
|
-
WasmI32.load8U(bytesPtr,
|
|
1767
|
+
let w2 = (
|
|
1768
|
+
WasmI32.load8U(bytesPtr, 3n) << 8n |
|
|
1769
|
+
WasmI32.load8U(bytesPtr, 2n)
|
|
1770
|
+
) &
|
|
1872
1771
|
0x03FFn
|
|
1873
1772
|
//let uPrime = codePoint - 0x10000n
|
|
1874
1773
|
//let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) + 0xD800n // High surrogate
|
|
@@ -1912,45 +1811,31 @@ let decodeRangeHelp =
|
|
|
1912
1811
|
}
|
|
1913
1812
|
|
|
1914
1813
|
/**
|
|
1915
|
-
* Decodes the given byte sequence of the specified range into a string
|
|
1814
|
+
* Decodes the given byte sequence of the specified range into a string using the encoding scheme provided.
|
|
1916
1815
|
*
|
|
1917
1816
|
* @param bytes: The input bytes
|
|
1918
1817
|
* @param encoding: The encoding to use
|
|
1919
1818
|
* @param start: The byte offset to begin decoding from
|
|
1920
1819
|
* @param size: The maximum number of bytes to decode
|
|
1820
|
+
* @param keepBom: Whether or not to include a byte order marker (false by default)
|
|
1921
1821
|
* @returns The decoded string
|
|
1922
1822
|
*
|
|
1923
|
-
* @
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
bytes: Bytes,
|
|
1928
|
-
encoding: Encoding,
|
|
1929
|
-
start: Number,
|
|
1930
|
-
size: Number,
|
|
1931
|
-
) => {
|
|
1932
|
-
decodeRangeHelp(bytes, encoding, true, start, size)
|
|
1933
|
-
}
|
|
1934
|
-
|
|
1935
|
-
/**
|
|
1936
|
-
* Decodes the given byte sequence of the specified range into a string, including any byte-order marker, using encoding scheme provided.
|
|
1937
|
-
*
|
|
1938
|
-
* @param bytes: The input bytes
|
|
1939
|
-
* @param encoding: The encoding to use
|
|
1940
|
-
* @param start: The byte offset to begin decoding from
|
|
1941
|
-
* @param size: The maximum number of bytes to decode
|
|
1942
|
-
* @returns The decoded string
|
|
1823
|
+
* @throws InvalidArgument(String): When `start` is not an integer
|
|
1824
|
+
* @throws InvalidArgument(String): When `start` is negative
|
|
1825
|
+
* @throws InvalidArgument(String): When `size` is not an integer
|
|
1826
|
+
* @throws InvalidArgument(String): When `size` is negative
|
|
1943
1827
|
*
|
|
1944
1828
|
* @since v0.4.0
|
|
1829
|
+
* @history v0.6.0: Added `keepBom` default argument
|
|
1945
1830
|
*/
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
decodeRangeHelp(bytes, encoding,
|
|
1831
|
+
provide let decodeRange = (
|
|
1832
|
+
bytes: Bytes,
|
|
1833
|
+
encoding: Encoding,
|
|
1834
|
+
start: Number,
|
|
1835
|
+
size: Number,
|
|
1836
|
+
keepBom=false,
|
|
1837
|
+
) => {
|
|
1838
|
+
decodeRangeHelp(bytes, encoding, !keepBom, start, size)
|
|
1954
1839
|
}
|
|
1955
1840
|
|
|
1956
1841
|
@unsafe
|
|
@@ -1961,29 +1846,18 @@ let decodeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool) => {
|
|
|
1961
1846
|
}
|
|
1962
1847
|
|
|
1963
1848
|
/**
|
|
1964
|
-
* Decodes the given byte sequence into a string using the given encoding scheme
|
|
1849
|
+
* Decodes the given byte sequence into a string using the given encoding scheme.
|
|
1965
1850
|
*
|
|
1966
1851
|
* @param bytes: The input bytes
|
|
1967
1852
|
* @param encoding: The encoding to use
|
|
1853
|
+
* @param keepBom: Whether or not to include a byte order marker (false by default)
|
|
1968
1854
|
* @returns The decoded string
|
|
1969
1855
|
*
|
|
1970
1856
|
* @since v0.4.0
|
|
1857
|
+
* @history v0.6.0: Added `keepBom` default argument
|
|
1971
1858
|
*/
|
|
1972
|
-
|
|
1973
|
-
decodeHelp(bytes, encoding,
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
|
-
/**
|
|
1977
|
-
* Decodes the given byte sequence into a string using the given encoding scheme, including any byte-order marker.
|
|
1978
|
-
*
|
|
1979
|
-
* @param bytes: The input bytes
|
|
1980
|
-
* @param encoding: The encoding to use
|
|
1981
|
-
* @returns The decoded string
|
|
1982
|
-
*
|
|
1983
|
-
* @since v0.4.0
|
|
1984
|
-
*/
|
|
1985
|
-
export let decodeKeepBom = (bytes: Bytes, encoding: Encoding) => {
|
|
1986
|
-
decodeHelp(bytes, encoding, false)
|
|
1859
|
+
provide let decode = (bytes: Bytes, encoding: Encoding, keepBom=false) => {
|
|
1860
|
+
decodeHelp(bytes, encoding, !keepBom)
|
|
1987
1861
|
}
|
|
1988
1862
|
|
|
1989
1863
|
/**
|
|
@@ -1997,14 +1871,8 @@ export let decodeKeepBom = (bytes: Bytes, encoding: Encoding) => {
|
|
|
1997
1871
|
* @since v0.4.0
|
|
1998
1872
|
*/
|
|
1999
1873
|
@unsafe
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
let (-) = WasmI32.sub
|
|
2003
|
-
let (&) = WasmI32.and
|
|
2004
|
-
let (<) = WasmI32.ltU
|
|
2005
|
-
let (<=) = WasmI32.leU
|
|
2006
|
-
let (==) = WasmI32.eq
|
|
2007
|
-
let (+) = WasmI32.add
|
|
1874
|
+
provide let forEachCodePoint = (fn: Number => Void, str: String) => {
|
|
1875
|
+
use WasmI32.{ (+), (-), (&), (>>>), ltU as (<), leU as (<=), (==) }
|
|
2008
1876
|
|
|
2009
1877
|
let strPtr = WasmI32.fromGrain(str)
|
|
2010
1878
|
|
|
@@ -2055,14 +1923,8 @@ export let forEachCodePoint = (fn: Number -> Void, str: String) => {
|
|
|
2055
1923
|
* @since v0.4.0
|
|
2056
1924
|
*/
|
|
2057
1925
|
@unsafe
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
let (-) = WasmI32.sub
|
|
2061
|
-
let (&) = WasmI32.and
|
|
2062
|
-
let (<) = WasmI32.ltU
|
|
2063
|
-
let (<=) = WasmI32.leU
|
|
2064
|
-
let (==) = WasmI32.eq
|
|
2065
|
-
let (+) = WasmI32.add
|
|
1926
|
+
provide let forEachCodePointi = (fn: (Number, Number) => Void, str: String) => {
|
|
1927
|
+
use WasmI32.{ (+), (-), (&), (>>>), ltU as (<), leU as (<=), (==) }
|
|
2066
1928
|
|
|
2067
1929
|
let strPtr = WasmI32.fromGrain(str)
|
|
2068
1930
|
|
|
@@ -2101,19 +1963,10 @@ export let forEachCodePointi = (fn: (Number, Number) -> Void, str: String) => {
|
|
|
2101
1963
|
}
|
|
2102
1964
|
|
|
2103
1965
|
@unsafe
|
|
2104
|
-
let trimString = (
|
|
2105
|
-
|
|
2106
|
-
let
|
|
2107
|
-
|
|
2108
|
-
let (-) = WasmI32.sub
|
|
2109
|
-
let (<) = WasmI32.ltU
|
|
2110
|
-
let (==) = WasmI32.eq
|
|
2111
|
-
let (!=) = WasmI32.ne
|
|
2112
|
-
|
|
2113
|
-
let mut stringPtr = WasmI32.fromGrain(str)
|
|
2114
|
-
let byteLength = WasmI32.load(stringPtr, 4n)
|
|
2115
|
-
stringPtr += 8n
|
|
2116
|
-
let mut i = 0n, offset = 1n
|
|
1966
|
+
let trimString = (stringPtr: WasmI32, byteLength: WasmI32, fromEnd: Bool) => {
|
|
1967
|
+
use WasmI32.{ (+), (-), (*), (>>>), ltU as (<), (==), (!=) }
|
|
1968
|
+
let mut i = 0n
|
|
1969
|
+
and offset = 1n
|
|
2117
1970
|
if (fromEnd) {
|
|
2118
1971
|
i = byteLength - 1n
|
|
2119
1972
|
offset = -1n
|
|
@@ -2157,14 +2010,7 @@ let trimString = (str: String, fromEnd: Bool) => {
|
|
|
2157
2010
|
}
|
|
2158
2011
|
count += 1n
|
|
2159
2012
|
}
|
|
2160
|
-
|
|
2161
|
-
// Copy the string
|
|
2162
|
-
if (fromEnd) {
|
|
2163
|
-
Memory.copy(str + 8n, stringPtr, byteLength - count)
|
|
2164
|
-
} else {
|
|
2165
|
-
Memory.copy(str + 8n, stringPtr + count, byteLength - count)
|
|
2166
|
-
}
|
|
2167
|
-
WasmI32.toGrain(str): String
|
|
2013
|
+
count
|
|
2168
2014
|
}
|
|
2169
2015
|
/**
|
|
2170
2016
|
* Trims the beginning of a string—removing any leading whitespace characters.
|
|
@@ -2176,7 +2022,17 @@ let trimString = (str: String, fromEnd: Bool) => {
|
|
|
2176
2022
|
*
|
|
2177
2023
|
* @since v0.4.2
|
|
2178
2024
|
*/
|
|
2179
|
-
|
|
2025
|
+
@unsafe
|
|
2026
|
+
provide let trimStart = (string: String) => {
|
|
2027
|
+
use WasmI32.{ (-), (+) }
|
|
2028
|
+
let mut stringPtr = WasmI32.fromGrain(string)
|
|
2029
|
+
let byteLength = WasmI32.load(stringPtr, 4n)
|
|
2030
|
+
stringPtr += 8n
|
|
2031
|
+
let count = trimString(stringPtr, byteLength, false)
|
|
2032
|
+
let str = allocateString(byteLength - count)
|
|
2033
|
+
Memory.copy(str + 8n, stringPtr + count, byteLength - count)
|
|
2034
|
+
WasmI32.toGrain(str): String
|
|
2035
|
+
}
|
|
2180
2036
|
/**
|
|
2181
2037
|
* Trims the end of a string—removing any trailing whitespace characters.
|
|
2182
2038
|
*
|
|
@@ -2187,7 +2043,17 @@ export let trimStart = (string: String) => trimString(string, false)
|
|
|
2187
2043
|
*
|
|
2188
2044
|
* @since v0.4.2
|
|
2189
2045
|
*/
|
|
2190
|
-
|
|
2046
|
+
@unsafe
|
|
2047
|
+
provide let trimEnd = (string: String) => {
|
|
2048
|
+
use WasmI32.{ (-), (+) }
|
|
2049
|
+
let mut stringPtr = WasmI32.fromGrain(string)
|
|
2050
|
+
let byteLength = WasmI32.load(stringPtr, 4n)
|
|
2051
|
+
stringPtr += 8n
|
|
2052
|
+
let count = trimString(stringPtr, byteLength, true)
|
|
2053
|
+
let str = allocateString(byteLength - count)
|
|
2054
|
+
Memory.copy(str + 8n, stringPtr, byteLength - count)
|
|
2055
|
+
WasmI32.toGrain(str): String
|
|
2056
|
+
}
|
|
2191
2057
|
/**
|
|
2192
2058
|
* Trims a string—removing all leading and trailing whitespace characters.
|
|
2193
2059
|
*
|
|
@@ -2198,4 +2064,58 @@ export let trimEnd = (string: String) => trimString(string, true)
|
|
|
2198
2064
|
*
|
|
2199
2065
|
* @since v0.4.2
|
|
2200
2066
|
*/
|
|
2201
|
-
|
|
2067
|
+
@unsafe
|
|
2068
|
+
provide let trim = (string: String) => {
|
|
2069
|
+
use WasmI32.{ (-), (+), (==) }
|
|
2070
|
+
let mut stringPtr = WasmI32.fromGrain(string)
|
|
2071
|
+
let byteLength = WasmI32.load(stringPtr, 4n)
|
|
2072
|
+
stringPtr += 8n
|
|
2073
|
+
let startCount = trimString(stringPtr, byteLength, false)
|
|
2074
|
+
if (startCount == byteLength) return ""
|
|
2075
|
+
let endCount = trimString(stringPtr, byteLength, true)
|
|
2076
|
+
let str = allocateString(byteLength - startCount - endCount)
|
|
2077
|
+
Memory.copy(
|
|
2078
|
+
str + 8n,
|
|
2079
|
+
stringPtr + startCount,
|
|
2080
|
+
byteLength - startCount - endCount
|
|
2081
|
+
)
|
|
2082
|
+
return WasmI32.toGrain(str): String
|
|
2083
|
+
}
|
|
2084
|
+
|
|
2085
|
+
/**
|
|
2086
|
+
* Converts all ASCII uppercase characters in the string to lowercase.
|
|
2087
|
+
*
|
|
2088
|
+
* @param string: The string to convert
|
|
2089
|
+
* @returns The lowercased string
|
|
2090
|
+
*
|
|
2091
|
+
* @example assert String.toAsciiLowercase("aBc123") == "abc123"
|
|
2092
|
+
*
|
|
2093
|
+
* @since v0.6.0
|
|
2094
|
+
*/
|
|
2095
|
+
provide let toAsciiLowercase = string => {
|
|
2096
|
+
let chars = explode(string)
|
|
2097
|
+
let len = arrayLength(chars)
|
|
2098
|
+
for (let mut i = 0; i < len; i += 1) {
|
|
2099
|
+
chars[i] = Char.toAsciiLowercase(chars[i])
|
|
2100
|
+
}
|
|
2101
|
+
implode(chars)
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
/**
|
|
2105
|
+
* Converts all ASCII lowercase characters in the string to uppercase.
|
|
2106
|
+
*
|
|
2107
|
+
* @param string: The string to convert
|
|
2108
|
+
* @returns The uppercased string
|
|
2109
|
+
*
|
|
2110
|
+
* @example assert String.toAsciiUppercase("aBc123") == "ABC123"
|
|
2111
|
+
*
|
|
2112
|
+
* @since v0.6.0
|
|
2113
|
+
*/
|
|
2114
|
+
provide let toAsciiUppercase = string => {
|
|
2115
|
+
let chars = explode(string)
|
|
2116
|
+
let len = arrayLength(chars)
|
|
2117
|
+
for (let mut i = 0; i < len; i += 1) {
|
|
2118
|
+
chars[i] = Char.toAsciiUppercase(chars[i])
|
|
2119
|
+
}
|
|
2120
|
+
implode(chars)
|
|
2121
|
+
}
|