@grain/stdlib 0.4.1 → 0.4.5
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 +63 -0
- package/LICENSE +21 -0
- package/README.md +34 -0
- package/array.gr +200 -89
- package/array.md +81 -5
- package/buffer.gr +93 -36
- package/bytes.gr +512 -407
- package/bytes.md +621 -0
- package/char.gr +119 -55
- package/char.md +200 -0
- package/hash.gr +42 -15
- package/hash.md +44 -0
- package/list.gr +121 -50
- package/map.gr +106 -110
- package/number.gr +37 -1
- package/number.md +66 -0
- package/option.gr +260 -53
- package/option.md +579 -0
- package/package.json +33 -29
- package/pervasives.gr +32 -20
- package/queue.gr +102 -30
- package/queue.md +191 -0
- package/range.gr +26 -26
- package/range.md +1 -1
- package/regex.gr +3055 -0
- package/regex.md +449 -0
- package/result.gr +216 -70
- package/result.md +446 -0
- package/runtime/dataStructures.gr +28 -29
- package/runtime/debug.gr +0 -1
- package/runtime/equal.gr +37 -16
- package/runtime/exception.gr +28 -15
- package/runtime/gc.gr +33 -20
- package/runtime/malloc.gr +19 -11
- package/runtime/numberUtils.gr +208 -105
- package/runtime/numbers.gr +217 -118
- package/runtime/string.gr +150 -59
- package/runtime/stringUtils.gr +176 -0
- package/runtime/unsafe/conv.gr +51 -8
- package/runtime/unsafe/memory.gr +14 -3
- package/runtime/unsafe/printWasm.gr +4 -4
- package/runtime/unsafe/tags.gr +2 -2
- package/runtime/unsafe/wasmf32.gr +9 -2
- package/runtime/unsafe/wasmf64.gr +9 -2
- package/runtime/unsafe/wasmi32.gr +65 -47
- package/runtime/unsafe/wasmi64.gr +78 -50
- package/runtime/wasi.gr +199 -45
- package/set.gr +281 -119
- package/set.md +502 -0
- package/stack.gr +26 -26
- package/stack.md +143 -0
- package/string.gr +697 -329
- package/string.md +815 -0
- package/sys/file.gr +356 -177
- package/sys/process.gr +10 -6
- package/sys/random.gr +3 -6
- package/sys/time.gr +3 -3
package/char.gr
CHANGED
|
@@ -1,35 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module Char: Utilities for working with the Char type.
|
|
3
|
+
*
|
|
4
|
+
* The Char type represents a single [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value).
|
|
5
|
+
*
|
|
6
|
+
* @example import Char from "char"
|
|
7
|
+
*
|
|
8
|
+
* @since 0.3.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
import WasmI32 from "runtime/unsafe/wasmi32"
|
|
2
12
|
import Memory from "runtime/unsafe/memory"
|
|
3
13
|
import Errors from "runtime/unsafe/errors"
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
14
|
+
import {
|
|
15
|
+
tagSimpleNumber,
|
|
16
|
+
allocateChar,
|
|
17
|
+
allocateString,
|
|
18
|
+
} from "runtime/dataStructures"
|
|
7
19
|
|
|
8
20
|
exception MalformedUtf8
|
|
9
21
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
22
|
+
/**
|
|
23
|
+
* @section Values: Functions and constants included in the Char module.
|
|
24
|
+
*/
|
|
13
25
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The minimum valid Unicode scalar value.
|
|
28
|
+
*
|
|
29
|
+
* @since 0.3.0
|
|
30
|
+
*/
|
|
31
|
+
export let min = 0x0000
|
|
32
|
+
/**
|
|
33
|
+
* The maximum valid Unicode scalar value.
|
|
34
|
+
*
|
|
35
|
+
* @since 0.3.0
|
|
36
|
+
*/
|
|
37
|
+
export let max = 0x10FFFF
|
|
17
38
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Determines whether the given character code is a valid Unicode scalar value.
|
|
41
|
+
*
|
|
42
|
+
* @param charCode: The number to check
|
|
43
|
+
* @returns `true` if the number refers to a valid Unicode scalar value or `false` otherwise
|
|
44
|
+
*
|
|
45
|
+
* @since 0.3.0
|
|
46
|
+
*/
|
|
47
|
+
export let isValid = charCode => {
|
|
48
|
+
charCode >= min &&
|
|
49
|
+
(charCode <= 0xD7FF || charCode >= 0xE000) &&
|
|
50
|
+
charCode <= max
|
|
23
51
|
}
|
|
24
52
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Determines the Unicode scalar value for a character.
|
|
55
|
+
*
|
|
56
|
+
* @param char: The character
|
|
57
|
+
* @returns The Unicode scalar value for the given character
|
|
58
|
+
*
|
|
59
|
+
* @since 0.3.0
|
|
60
|
+
*/
|
|
28
61
|
@disableGC
|
|
29
|
-
let code = (
|
|
62
|
+
export let rec code = (char: Char) => {
|
|
30
63
|
// Algorithm from https://encoding.spec.whatwg.org/#utf-8-decoder
|
|
31
64
|
|
|
32
|
-
let
|
|
65
|
+
let char = WasmI32.fromGrain(char)
|
|
33
66
|
|
|
34
67
|
let (+) = WasmI32.add
|
|
35
68
|
let (==) = WasmI32.eq
|
|
@@ -50,7 +83,7 @@ let code = (c: Char) => {
|
|
|
50
83
|
let mut result = 0n
|
|
51
84
|
|
|
52
85
|
while (true) {
|
|
53
|
-
let byte = WasmI32.load8U(
|
|
86
|
+
let byte = WasmI32.load8U(char + offset, 4n)
|
|
54
87
|
offset += 1n
|
|
55
88
|
if (bytesNeeded == 0n) {
|
|
56
89
|
if (byte >= 0x00n && byte <= 0x7Fn) {
|
|
@@ -79,21 +112,30 @@ let code = (c: Char) => {
|
|
|
79
112
|
}
|
|
80
113
|
lowerBoundary = 0x80n
|
|
81
114
|
upperBoundary = 0xBFn
|
|
82
|
-
codePoint =
|
|
115
|
+
codePoint = codePoint << 6n | byte & 0x3Fn
|
|
83
116
|
bytesSeen += 1n
|
|
84
117
|
if (bytesSeen == bytesNeeded) {
|
|
85
118
|
result = codePoint
|
|
86
119
|
break
|
|
87
120
|
}
|
|
88
121
|
}
|
|
122
|
+
|
|
123
|
+
Memory.decRef(char)
|
|
124
|
+
Memory.decRef(WasmI32.fromGrain(code))
|
|
89
125
|
tagSimpleNumber(result)
|
|
90
126
|
}
|
|
91
127
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
128
|
+
/**
|
|
129
|
+
* Creates a character from the given Unicode scalar value.
|
|
130
|
+
* Throws an exception if the Unicode scalar value is invalid.
|
|
131
|
+
*
|
|
132
|
+
* @param usv: The Unicode scalar value
|
|
133
|
+
* @returns The character for the given Unicode scalar value
|
|
134
|
+
*
|
|
135
|
+
* @since 0.3.0
|
|
136
|
+
*/
|
|
95
137
|
@disableGC
|
|
96
|
-
let fromCode = (
|
|
138
|
+
export let rec fromCode = (usv: Number) => {
|
|
97
139
|
// Algorithm from https://encoding.spec.whatwg.org/#utf-8-encoder
|
|
98
140
|
|
|
99
141
|
let (+) = WasmI32.add
|
|
@@ -107,23 +149,23 @@ let fromCode = (code: Number) => {
|
|
|
107
149
|
let (&) = WasmI32.and
|
|
108
150
|
let (|) = WasmI32.or
|
|
109
151
|
|
|
110
|
-
let
|
|
111
|
-
if ((
|
|
152
|
+
let usv = WasmI32.fromGrain(usv)
|
|
153
|
+
if ((usv & 1n) == 0n) {
|
|
112
154
|
throw InvalidArgument("Invalid character code")
|
|
113
155
|
}
|
|
114
156
|
|
|
115
|
-
let
|
|
116
|
-
if (
|
|
157
|
+
let usv = usv >>> 1n
|
|
158
|
+
let result = if (usv < 0x80n) {
|
|
117
159
|
let char = allocateChar()
|
|
118
|
-
WasmI32.store8(char,
|
|
160
|
+
WasmI32.store8(char, usv, 4n)
|
|
119
161
|
WasmI32.toGrain(char): Char
|
|
120
162
|
} else {
|
|
121
163
|
let mut count = 0n
|
|
122
164
|
let mut offset = 0n
|
|
123
|
-
if (
|
|
165
|
+
if (usv <= 0x07FFn) {
|
|
124
166
|
count = 1n
|
|
125
167
|
offset = 0xC0n
|
|
126
|
-
} else if (
|
|
168
|
+
} else if (usv <= 0xFFFFn) {
|
|
127
169
|
count = 2n
|
|
128
170
|
offset = 0xE0n
|
|
129
171
|
} else {
|
|
@@ -131,27 +173,38 @@ let fromCode = (code: Number) => {
|
|
|
131
173
|
offset = 0xF0n
|
|
132
174
|
}
|
|
133
175
|
let char = allocateChar()
|
|
134
|
-
WasmI32.store8(char, (
|
|
176
|
+
WasmI32.store8(char, (usv >>> 6n * count) + offset, 4n)
|
|
135
177
|
|
|
136
178
|
let mut n = 0n
|
|
137
179
|
while (count > 0n) {
|
|
138
180
|
n += 1n
|
|
139
|
-
let temp =
|
|
140
|
-
WasmI32.store8(char + n, 0x80n |
|
|
181
|
+
let temp = usv >>> 6n * (count - 1n)
|
|
182
|
+
WasmI32.store8(char + n, 0x80n | temp & 0x3Fn, 4n)
|
|
141
183
|
count -= 1n
|
|
142
184
|
}
|
|
143
185
|
|
|
144
186
|
WasmI32.toGrain(char): Char
|
|
145
187
|
}
|
|
188
|
+
|
|
189
|
+
// We've asserted that the original `code` was a stack allocated number so
|
|
190
|
+
// no need to decRef it
|
|
191
|
+
Memory.decRef(WasmI32.fromGrain(fromCode))
|
|
192
|
+
result
|
|
146
193
|
}
|
|
147
194
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
195
|
+
/**
|
|
196
|
+
* Returns the next valid character by Unicode scalar value.
|
|
197
|
+
* Throws if the input character is the max valid Unicode scalar value.
|
|
198
|
+
*
|
|
199
|
+
* @param char: The character
|
|
200
|
+
* @returns The next valid character by Unicode scalar value
|
|
201
|
+
*
|
|
202
|
+
* @since 0.3.0
|
|
203
|
+
*/
|
|
204
|
+
export let succ = char => {
|
|
205
|
+
let codePoint = code(char)
|
|
153
206
|
if (codePoint == max) {
|
|
154
|
-
fail "no valid Unicode
|
|
207
|
+
fail "no valid Unicode scalar value past U+10FFF"
|
|
155
208
|
} else if (codePoint == 0xD7FF) {
|
|
156
209
|
fromCode(0xE000)
|
|
157
210
|
} else {
|
|
@@ -159,13 +212,19 @@ let succ = (c) => {
|
|
|
159
212
|
}
|
|
160
213
|
}
|
|
161
214
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Returns the previous valid character by Unicode scalar value.
|
|
217
|
+
* Throws if the input character is the min valid Unicode scalar value.
|
|
218
|
+
*
|
|
219
|
+
* @param char: The character
|
|
220
|
+
* @returns The previous valid character by Unicode scalar value
|
|
221
|
+
*
|
|
222
|
+
* @since 0.3.0
|
|
223
|
+
*/
|
|
224
|
+
export let pred = char => {
|
|
225
|
+
let codePoint = code(char)
|
|
167
226
|
if (codePoint == min) {
|
|
168
|
-
fail "no valid Unicode
|
|
227
|
+
fail "no valid Unicode scalar value below U+0000"
|
|
169
228
|
} else if (codePoint == 0xE000) {
|
|
170
229
|
fromCode(0xD7FF)
|
|
171
230
|
} else {
|
|
@@ -173,17 +232,22 @@ let pred = (c) => {
|
|
|
173
232
|
}
|
|
174
233
|
}
|
|
175
234
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Converts the given character to a string.
|
|
237
|
+
*
|
|
238
|
+
* @param char: The character to convert
|
|
239
|
+
* @returns A string containing the given character
|
|
240
|
+
*
|
|
241
|
+
* @since 0.3.0
|
|
242
|
+
*/
|
|
179
243
|
@disableGC
|
|
180
|
-
export let rec toString = (
|
|
244
|
+
export let rec toString = (char: Char) => {
|
|
181
245
|
let (+) = WasmI32.add
|
|
182
246
|
let (&) = WasmI32.and
|
|
183
247
|
let (==) = WasmI32.eq
|
|
184
248
|
|
|
185
|
-
let
|
|
186
|
-
let byte = WasmI32.load8U(
|
|
249
|
+
let char = WasmI32.fromGrain(char)
|
|
250
|
+
let byte = WasmI32.load8U(char, 4n)
|
|
187
251
|
let n = if ((byte & 0x80n) == 0x00n) {
|
|
188
252
|
1n
|
|
189
253
|
} else if ((byte & 0xF0n) == 0xF0n) {
|
|
@@ -194,9 +258,9 @@ export let rec toString = (c: Char) => {
|
|
|
194
258
|
2n
|
|
195
259
|
}
|
|
196
260
|
let str = allocateString(n)
|
|
197
|
-
Memory.copy(str + 8n,
|
|
261
|
+
Memory.copy(str + 8n, char + 4n, n)
|
|
198
262
|
let ret = WasmI32.toGrain(str): String
|
|
199
|
-
Memory.decRef(WasmI32.fromGrain(
|
|
263
|
+
Memory.decRef(WasmI32.fromGrain(char))
|
|
200
264
|
Memory.decRef(WasmI32.fromGrain(toString))
|
|
201
265
|
ret
|
|
202
266
|
}
|
package/char.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Char
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Utilities for working with the Char type.
|
|
6
|
+
|
|
7
|
+
The Char type represents a single [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value).
|
|
8
|
+
|
|
9
|
+
<details disabled>
|
|
10
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
11
|
+
No other changes yet.
|
|
12
|
+
</details>
|
|
13
|
+
|
|
14
|
+
```grain
|
|
15
|
+
import Char from "char"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Values
|
|
19
|
+
|
|
20
|
+
Functions and constants included in the Char module.
|
|
21
|
+
|
|
22
|
+
### Char.**min**
|
|
23
|
+
|
|
24
|
+
<details disabled>
|
|
25
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
26
|
+
No other changes yet.
|
|
27
|
+
</details>
|
|
28
|
+
|
|
29
|
+
```grain
|
|
30
|
+
min : Number
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The minimum valid Unicode scalar value.
|
|
34
|
+
|
|
35
|
+
### Char.**max**
|
|
36
|
+
|
|
37
|
+
<details disabled>
|
|
38
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
39
|
+
No other changes yet.
|
|
40
|
+
</details>
|
|
41
|
+
|
|
42
|
+
```grain
|
|
43
|
+
max : Number
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The maximum valid Unicode scalar value.
|
|
47
|
+
|
|
48
|
+
### Char.**isValid**
|
|
49
|
+
|
|
50
|
+
<details disabled>
|
|
51
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
52
|
+
No other changes yet.
|
|
53
|
+
</details>
|
|
54
|
+
|
|
55
|
+
```grain
|
|
56
|
+
isValid : Number -> Bool
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Determines whether the given character code is a valid Unicode scalar value.
|
|
60
|
+
|
|
61
|
+
Parameters:
|
|
62
|
+
|
|
63
|
+
|param|type|description|
|
|
64
|
+
|-----|----|-----------|
|
|
65
|
+
|`charCode`|`Number`|The number to check|
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
|
|
69
|
+
|type|description|
|
|
70
|
+
|----|-----------|
|
|
71
|
+
|`Bool`|`true` if the number refers to a valid Unicode scalar value or `false` otherwise|
|
|
72
|
+
|
|
73
|
+
### Char.**code**
|
|
74
|
+
|
|
75
|
+
<details disabled>
|
|
76
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
77
|
+
No other changes yet.
|
|
78
|
+
</details>
|
|
79
|
+
|
|
80
|
+
```grain
|
|
81
|
+
code : Char -> Number
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Determines the Unicode scalar value for a character.
|
|
85
|
+
|
|
86
|
+
Parameters:
|
|
87
|
+
|
|
88
|
+
|param|type|description|
|
|
89
|
+
|-----|----|-----------|
|
|
90
|
+
|`char`|`Char`|The character|
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
|
|
94
|
+
|type|description|
|
|
95
|
+
|----|-----------|
|
|
96
|
+
|`Number`|The Unicode scalar value for the given character|
|
|
97
|
+
|
|
98
|
+
### Char.**fromCode**
|
|
99
|
+
|
|
100
|
+
<details disabled>
|
|
101
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
102
|
+
No other changes yet.
|
|
103
|
+
</details>
|
|
104
|
+
|
|
105
|
+
```grain
|
|
106
|
+
fromCode : Number -> Char
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Creates a character from the given Unicode scalar value.
|
|
110
|
+
Throws an exception if the Unicode scalar value is invalid.
|
|
111
|
+
|
|
112
|
+
Parameters:
|
|
113
|
+
|
|
114
|
+
|param|type|description|
|
|
115
|
+
|-----|----|-----------|
|
|
116
|
+
|`usv`|`Number`|The Unicode scalar value|
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
|
|
120
|
+
|type|description|
|
|
121
|
+
|----|-----------|
|
|
122
|
+
|`Char`|The character for the given Unicode scalar value|
|
|
123
|
+
|
|
124
|
+
### Char.**succ**
|
|
125
|
+
|
|
126
|
+
<details disabled>
|
|
127
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
128
|
+
No other changes yet.
|
|
129
|
+
</details>
|
|
130
|
+
|
|
131
|
+
```grain
|
|
132
|
+
succ : Char -> Char
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Returns the next valid character by Unicode scalar value.
|
|
136
|
+
Throws if the input character is the max valid Unicode scalar value.
|
|
137
|
+
|
|
138
|
+
Parameters:
|
|
139
|
+
|
|
140
|
+
|param|type|description|
|
|
141
|
+
|-----|----|-----------|
|
|
142
|
+
|`char`|`Char`|The character|
|
|
143
|
+
|
|
144
|
+
Returns:
|
|
145
|
+
|
|
146
|
+
|type|description|
|
|
147
|
+
|----|-----------|
|
|
148
|
+
|`Char`|The next valid character by Unicode scalar value|
|
|
149
|
+
|
|
150
|
+
### Char.**pred**
|
|
151
|
+
|
|
152
|
+
<details disabled>
|
|
153
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
154
|
+
No other changes yet.
|
|
155
|
+
</details>
|
|
156
|
+
|
|
157
|
+
```grain
|
|
158
|
+
pred : Char -> Char
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Returns the previous valid character by Unicode scalar value.
|
|
162
|
+
Throws if the input character is the min valid Unicode scalar value.
|
|
163
|
+
|
|
164
|
+
Parameters:
|
|
165
|
+
|
|
166
|
+
|param|type|description|
|
|
167
|
+
|-----|----|-----------|
|
|
168
|
+
|`char`|`Char`|The character|
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
|
|
172
|
+
|type|description|
|
|
173
|
+
|----|-----------|
|
|
174
|
+
|`Char`|The previous valid character by Unicode scalar value|
|
|
175
|
+
|
|
176
|
+
### Char.**toString**
|
|
177
|
+
|
|
178
|
+
<details disabled>
|
|
179
|
+
<summary tabindex="-1">Added in <code>0.3.0</code></summary>
|
|
180
|
+
No other changes yet.
|
|
181
|
+
</details>
|
|
182
|
+
|
|
183
|
+
```grain
|
|
184
|
+
toString : Char -> String
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Converts the given character to a string.
|
|
188
|
+
|
|
189
|
+
Parameters:
|
|
190
|
+
|
|
191
|
+
|param|type|description|
|
|
192
|
+
|-----|----|-----------|
|
|
193
|
+
|`char`|`Char`|The character to convert|
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
|
|
197
|
+
|type|description|
|
|
198
|
+
|----|-----------|
|
|
199
|
+
|`String`|A string containing the given character|
|
|
200
|
+
|
package/hash.gr
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
/* grainc-flags --no-gc */
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @module Hash: Utilities for hashing any value.
|
|
5
|
+
* @example import Hash from "hash"
|
|
6
|
+
*
|
|
7
|
+
* @since v0.1.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
3
10
|
/**
|
|
4
11
|
This module implements MurmurHash3 for Grain data types.
|
|
5
12
|
https://en.wikipedia.org/wiki/MurmurHash
|
|
@@ -18,7 +25,7 @@ import WasmI32, {
|
|
|
18
25
|
eq as (==),
|
|
19
26
|
ne as (!=),
|
|
20
27
|
gtU as (>),
|
|
21
|
-
ltU as (<)
|
|
28
|
+
ltU as (<),
|
|
22
29
|
} from "runtime/unsafe/wasmi32"
|
|
23
30
|
import Tags from "runtime/unsafe/tags"
|
|
24
31
|
import Memory from "runtime/unsafe/memory"
|
|
@@ -48,17 +55,17 @@ let n = 0xe6546b64n
|
|
|
48
55
|
|
|
49
56
|
let mut h = seed
|
|
50
57
|
|
|
51
|
-
let hash32 =
|
|
58
|
+
let hash32 = k => {
|
|
52
59
|
let mut k = k * c1
|
|
53
60
|
k = WasmI32.rotl(k, r1)
|
|
54
61
|
k *= c2
|
|
55
62
|
|
|
56
63
|
h = h ^ k
|
|
57
64
|
h = WasmI32.rotl(h, r2)
|
|
58
|
-
h =
|
|
65
|
+
h = h * m + n
|
|
59
66
|
}
|
|
60
67
|
|
|
61
|
-
let hashRemaining =
|
|
68
|
+
let hashRemaining = r => {
|
|
62
69
|
// Note: wasm is little-endian so no swap is necessary
|
|
63
70
|
|
|
64
71
|
let mut r = r * c1
|
|
@@ -68,14 +75,14 @@ let hashRemaining = (r) => {
|
|
|
68
75
|
h = h ^ r
|
|
69
76
|
}
|
|
70
77
|
|
|
71
|
-
let finalize =
|
|
78
|
+
let finalize = len => {
|
|
72
79
|
h = h ^ len
|
|
73
80
|
|
|
74
|
-
h = h ^
|
|
81
|
+
h = h ^ h >>> 16n
|
|
75
82
|
h *= 0x85ebca6bn
|
|
76
|
-
h = h ^
|
|
83
|
+
h = h ^ h >>> 13n
|
|
77
84
|
h *= 0xc2b2ae35n
|
|
78
|
-
h = h ^
|
|
85
|
+
h = h ^ h >>> 16n
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
let rec hashOne = (val, depth) => {
|
|
@@ -83,10 +90,14 @@ let rec hashOne = (val, depth) => {
|
|
|
83
90
|
void
|
|
84
91
|
} else if ((val & Tags._GRAIN_NUMBER_TAG_MASK) != 0n) {
|
|
85
92
|
hash32(val)
|
|
86
|
-
} else if (
|
|
93
|
+
} else if (
|
|
94
|
+
(val & Tags._GRAIN_GENERIC_TAG_MASK) == Tags._GRAIN_GENERIC_HEAP_TAG_TYPE
|
|
95
|
+
) {
|
|
87
96
|
let heapPtr = val
|
|
88
97
|
match (WasmI32.load(heapPtr, 0n)) {
|
|
89
|
-
t when
|
|
98
|
+
t when (
|
|
99
|
+
t == Tags._GRAIN_STRING_HEAP_TAG || t == Tags._GRAIN_BYTES_HEAP_TAG
|
|
100
|
+
) => {
|
|
90
101
|
let length = WasmI32.load(heapPtr, 4n)
|
|
91
102
|
let extra = length % 4n
|
|
92
103
|
let l = length - extra
|
|
@@ -191,12 +202,12 @@ let rec hashOne = (val, depth) => {
|
|
|
191
202
|
},
|
|
192
203
|
_ => {
|
|
193
204
|
hash32(heapPtr)
|
|
194
|
-
}
|
|
205
|
+
},
|
|
195
206
|
}
|
|
196
207
|
},
|
|
197
208
|
_ => {
|
|
198
209
|
hash32(heapPtr)
|
|
199
|
-
}
|
|
210
|
+
},
|
|
200
211
|
}
|
|
201
212
|
} else if (val == WasmI32.fromGrain(true)) {
|
|
202
213
|
hash32(val)
|
|
@@ -208,14 +219,30 @@ let rec hashOne = (val, depth) => {
|
|
|
208
219
|
hash32(val)
|
|
209
220
|
}
|
|
210
221
|
}
|
|
222
|
+
/**
|
|
223
|
+
* @section Values: Functions for hashing.
|
|
224
|
+
*/
|
|
211
225
|
|
|
212
|
-
|
|
226
|
+
/**
|
|
227
|
+
* A generic hash function that produces an integer from any value. If `a == b` then `Hash.hash(a) == Hash.hash(b)`.
|
|
228
|
+
*
|
|
229
|
+
* @param anything: The value to hash
|
|
230
|
+
* @returns A hash for the given value
|
|
231
|
+
*
|
|
232
|
+
* @since v0.1.0
|
|
233
|
+
*/
|
|
234
|
+
export let rec hash = anything => {
|
|
213
235
|
h = seed
|
|
214
236
|
|
|
215
|
-
hashOne(WasmI32.fromGrain(
|
|
237
|
+
hashOne(WasmI32.fromGrain(anything), 0n)
|
|
216
238
|
finalize(0n)
|
|
217
239
|
|
|
218
240
|
// Tag the number on the way out.
|
|
219
241
|
// Since Grain has proper modulus, negative numbers are okay.
|
|
220
|
-
tagSimpleNumber(h)
|
|
242
|
+
let result = tagSimpleNumber(h)
|
|
243
|
+
|
|
244
|
+
Memory.decRef(WasmI32.fromGrain(hash))
|
|
245
|
+
Memory.decRef(WasmI32.fromGrain(anything))
|
|
246
|
+
|
|
247
|
+
result
|
|
221
248
|
}
|
package/hash.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hash
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Utilities for hashing any value.
|
|
6
|
+
|
|
7
|
+
<details disabled>
|
|
8
|
+
<summary tabindex="-1">Added in <code>0.1.0</code></summary>
|
|
9
|
+
No other changes yet.
|
|
10
|
+
</details>
|
|
11
|
+
|
|
12
|
+
```grain
|
|
13
|
+
import Hash from "hash"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Values
|
|
17
|
+
|
|
18
|
+
Functions for hashing.
|
|
19
|
+
|
|
20
|
+
### Hash.**hash**
|
|
21
|
+
|
|
22
|
+
<details disabled>
|
|
23
|
+
<summary tabindex="-1">Added in <code>0.1.0</code></summary>
|
|
24
|
+
No other changes yet.
|
|
25
|
+
</details>
|
|
26
|
+
|
|
27
|
+
```grain
|
|
28
|
+
hash : a -> Number
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
A generic hash function that produces an integer from any value. If `a == b` then `Hash.hash(a) == Hash.hash(b)`.
|
|
32
|
+
|
|
33
|
+
Parameters:
|
|
34
|
+
|
|
35
|
+
|param|type|description|
|
|
36
|
+
|-----|----|-----------|
|
|
37
|
+
|`anything`|`a`|The value to hash|
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
|
|
41
|
+
|type|description|
|
|
42
|
+
|----|-----------|
|
|
43
|
+
|`Number`|A hash for the given value|
|
|
44
|
+
|