@grain/stdlib 0.5.2 → 0.5.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/array.gr +61 -1
  3. package/array.md +113 -0
  4. package/bigint.md +30 -30
  5. package/buffer.gr +24 -22
  6. package/char.gr +2 -2
  7. package/float32.md +3 -3
  8. package/float64.md +3 -3
  9. package/immutablemap.gr +493 -0
  10. package/immutablemap.md +479 -0
  11. package/immutablepriorityqueue.gr +360 -0
  12. package/immutablepriorityqueue.md +291 -0
  13. package/immutableset.gr +498 -0
  14. package/immutableset.md +449 -0
  15. package/list.gr +75 -2
  16. package/list.md +110 -0
  17. package/map.gr +1 -2
  18. package/marshal.gr +1058 -0
  19. package/marshal.md +76 -0
  20. package/number.gr +689 -23
  21. package/number.md +362 -27
  22. package/package.json +1 -1
  23. package/pervasives.gr +16 -5
  24. package/pervasives.md +28 -0
  25. package/priorityqueue.gr +261 -0
  26. package/priorityqueue.md +309 -0
  27. package/queue.gr +14 -1
  28. package/queue.md +16 -1
  29. package/regex.gr +90 -67
  30. package/runtime/bigint.gr +4 -4
  31. package/runtime/compare.gr +179 -0
  32. package/runtime/compare.md +6 -0
  33. package/runtime/equal.gr +3 -3
  34. package/runtime/exception.gr +9 -5
  35. package/runtime/exception.md +8 -2
  36. package/runtime/gc.gr +2 -1
  37. package/runtime/malloc.gr +1 -3
  38. package/runtime/numberUtils.gr +11 -11
  39. package/runtime/numbers.gr +423 -100
  40. package/runtime/numbers.md +50 -0
  41. package/runtime/string.gr +4 -2
  42. package/set.gr +26 -27
  43. package/stack.gr +12 -0
  44. package/stack.md +15 -0
  45. package/string.gr +409 -53
  46. package/string.md +164 -1
  47. package/sys/file.gr +4 -4
  48. package/sys/file.md +3 -3
  49. package/sys/process.gr +3 -3
  50. package/sys/process.md +3 -3
  51. package/sys/random.gr +2 -2
  52. package/sys/random.md +2 -2
  53. package/sys/time.gr +2 -2
  54. package/sys/time.md +2 -2
package/string.gr CHANGED
@@ -11,6 +11,7 @@ import Memory from "runtime/unsafe/memory"
11
11
  import Exception from "runtime/exception"
12
12
  import Conv from "runtime/unsafe/conv"
13
13
  import {
14
+ untagSimpleNumber,
14
15
  tagSimpleNumber,
15
16
  tagChar,
16
17
  untagChar,
@@ -100,7 +101,7 @@ export let byteLength = (string: String) => {
100
101
  }
101
102
 
102
103
  /**
103
- * Finds the position of a substring in the input string.
104
+ * Finds the first position of a substring in the input string.
104
105
  *
105
106
  * @param search: The substring to find
106
107
  * @param string: The string to inspect
@@ -161,6 +162,65 @@ export let indexOf = (search: String, string: String) => {
161
162
  }
162
163
  }
163
164
 
165
+ /**
166
+ * Finds the last position of a substring in the input string.
167
+ *
168
+ * @param search: The substring to find
169
+ * @param string: The string to inspect
170
+ * @returns `Some(position)` containing the starting position of the substring if found or `None` otherwise
171
+ *
172
+ * @example String.lastIndexOf("world", "Hello world world") == Some(12)
173
+ *
174
+ * @since v0.5.3
175
+ */
176
+ @unsafe
177
+ export let lastIndexOf = (search: String, string: String) => {
178
+ // The last possible index in the string given the length of the search
179
+ let lastIndex = length(string) - length(search)
180
+
181
+ let (>) = WasmI32.gtU
182
+ let (>=) = WasmI32.geU
183
+ let (==) = WasmI32.eq
184
+ let (!=) = WasmI32.ne
185
+ let (+) = WasmI32.add
186
+ let (-) = WasmI32.sub
187
+ let (&) = WasmI32.and
188
+
189
+ let search = WasmI32.fromGrain(search)
190
+ let string = WasmI32.fromGrain(string)
191
+ let searchSize = WasmI32.load(search, 4n)
192
+ let stringSize = WasmI32.load(string, 4n)
193
+ if (searchSize > stringSize) {
194
+ None
195
+ } else {
196
+ let mut matchIndex = -1n
197
+ let mut stringIndex = untagSimpleNumber(lastIndex)
198
+ let searchPtr = search + 8n
199
+ let stringStartPtr = string + 8n
200
+ for (
201
+ let mut stringPtr = stringStartPtr + stringSize - searchSize;
202
+ stringPtr >= stringStartPtr;
203
+ stringPtr -= 1n
204
+ ) {
205
+ let byte = WasmI32.load8U(stringPtr, 0n)
206
+ if ((byte & 0xC0n) == 0x80n) {
207
+ // We're not at the start of a codepoint, so move on
208
+ continue
209
+ }
210
+ if (Memory.compare(stringPtr, searchPtr, searchSize) == 0n) {
211
+ matchIndex = stringIndex
212
+ break
213
+ }
214
+ stringIndex -= 1n
215
+ }
216
+ if (matchIndex == -1n) {
217
+ None
218
+ } else {
219
+ Some(tagSimpleNumber(matchIndex))
220
+ }
221
+ }
222
+ }
223
+
164
224
  @disableGC
165
225
  let getCodePoint = (ptr: WasmI32) => {
166
226
  // Algorithm from https://encoding.spec.whatwg.org/#utf-8-decoder
@@ -221,19 +281,9 @@ let getCodePoint = (ptr: WasmI32) => {
221
281
  }
222
282
  result
223
283
  }
224
- /**
225
- * Get the character at the position in the input string.
226
- *
227
- * @param position: The position to check
228
- * @param string: The string to search
229
- * @returns The character at the provided position
230
- *
231
- * @example String.charAt(5, "Hello world") == ' '
232
- *
233
- * @since v0.4.0
234
- */
284
+
235
285
  @unsafe
236
- export let charAt = (position, string: String) => {
286
+ let charAtHelp = (position, string: String) => {
237
287
  if (length(string) <= position || position < 0) {
238
288
  fail "Invalid offset: " ++ toString(position)
239
289
  }
@@ -249,10 +299,10 @@ export let charAt = (position, string: String) => {
249
299
  let mut ptr = string + 8n
250
300
  let end = ptr + size
251
301
  let mut counter = 0n
252
- let mut result = WasmI32.toGrain(0n): Char
302
+ let mut result = 0n
253
303
  while (ptr < end) {
254
304
  if (counter == position) {
255
- result = tagChar(getCodePoint(ptr))
305
+ result = getCodePoint(ptr)
256
306
  break
257
307
  }
258
308
  let byte = WasmI32.load8U(ptr, 0n)
@@ -274,6 +324,38 @@ export let charAt = (position, string: String) => {
274
324
  result
275
325
  }
276
326
 
327
+ /**
328
+ * Get the Unicode code point at the position in the input string.
329
+ *
330
+ * @param position: The position to check
331
+ * @param string: The string to search
332
+ * @returns The character code at the provided position
333
+ *
334
+ * @example String.charCodeAt(5, "Hello world") == 32
335
+ *
336
+ * @since v0.5.3
337
+ */
338
+ @unsafe
339
+ export let charCodeAt = (position, string: String) => {
340
+ tagSimpleNumber(charAtHelp(position, string))
341
+ }
342
+
343
+ /**
344
+ * Get the character at the position in the input string.
345
+ *
346
+ * @param position: The position to check
347
+ * @param string: The string to search
348
+ * @returns The character at the provided position
349
+ *
350
+ * @example String.charAt(5, "Hello world") == ' '
351
+ *
352
+ * @since v0.4.0
353
+ */
354
+ @unsafe
355
+ export let charAt = (position, string: String) => {
356
+ tagChar(charAtHelp(position, string))
357
+ }
358
+
277
359
  @unsafe
278
360
  let explodeHelp = (s: String, chars) => {
279
361
  let (>>>) = WasmI32.shrU
@@ -790,6 +872,239 @@ export let endsWith = (search: String, string: String) => {
790
872
  }
791
873
  }
792
874
 
875
+ /**
876
+ * Replaces the first appearance of the search pattern in the string with the replacement value.
877
+ *
878
+ * @param searchPattern: The string to replace
879
+ * @param replacement: The replacement
880
+ * @param string: The string to change
881
+ * @returns A new string with the first occurrence of the search pattern replaced
882
+ *
883
+ * @example String.replaceFirst("🌾", "🌎", "Hello 🌾🌾") == "Hello 🌎🌾"
884
+ *
885
+ * @since v0.5.4
886
+ */
887
+ @unsafe
888
+ export let replaceFirst =
889
+ (
890
+ searchPattern: String,
891
+ replacement: String,
892
+ string: String,
893
+ ) => {
894
+ let (+) = WasmI32.add
895
+ let (-) = WasmI32.sub
896
+ let (>) = WasmI32.gtU
897
+ let (<) = WasmI32.ltU
898
+ let (==) = WasmI32.eq
899
+
900
+ let mut patternPtr = WasmI32.fromGrain(searchPattern)
901
+ let mut stringPtr = WasmI32.fromGrain(string)
902
+ let mut replacementPtr = WasmI32.fromGrain(replacement)
903
+
904
+ let patternLen = WasmI32.load(patternPtr, 4n)
905
+ let stringLen = WasmI32.load(stringPtr, 4n)
906
+ let replacementLen = WasmI32.load(replacementPtr, 4n)
907
+ // Bail if search str is longer than the string
908
+ if (stringLen < patternLen) {
909
+ string
910
+ } else {
911
+ patternPtr += 8n
912
+ stringPtr += 8n
913
+ replacementPtr += 8n
914
+
915
+ let mut found = false
916
+ // Search for an instance of the string
917
+ let mut foundIndex = -1n
918
+ let stringEndPtr = stringPtr + stringLen - patternLen + 1n
919
+ for (let mut i = stringPtr; i < stringEndPtr; i += 1n) {
920
+ // check for match
921
+ foundIndex += 1n
922
+ if (Memory.compare(i, patternPtr, patternLen) == 0n) {
923
+ found = true
924
+ break
925
+ }
926
+ }
927
+ if (found) {
928
+ // Create the new string
929
+ let str = allocateString(stringLen - patternLen + replacementLen)
930
+ let strPtr = str + 8n
931
+ Memory.copy(strPtr, stringPtr, foundIndex)
932
+ Memory.copy(strPtr + foundIndex, replacementPtr, replacementLen)
933
+ Memory.copy(
934
+ strPtr + foundIndex + replacementLen,
935
+ stringPtr + foundIndex + patternLen,
936
+ stringLen - foundIndex
937
+ )
938
+ // Copy over the str
939
+ WasmI32.toGrain(str): String
940
+ } else {
941
+ string
942
+ }
943
+ }
944
+ }
945
+
946
+ /**
947
+ * Replaces the last appearance of the search pattern in the string with the replacement value.
948
+ *
949
+ * @param searchPattern: The string to replace
950
+ * @param replacement: The replacement
951
+ * @param string: The string to change
952
+ * @returns A new string with the last occurrence of the search pattern replaced
953
+ *
954
+ * @example String.replaceLast("🌾", "🌎", "Hello 🌾🌾") == "Hello 🌾🌎"
955
+ *
956
+ * @since v0.5.4
957
+ */
958
+ @unsafe
959
+ export let replaceLast =
960
+ (
961
+ searchPattern: String,
962
+ replacement: String,
963
+ string: String,
964
+ ) => {
965
+ let (+) = WasmI32.add
966
+ let (-) = WasmI32.sub
967
+ let (>) = WasmI32.gtU
968
+ let (<) = WasmI32.ltU
969
+ let (==) = WasmI32.eq
970
+
971
+ let mut patternPtr = WasmI32.fromGrain(searchPattern)
972
+ let mut stringPtr = WasmI32.fromGrain(string)
973
+ let mut replacementPtr = WasmI32.fromGrain(replacement)
974
+
975
+ let patternLen = WasmI32.load(patternPtr, 4n)
976
+ let stringLen = WasmI32.load(stringPtr, 4n)
977
+ let replacementLen = WasmI32.load(replacementPtr, 4n)
978
+
979
+ // Bail if search str is longer than the string
980
+ if (stringLen < patternLen) {
981
+ string
982
+ } else {
983
+ patternPtr += 8n
984
+ stringPtr += 8n
985
+ replacementPtr += 8n
986
+
987
+ let mut found = false
988
+ // Search for an instance of the string
989
+ let stringEndPtr = stringPtr + stringLen - patternLen
990
+ let mut foundIndex = stringLen - patternLen + 1n
991
+ for (let mut i = stringEndPtr; i > stringPtr - 1n; i -= 1n) {
992
+ // check for match
993
+ foundIndex -= 1n
994
+ if (Memory.compare(i, patternPtr, patternLen) == 0n) {
995
+ found = true
996
+ break
997
+ }
998
+ }
999
+ if (found) {
1000
+ // Create the new string
1001
+ let str = allocateString(stringLen - patternLen + replacementLen)
1002
+ let strPtr = str + 8n
1003
+ Memory.copy(strPtr, stringPtr, foundIndex)
1004
+ Memory.copy(strPtr + foundIndex, replacementPtr, replacementLen)
1005
+ Memory.copy(
1006
+ strPtr + foundIndex + replacementLen,
1007
+ stringPtr + foundIndex + patternLen,
1008
+ stringLen - foundIndex
1009
+ )
1010
+ // Copy over the str
1011
+ WasmI32.toGrain(str): String
1012
+ } else {
1013
+ string
1014
+ }
1015
+ }
1016
+ }
1017
+
1018
+ /**
1019
+ * Replaces every appearance of the search pattern in the string with the replacement value.
1020
+ *
1021
+ * @param searchPattern: The string to replace
1022
+ * @param replacement: The replacement
1023
+ * @param string: The string to change
1024
+ * @returns A new string with each occurrence of the search pattern replaced
1025
+ *
1026
+ * @example String.replaceAll("🌾", "🌎", "Hello 🌾🌾") == "Hello 🌎🌎"
1027
+ *
1028
+ * @since v0.5.4
1029
+ */
1030
+ @unsafe
1031
+ export let replaceAll =
1032
+ (
1033
+ searchPattern: String,
1034
+ replacement: String,
1035
+ string: String,
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
1044
+
1045
+ let mut patternPtr = WasmI32.fromGrain(searchPattern)
1046
+ let mut stringPtr = WasmI32.fromGrain(string)
1047
+ let mut replacementPtr = WasmI32.fromGrain(replacement)
1048
+
1049
+ let patternLen = WasmI32.load(patternPtr, 4n)
1050
+ let stringLen = WasmI32.load(stringPtr, 4n)
1051
+ let replacementLen = WasmI32.load(replacementPtr, 4n)
1052
+
1053
+ // Bail if search str is longer than the string
1054
+ if (stringLen < patternLen) {
1055
+ string
1056
+ } else {
1057
+ patternPtr += 8n
1058
+ stringPtr += 8n
1059
+ replacementPtr += 8n
1060
+
1061
+ let mut found = false
1062
+ // Search for an instance of the string
1063
+ let stringEndPtr = stringPtr + stringLen - patternLen
1064
+ let mut foundIndex = stringLen - patternLen + 1n
1065
+ let mut foundIndexes = []
1066
+ let mut foundCount = 0n
1067
+ for (let mut i = stringEndPtr; i > stringPtr - 1n; i -= 1n) {
1068
+ // check for match
1069
+ foundIndex -= 1n
1070
+ if (Memory.compare(i, patternPtr, patternLen) == 0n) {
1071
+ found = true
1072
+ foundCount += 1n
1073
+ foundIndexes = [tagSimpleNumber(foundIndex), ...foundIndexes]
1074
+ }
1075
+ }
1076
+ if (found) {
1077
+ // Create the new string
1078
+ let str = allocateString(
1079
+ stringLen - (patternLen - replacementLen) * foundCount
1080
+ )
1081
+ let mut strPtr = str + 8n
1082
+ let mut lastIndex = 0n
1083
+ while (true) {
1084
+ match (foundIndexes) {
1085
+ [idx, ...rest] => {
1086
+ let index = untagSimpleNumber(idx)
1087
+ // Copy the part before
1088
+ Memory.copy(strPtr, stringPtr + lastIndex, index - lastIndex)
1089
+ strPtr += index - lastIndex
1090
+ // Copy the part after
1091
+ Memory.copy(strPtr, replacementPtr, replacementLen)
1092
+ strPtr += replacementLen
1093
+ lastIndex = index + patternLen
1094
+ foundIndexes = rest
1095
+ },
1096
+ [] => break,
1097
+ }
1098
+ }
1099
+ // Copy remaining string
1100
+ Memory.copy(strPtr, stringPtr + lastIndex, stringLen - lastIndex)
1101
+ WasmI32.toGrain(str): String
1102
+ } else {
1103
+ string
1104
+ }
1105
+ }
1106
+ }
1107
+
793
1108
  // String->Byte encoding and helper functions:
794
1109
 
795
1110
  // these are globals to avoid memory leaks
@@ -1267,33 +1582,33 @@ let bytesHaveBom = (bytes: Bytes, encoding: Encoding, start: WasmI32) => {
1267
1582
  match (encoding) {
1268
1583
  UTF8 => {
1269
1584
  bytesSize >= 3n &&
1270
- WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xEFn &&
1271
- WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xBBn &&
1272
- WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0xBFn
1585
+ WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xEFn &&
1586
+ WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xBBn &&
1587
+ WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0xBFn
1273
1588
  },
1274
1589
  UTF16_BE => {
1275
1590
  bytesSize >= 2n &&
1276
- WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFEn &&
1277
- WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFFn
1591
+ WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFEn &&
1592
+ WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFFn
1278
1593
  },
1279
1594
  UTF16_LE => {
1280
1595
  bytesSize >= 2n &&
1281
- WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFFn &&
1282
- WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFEn
1596
+ WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFFn &&
1597
+ WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFEn
1283
1598
  },
1284
1599
  UTF32_BE => {
1285
1600
  bytesSize >= 4n &&
1286
- WasmI32.load8U(ptr, _BYTES_OFFSET) == 0x00n &&
1287
- WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0x00n &&
1288
- WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0xFEn &&
1289
- WasmI32.load8U(ptr + 3n, _BYTES_OFFSET) == 0xFFn
1601
+ WasmI32.load8U(ptr, _BYTES_OFFSET) == 0x00n &&
1602
+ WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0x00n &&
1603
+ WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0xFEn &&
1604
+ WasmI32.load8U(ptr + 3n, _BYTES_OFFSET) == 0xFFn
1290
1605
  },
1291
1606
  UTF32_LE => {
1292
1607
  bytesSize >= 4n &&
1293
- WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFFn &&
1294
- WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFEn &&
1295
- WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0x00n &&
1296
- WasmI32.load8U(ptr + 3n, _BYTES_OFFSET) == 0x00n
1608
+ WasmI32.load8U(ptr, _BYTES_OFFSET) == 0xFFn &&
1609
+ WasmI32.load8U(ptr + 1n, _BYTES_OFFSET) == 0xFEn &&
1610
+ WasmI32.load8U(ptr + 2n, _BYTES_OFFSET) == 0x00n &&
1611
+ WasmI32.load8U(ptr + 3n, _BYTES_OFFSET) == 0x00n
1297
1612
  },
1298
1613
  }
1299
1614
  }
@@ -1530,7 +1845,7 @@ let decodeRangeHelp =
1530
1845
  // high surrogate. next character is low srurrogate
1531
1846
  let w1 = (w1 & 0x03FFn) << 10n
1532
1847
  let w2 = (WasmI32.load8U(bytesPtr, 2n) << 8n |
1533
- WasmI32.load8U(bytesPtr, 3n)) &
1848
+ WasmI32.load8U(bytesPtr, 3n)) &
1534
1849
  0x03FFn
1535
1850
  let codeWord = w1 + w2 + 0x10000n
1536
1851
  // no problems, so go past both code words
@@ -1553,7 +1868,7 @@ let decodeRangeHelp =
1553
1868
  // high surrogate. next character is low srurrogate
1554
1869
  let w1 = (w1 & 0x03FFn) << 10n
1555
1870
  let w2 = (WasmI32.load8U(bytesPtr, 3n) << 8n |
1556
- WasmI32.load8U(bytesPtr, 2n)) &
1871
+ WasmI32.load8U(bytesPtr, 2n)) &
1557
1872
  0x03FFn
1558
1873
  //let uPrime = codePoint - 0x10000n
1559
1874
  //let w1 = ((uPrime & 0b11111111110000000000n) >>> 10n) + 0xD800n // High surrogate
@@ -1785,30 +2100,71 @@ export let forEachCodePointi = (fn: (Number, Number) -> Void, str: String) => {
1785
2100
  void
1786
2101
  }
1787
2102
 
1788
- let trimString = (str: String, end: Bool) => {
1789
- let chars = explode(str), charsLength = length(str)
1790
- let mut i = 0, offset = 1
1791
- if (end) {
1792
- i = charsLength - 1
1793
- offset = -1
2103
+ @unsafe
2104
+ let trimString = (str: String, fromEnd: Bool) => {
2105
+ let (>>>) = WasmI32.shrU
2106
+ let (+) = WasmI32.add
2107
+ let (*) = WasmI32.mul
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
2117
+ if (fromEnd) {
2118
+ i = byteLength - 1n
2119
+ offset = -1n
1794
2120
  }
1795
- for (; i < charsLength && i > -1; i += offset) {
1796
- let currentChar = chars[i]
1797
- // TODO: Use unicode whitespace property and unicode line terminator once github issue #661 is completed
2121
+ let mut count = 0n
2122
+ for (; i < byteLength; i += offset) {
2123
+ // Get the byte, not necessarily a full UTF-8 codepoint
2124
+ let byte = WasmI32.load8U(stringPtr, i)
2125
+ // TODO(#661): Use unicode whitespace property and unicode line terminator
2126
+ if (!fromEnd) {
2127
+ if (
2128
+ byte == 0xEFn && // Check for the first BOM byte
2129
+ // Check for the full BOM codepoint, 0xEFBBBF. Bytes are reversed because wasm is little-endian
2130
+ WasmI32.load(stringPtr, i - 1n) >>> 8n == 0xBFBBEFn
2131
+ ) {
2132
+ i += 2n
2133
+ count += 3n
2134
+ continue
2135
+ }
2136
+ } else {
2137
+ if (
2138
+ byte == 0xBFn && // Check for the last BOM byte
2139
+ // Check for the full BOM codepoint, 0xEFBBBF. Bytes are reversed because wasm is little-endian
2140
+ WasmI32.load(stringPtr, i - 3n) >>> 8n == 0xBFBBEFn
2141
+ ) {
2142
+ i -= 2n
2143
+ count += 3n
2144
+ continue
2145
+ }
2146
+ }
1798
2147
  if (
1799
- // Spacing
1800
- currentChar != '\u{0009}' && // Tab
1801
- currentChar != '\u{000B}' && // LINE TABULATION
1802
- currentChar != '\u{000C}' && // FORM FEED (FF)
1803
- currentChar != '\u{0020}' && // Space
1804
- currentChar != '\u{00A0}' && // No Break Space
1805
- currentChar != '\u{FEFF}' && // ZERO WIDTH NO-BREAK SPACE
1806
- // Line Terminators
1807
- currentChar != '\n' && // LF
1808
- currentChar != '\r' // CR
1809
- ) break
2148
+ byte != 0x20n && // Space
2149
+ byte != 0x0Dn && // LF
2150
+ byte != 0x0An && // CR
2151
+ byte != 0x09n && // Tab
2152
+ byte != 0x0Bn && // LINE TABULATION
2153
+ byte != 0x0Cn && // FORM FEED (FF)
2154
+ byte != 0xA0n // No Break Space
2155
+ ) {
2156
+ break
2157
+ }
2158
+ count += 1n
1810
2159
  }
1811
- if (end) slice(0, i + 1, str) else slice(i, charsLength, str)
2160
+ let str = allocateString(byteLength - count)
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
1812
2168
  }
1813
2169
  /**
1814
2170
  * Trims the beginning of a string—removing any leading whitespace characters.