@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.
- package/CHANGELOG.md +30 -0
- package/array.gr +60 -57
- package/array.md +24 -6
- package/buffer.gr +71 -1
- package/buffer.md +142 -0
- package/bytes.gr +52 -3
- package/bytes.md +117 -0
- package/char.gr +21 -18
- package/char.md +18 -3
- package/immutablepriorityqueue.gr +13 -13
- package/int32.gr +39 -37
- package/int32.md +6 -0
- package/int64.gr +39 -37
- package/int64.md +6 -0
- package/list.gr +31 -22
- package/list.md +39 -10
- package/map.gr +19 -28
- package/number.gr +81 -5
- package/number.md +64 -2
- package/option.gr +30 -26
- package/option.md +12 -0
- package/package.json +1 -1
- package/path.gr +787 -0
- package/path.md +727 -0
- package/pervasives.gr +3 -4
- package/pervasives.md +6 -1
- package/queue.gr +11 -9
- package/queue.md +2 -0
- package/regex.gr +76 -3
- package/regex.md +70 -0
- package/result.gr +24 -20
- package/result.md +12 -0
- package/runtime/atof/common.gr +198 -0
- package/runtime/atof/common.md +243 -0
- package/runtime/atof/decimal.gr +663 -0
- package/runtime/atof/decimal.md +59 -0
- package/runtime/atof/lemire.gr +264 -0
- package/runtime/atof/lemire.md +6 -0
- package/runtime/atof/parse.gr +615 -0
- package/runtime/atof/parse.md +12 -0
- package/runtime/atof/slow.gr +238 -0
- package/runtime/atof/slow.md +6 -0
- package/runtime/atof/table.gr +2016 -0
- package/runtime/atof/table.md +12 -0
- package/runtime/{stringUtils.gr → atoi/parse.gr} +1 -1
- package/runtime/{stringUtils.md → atoi/parse.md} +1 -1
- package/runtime/bigint.gr +3 -3
- package/runtime/equal.gr +1 -1
- package/runtime/numberUtils.gr +2 -2
- package/runtime/numberUtils.md +6 -0
- package/runtime/numbers.gr +4 -4
- package/runtime/unsafe/conv.gr +21 -41
- package/runtime/unsafe/conv.md +0 -3
- package/runtime/unsafe/printWasm.gr +4 -40
- package/runtime/utils/printing.gr +3 -3
- package/stack.gr +4 -2
- package/stack.md +2 -0
- package/string.gr +1 -1
- 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
|
+
}
|