@grain/stdlib 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/array.gr +60 -57
  3. package/array.md +24 -6
  4. package/buffer.gr +71 -1
  5. package/buffer.md +142 -0
  6. package/bytes.gr +52 -3
  7. package/bytes.md +117 -0
  8. package/char.gr +21 -18
  9. package/char.md +18 -3
  10. package/immutablepriorityqueue.gr +13 -13
  11. package/int32.gr +39 -37
  12. package/int32.md +6 -0
  13. package/int64.gr +39 -37
  14. package/int64.md +6 -0
  15. package/list.gr +31 -22
  16. package/list.md +39 -10
  17. package/map.gr +19 -28
  18. package/number.gr +81 -5
  19. package/number.md +64 -2
  20. package/option.gr +30 -26
  21. package/option.md +12 -0
  22. package/package.json +1 -1
  23. package/path.gr +787 -0
  24. package/path.md +727 -0
  25. package/pervasives.gr +3 -4
  26. package/pervasives.md +6 -1
  27. package/queue.gr +11 -9
  28. package/queue.md +2 -0
  29. package/regex.gr +76 -3
  30. package/regex.md +70 -0
  31. package/result.gr +24 -20
  32. package/result.md +12 -0
  33. package/runtime/atof/common.gr +198 -0
  34. package/runtime/atof/common.md +243 -0
  35. package/runtime/atof/decimal.gr +663 -0
  36. package/runtime/atof/decimal.md +59 -0
  37. package/runtime/atof/lemire.gr +264 -0
  38. package/runtime/atof/lemire.md +6 -0
  39. package/runtime/atof/parse.gr +615 -0
  40. package/runtime/atof/parse.md +12 -0
  41. package/runtime/atof/slow.gr +238 -0
  42. package/runtime/atof/slow.md +6 -0
  43. package/runtime/atof/table.gr +2016 -0
  44. package/runtime/atof/table.md +12 -0
  45. package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
  46. package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
  47. package/runtime/bigint.gr +3 -3
  48. package/runtime/equal.gr +1 -1
  49. package/runtime/numberUtils.gr +2 -2
  50. package/runtime/numberUtils.md +6 -0
  51. package/runtime/numbers.gr +4 -4
  52. package/runtime/unsafe/conv.gr +21 -41
  53. package/runtime/unsafe/conv.md +0 -3
  54. package/runtime/unsafe/printWasm.gr +4 -40
  55. package/runtime/utils/printing.gr +3 -3
  56. package/stack.gr +4 -2
  57. package/stack.md +2 -0
  58. package/string.gr +1 -1
  59. package/sys/time.gr +4 -4
@@ -0,0 +1,238 @@
1
+ // This module was based on Rust's dec2flt
2
+ // https://github.com/rust-lang/rust/blob/1cbc45942d5c0f6eb5d94e3b10762ba541958035/library/core/src/num/dec2flt/slow.rs
3
+ // Rust's MIT license is provided below:
4
+ /*
5
+ * Permission is hereby granted, free of charge, to any
6
+ * person obtaining a copy of this software and associated
7
+ * documentation files (the "Software"), to deal in the
8
+ * Software without restriction, including without
9
+ * limitation the rights to use, copy, modify, merge,
10
+ * publish, distribute, sublicense, and/or sell copies of
11
+ * the Software, and to permit persons to whom the Software
12
+ * is furnished to do so, subject to the following
13
+ * conditions:
14
+ *
15
+ * The above copyright notice and this permission notice
16
+ * shall be included in all copies or substantial portions
17
+ * of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20
+ * ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21
+ * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22
+ * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23
+ * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26
+ * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27
+ * DEALINGS IN THE SOFTWARE.
28
+ */
29
+
30
+ //! Slow, fallback algorithm for cases the Eisel-Lemire algorithm cannot round.
31
+
32
+ import WasmI32 from "runtime/unsafe/wasmi32"
33
+ import WasmI64 from "runtime/unsafe/wasmi64"
34
+ import Memory from "runtime/unsafe/memory"
35
+ import { newInt32, newInt64 } from "runtime/dataStructures"
36
+
37
+ import {
38
+ BiasedFp,
39
+ fpZero,
40
+ fpInf,
41
+ fpErr,
42
+ _MINIMUM_EXPONENT,
43
+ _INFINITE_POWER,
44
+ _MANTISSA_EXPLICIT_BITS_32,
45
+ _MANTISSA_EXPLICIT_BITS_64,
46
+ } from "./common"
47
+ import Decimal, { parseDecimal, _DECIMAL_POINT_RANGE } from "./decimal"
48
+
49
+ @unsafe
50
+ let _MAX_SHIFT = 60n
51
+ @unsafe
52
+ let _NUM_POWERS = 19n
53
+ @unsafe
54
+ let mut _POWERS = -1n
55
+
56
+ @unsafe
57
+ let get_POWERS = () => {
58
+ let (==) = WasmI32.eq
59
+ if (_POWERS == -1n) {
60
+ _POWERS = Memory.malloc(130n)
61
+ WasmI32.store8(_POWERS, 0n, 0n)
62
+ WasmI32.store8(_POWERS, 3n, 1n)
63
+ WasmI32.store8(_POWERS, 6n, 2n)
64
+ WasmI32.store8(_POWERS, 9n, 3n)
65
+ WasmI32.store8(_POWERS, 13n, 4n)
66
+ WasmI32.store8(_POWERS, 16n, 5n)
67
+ WasmI32.store8(_POWERS, 19n, 6n)
68
+ WasmI32.store8(_POWERS, 23n, 7n)
69
+ WasmI32.store8(_POWERS, 26n, 8n)
70
+ WasmI32.store8(_POWERS, 29n, 9n)
71
+ WasmI32.store8(_POWERS, 33n, 10n)
72
+ WasmI32.store8(_POWERS, 36n, 11n)
73
+ WasmI32.store8(_POWERS, 39n, 12n)
74
+ WasmI32.store8(_POWERS, 43n, 13n)
75
+ WasmI32.store8(_POWERS, 46n, 14n)
76
+ WasmI32.store8(_POWERS, 49n, 15n)
77
+ WasmI32.store8(_POWERS, 53n, 16n)
78
+ WasmI32.store8(_POWERS, 56n, 17n)
79
+ WasmI32.store8(_POWERS, 59n, 18n)
80
+ }
81
+ _POWERS
82
+ }
83
+
84
+ @unsafe
85
+ let getShift = n => {
86
+ if (WasmI32.ltS(n, _NUM_POWERS)) {
87
+ WasmI32.load8U(get_POWERS(), n)
88
+ } else {
89
+ _MAX_SHIFT
90
+ }
91
+ }
92
+
93
+ /*
94
+ * Parse the significant digits and biased, binary exponent of a float.
95
+ *
96
+ * This is a fallback algorithm that uses a big-integer representation
97
+ * of the float, and therefore is considerably slower than faster
98
+ * approximations. However, it will always determine how to round
99
+ * the significant digits to the nearest machine float, allowing
100
+ * use to handle near half-way cases.
101
+ *
102
+ * Near half-way cases are halfway between two consecutive machine floats.
103
+ * For example, the float `16777217.0` has a bitwise representation of
104
+ * `100000000000000000000000 1`. Rounding to a single-precision float,
105
+ * the trailing `1` is truncated. Using round-nearest, tie-even, any
106
+ * value above `16777217.0` must be rounded up to `16777218.0`, while
107
+ * any value before or equal to `16777217.0` must be rounded down
108
+ * to `16777216.0`. These near-halfway conversions therefore may require
109
+ * a large number of digits to unambiguously determine how to round.
110
+ *
111
+ * The algorithms described here are based on "Processing Long Numbers Quickly",
112
+ * available here: <https://arxiv.org/pdf/2101.11408.pdf#section.11>.
113
+ */
114
+ @unsafe
115
+ export let parseLongMantissa = (s: String) => {
116
+ let (+) = WasmI32.add
117
+ let (-) = WasmI32.sub
118
+ let (&) = WasmI32.and
119
+ let (<) = WasmI32.ltS
120
+ let (>) = WasmI32.gtS
121
+ let (>=) = WasmI32.geS
122
+ let (<=) = WasmI32.leS
123
+ let (>>) = WasmI32.shrU
124
+ let (<<) = WasmI32.shl
125
+ let (==) = WasmI32.eq
126
+
127
+ let mut d = parseDecimal(s)
128
+ let digits = WasmI32.fromGrain(d.digits)
129
+ let mut numDigits = WasmI32.load(WasmI32.fromGrain(d.numDigits), 8n)
130
+ let mut decimalPoint = WasmI32.load(WasmI32.fromGrain(d.decimalPoint), 8n)
131
+
132
+ // Short-circuit if the value can only be a literal 0 or infinity.
133
+ if (numDigits == 0n || decimalPoint < -324n) {
134
+ fpZero()
135
+ } else if (decimalPoint >= 310n) {
136
+ fpInf()
137
+ } else {
138
+ let mut exp2 = 0n
139
+ // Shift right toward (1/2 ... 1].
140
+ let mut done = false
141
+ while (decimalPoint > 0n) {
142
+ let n = decimalPoint
143
+ let shift = getShift(n)
144
+ Decimal.rightShift(d, shift)
145
+ decimalPoint = WasmI32.load(WasmI32.fromGrain(d.decimalPoint), 8n)
146
+ if (decimalPoint < 0n - _DECIMAL_POINT_RANGE) {
147
+ done = true
148
+ break
149
+ }
150
+ exp2 += shift
151
+ }
152
+ if (done) {
153
+ fpZero()
154
+ } else {
155
+ // Shift left toward (1/2 ... 1].
156
+ let mut done = false
157
+ while (decimalPoint <= 0n) {
158
+ let shift = if (decimalPoint == 0n) {
159
+ match (WasmI32.load8U(digits, 8n)) {
160
+ digit when digit >= 5n => {
161
+ break
162
+ // Align types
163
+ 0n
164
+ },
165
+ 0n | 1n => 2n,
166
+ _ => 1n,
167
+ }
168
+ } else {
169
+ getShift(0n - decimalPoint)
170
+ }
171
+ Decimal.leftShift(d, shift)
172
+ decimalPoint = WasmI32.load(WasmI32.fromGrain(d.decimalPoint), 8n)
173
+ if (decimalPoint > _DECIMAL_POINT_RANGE) {
174
+ done = true
175
+ break
176
+ }
177
+ exp2 -= shift
178
+ }
179
+ if (done) {
180
+ fpInf()
181
+ } else {
182
+ // We are now in the range [1/2 ... 1] but the binary format uses [1 ... 2].
183
+ exp2 -= 1n
184
+ while (_MINIMUM_EXPONENT + 1n > exp2) {
185
+ let mut n = _MINIMUM_EXPONENT + 1n - exp2
186
+ if (n > _MAX_SHIFT) {
187
+ n = _MAX_SHIFT
188
+ }
189
+ Decimal.rightShift(d, n)
190
+ exp2 += n
191
+ }
192
+ if (exp2 - _MINIMUM_EXPONENT >= _INFINITE_POWER) {
193
+ fpInf()
194
+ } else {
195
+ // Shift the decimal to the hidden bit, and then round the value
196
+ // to get the high mantissa+1 bits.
197
+ Decimal.leftShift(d, _MANTISSA_EXPLICIT_BITS_32 + 1n)
198
+ let mut mantissa = Decimal.round(d)
199
+ let mut done = false
200
+ if (
201
+ WasmI64.geU(
202
+ mantissa,
203
+ WasmI64.shl(1N, WasmI64.add(_MANTISSA_EXPLICIT_BITS_64, 1N))
204
+ )
205
+ ) {
206
+ // Rounding up overflowed to the carry bit, need to
207
+ // shift back to the hidden bit.
208
+ Decimal.rightShift(d, 1n)
209
+ exp2 += 1n
210
+ mantissa = Decimal.round(d)
211
+ if (exp2 - _MINIMUM_EXPONENT >= _INFINITE_POWER) {
212
+ done = true
213
+ }
214
+ }
215
+ if (done) {
216
+ fpInf()
217
+ } else {
218
+ let mut power2 = exp2 - _MINIMUM_EXPONENT
219
+ if (
220
+ WasmI64.ltU(mantissa, WasmI64.shl(1N, _MANTISSA_EXPLICIT_BITS_64))
221
+ ) {
222
+ power2 -= 1n
223
+ }
224
+ // Zero out all the bits above the explicit mantissa bits.
225
+ mantissa = WasmI64.and(
226
+ mantissa,
227
+ WasmI64.sub(WasmI64.shl(1N, _MANTISSA_EXPLICIT_BITS_64), 1N)
228
+ )
229
+ {
230
+ f: WasmI32.toGrain(newInt64(mantissa)): Int64,
231
+ e: WasmI32.toGrain(newInt32(power2)): Int32,
232
+ }
233
+ }
234
+ }
235
+ }
236
+ }
237
+ }
238
+ }
@@ -0,0 +1,6 @@
1
+ ### Slow.**parseLongMantissa**
2
+
3
+ ```grain
4
+ parseLongMantissa : String -> %Common.BiasedFp
5
+ ```
6
+