turbouuid 0.0.4 → 0.0.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/README.md +110 -2
- package/assets/sshot.png +0 -0
- package/build +1 -0
- package/index.html +78 -0
- package/index.js +5 -1
- package/package.json +5 -2
- package/src/uuid.wat +510 -0
- package/test.html +40 -0
- package/uuid.wasm +0 -0
package/README.md
CHANGED
|
@@ -15,16 +15,124 @@ Benchmarks ran on 1,000,000 iterations show a massive performance gain:
|
|
|
15
15
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
18
|
-
The library attaches directly to `window.
|
|
18
|
+
The library attaches directly to `window.randomUUID` for browser environments.
|
|
19
19
|
|
|
20
20
|
```javascript
|
|
21
21
|
require('turbouuid');
|
|
22
22
|
|
|
23
23
|
// Returns a standard v4-like UUID string
|
|
24
|
-
console.log(
|
|
24
|
+
console.log(window.randomUUID());
|
|
25
25
|
// Output example: f1235820-f090-3fce-a0d6-af6e26c6a0d6
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
+
## SIMD-Accelerated In-Memory Storage
|
|
29
|
+
|
|
30
|
+
`turbouuid` now includes a high-performance, WebAssembly-based storage engine for managing UUIDs in memory. It leverages **128-bit SIMD** instructions to perform lightning-fast lookups and storage operations.
|
|
31
|
+
|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
### Key Features
|
|
35
|
+
|
|
36
|
+
* **⚡ SIMD-Powered Search**: Uses `v128` vector instructions to scan memory in parallel, offering incredibly fast `indexOf` and `has` checks.
|
|
37
|
+
* **🔗 Key-Ref Association**: Map each UUID to a 32-bit integer (e.g., a database ID or object reference) for efficient lookups (`uuid -> id`).
|
|
38
|
+
* **🧠 Zero-GC Overhead**: Operates on shared memory pages, bypassing the JavaScript garbage collector for stable, high-throughput performance.
|
|
39
|
+
|
|
40
|
+
### API Reference
|
|
41
|
+
|
|
42
|
+
To use the storage engine, initialize it via `turboUUID.base()`:
|
|
43
|
+
|
|
44
|
+
```javascript
|
|
45
|
+
const store = await turboUUID.base();
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
#### `store.randomUUID(value: number): string`
|
|
49
|
+
Generates a new UUID, stores it in memory, and associates it with the given `value`. Returns the generated UUID string.
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
const uuid = store.randomUUID(12345);
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
#### `store.uuidAt(index: number): string`
|
|
58
|
+
Returns the UUID string stored at the specific memory index.
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
// Get the first UUID stored
|
|
62
|
+
const firstUUID = store.uuidAt(0);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
#### `store.indexOf(uuid: string): number`
|
|
68
|
+
Returns the memory index of the given UUID. Returns `-1` if not found.
|
|
69
|
+
*Powered by SIMD for checking multiple bytes per cycle.*
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
const index = store.indexOf("f1235820-f090-3fce-a0d6-af6e26c6a0d6");
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
#### `store.has(uuid: string): boolean`
|
|
78
|
+
Checks if the UUID exists in the storage. Returns `1` (true) or `0` (false).
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
if (store.has(uuid)) {
|
|
82
|
+
console.log("UUID Exists!");
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
#### `store.valueOf(uuid: string): number`
|
|
89
|
+
Returns the integer value associated with the given UUID. Returns `0` if the UUID is not found.
|
|
90
|
+
|
|
91
|
+
```javascript
|
|
92
|
+
const userId = store.valueOf(uuid);
|
|
93
|
+
console.log("User ID:", userId); // 12345
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
#### `store.setValue(uuid: string, value: number): void`
|
|
99
|
+
Updates or sets the integer value associated with an existing UUID. If the UUID doesn't exist, it creates a new entry.
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
// Update the ID associated with this UUID
|
|
103
|
+
store.setValue(uuid, 67890);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
#### `store.remove(uuid: string): void`
|
|
109
|
+
Removes the UUID and its associated value from the storage.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
store.remove(uuid);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
#### `store.count(): number`
|
|
118
|
+
Returns the total number of UUIDs currently stored.
|
|
119
|
+
|
|
120
|
+
```javascript
|
|
121
|
+
console.log("Total UUIDs:", store.count());
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
#### `store.forEach(callback: (uuid, value, index) => void): void`
|
|
127
|
+
Iterates over all stored UUIDs.
|
|
128
|
+
*Note: The callback receives the UUID string, the associated value, and the index.*
|
|
129
|
+
|
|
130
|
+
```javascript
|
|
131
|
+
store.forEach((uuid, value, index) => {
|
|
132
|
+
console.log(`#${index}: ${uuid} -> ${value}`);
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
28
136
|
## How It Works
|
|
29
137
|
|
|
30
138
|
Instead of re-allocating memory for every generation, `turbouuid` reuses a set of TypedArrays (`Float64Array`, `Uint32Array`, `Uint16Array`, `BigUint64Array`) sharing the same buffer. This minimizes garbage collection overhead and maximizes throughput.
|
package/assets/sshot.png
ADDED
|
Binary file
|
package/build
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cd src && wat4wasm --input=uuid.wat --output=../uuid.wasm --untouched-window --wat2wasm=wat2wasm --enable-threads --keep-unused-functions --enable-multi-memory
|
package/index.html
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<script type="module">
|
|
6
|
+
import "./index.js"
|
|
7
|
+
|
|
8
|
+
turboUUID.base().then(base => {
|
|
9
|
+
|
|
10
|
+
const uuid = turboUUID();
|
|
11
|
+
const value = 2412; //integer
|
|
12
|
+
|
|
13
|
+
const setValue = base.setValue(uuid, value);
|
|
14
|
+
const indexOf = base.indexOf(uuid);
|
|
15
|
+
const uuidAt = base.uuidAt(0);
|
|
16
|
+
const has = !!base.has(uuid);
|
|
17
|
+
const count = base.count();
|
|
18
|
+
const valueOf = base.valueOf(uuid);
|
|
19
|
+
const randomUUID = base.randomUUID(value);
|
|
20
|
+
|
|
21
|
+
console.warn(base);
|
|
22
|
+
console.log(`const uuid = \x1b[32m"${uuid}"\x1b[0m`, ";");
|
|
23
|
+
console.log(`const value =`, value, ";");
|
|
24
|
+
console.group(`base calls:`);
|
|
25
|
+
console.log(`base.setValue(\x1b[34m${uuid}, ${value}\x1b[0m)`.padEnd(70).concat("-->"), setValue);
|
|
26
|
+
console.log(`base.indexOf(\x1b[35m${uuid}\x1b[0m)`.padEnd(70).concat("-->"), indexOf);
|
|
27
|
+
console.log(`base.uuidAt(\x1b[36m${indexOf}\x1b[0m)`.padEnd(70).concat("-->"), uuidAt);
|
|
28
|
+
console.log(`base.has(\x1b[33m${uuid}\x1b[0m)`.padEnd(70).concat("-->"), has);
|
|
29
|
+
console.log(`base.count(\x1b[31m\x1b[0m)`.padEnd(70).concat("-->"), count);
|
|
30
|
+
console.log(`base.valueOf(\x1b[31m${uuid}\x1b[0m)`.padEnd(70).concat("-->"), valueOf);
|
|
31
|
+
console.log(`base.randomUUID(\x1b[33m${value}\x1b[0m)`.padEnd(70).concat("-->"), randomUUID);
|
|
32
|
+
console.groupEnd(`base calls:`);
|
|
33
|
+
|
|
34
|
+
{
|
|
35
|
+
const map = new Map();
|
|
36
|
+
self.array = new Array();
|
|
37
|
+
let count, uuid, value, t0, t1, t2, dtm, dtb;
|
|
38
|
+
|
|
39
|
+
count = 4e3;
|
|
40
|
+
while (count--) {
|
|
41
|
+
uuid = turboUUID();
|
|
42
|
+
value = Math.floor(Math.random() * 1e5);
|
|
43
|
+
|
|
44
|
+
if (Math.random() > 0.998) {
|
|
45
|
+
array.push(uuid);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
map.set(uuid, value);
|
|
49
|
+
base.setValue(uuid, value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
console.log("ready")
|
|
53
|
+
new BroadcastChannel("uuid").onmessage = e => {
|
|
54
|
+
const uuid = e.data;
|
|
55
|
+
|
|
56
|
+
t0 = performance.mark("map_start");
|
|
57
|
+
map.get(uuid);
|
|
58
|
+
dtm = performance.measure("map", "map_start");
|
|
59
|
+
performance.clearMarks();
|
|
60
|
+
performance.clearMeasures();
|
|
61
|
+
performance.clearResourceTimings();
|
|
62
|
+
|
|
63
|
+
t0 = performance.mark("base_start");
|
|
64
|
+
base.valueOf(uuid);
|
|
65
|
+
dtb = performance.measure("base", "base_start");
|
|
66
|
+
performance.clearMarks();
|
|
67
|
+
performance.clearMeasures();
|
|
68
|
+
performance.clearResourceTimings();
|
|
69
|
+
|
|
70
|
+
console.warn({ dtm, dtb })
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
})
|
|
75
|
+
</script>
|
|
76
|
+
</head>
|
|
77
|
+
|
|
78
|
+
</html>
|
package/index.js
CHANGED
|
@@ -30,4 +30,8 @@ turboUUID.benchmark = (count = 1e6) => {
|
|
|
30
30
|
dt = performance.now() - t0;
|
|
31
31
|
console.log("window.turboUUID:\t", dt, "ms sample:", window.turboUUID());
|
|
32
32
|
//window.turboUUID: 404.78500032424927 ms sample: 853dcff4-2729-3fd6-fe00-36efc5920fe0
|
|
33
|
-
};
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
turboUUID.base = async () => {
|
|
36
|
+
return WebAssembly.instantiateStreaming(fetch("uuid.wasm"), self).then(i => console.log(i) || i.instance.exports);
|
|
37
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbouuid",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"description": "Fast uuid generator / an alternative for crypto.randomUUID",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"uuid"
|
|
@@ -19,5 +19,8 @@
|
|
|
19
19
|
"main": "index.js",
|
|
20
20
|
"scripts": {
|
|
21
21
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"wat4wasm": "^1.1.4"
|
|
22
25
|
}
|
|
23
|
-
}
|
|
26
|
+
}
|
package/src/uuid.wat
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
(module
|
|
2
|
+
(memory $base 1 1 shared)
|
|
3
|
+
(memory $i8a 5000 65535 shared)
|
|
4
|
+
(memory $i8b 5000 65535 shared)
|
|
5
|
+
(memory $i16 10000 65535 shared)
|
|
6
|
+
(memory $i32 20000 65535 shared)
|
|
7
|
+
(memory $i64 40000 65535 shared)
|
|
8
|
+
(memory $val 20000 65535 shared)
|
|
9
|
+
|
|
10
|
+
(export "uuidAt" (func $uuidAt))
|
|
11
|
+
(export "valueOf" (func $valueOf))
|
|
12
|
+
(export "indexOf" (func $indexOf))
|
|
13
|
+
(export "setValue" (func $setValue))
|
|
14
|
+
(export "has" (func $has))
|
|
15
|
+
(export "count" (func $count))
|
|
16
|
+
(export "forEach" (func $forEach))
|
|
17
|
+
(export "remove" (func $remove))
|
|
18
|
+
(export "randomUUID" (func $randomUUID))
|
|
19
|
+
|
|
20
|
+
(global $OFFSET_UUID_COUNT i32 (i32.const 36))
|
|
21
|
+
(global $OFFSET_BLOCK_COUNT i32 (i32.const 44))
|
|
22
|
+
(global $OFFSET_SEARCH_VALUE i32 (i32.const 48))
|
|
23
|
+
(global $OFFSET_RANDOM_UUID i32 (i32.const 64))
|
|
24
|
+
|
|
25
|
+
(global $ARGUMENTS_REGEXP_CLEAR_STR mut ext)
|
|
26
|
+
(global $ARGUMENTS_REGEXP_MATCH_I8A mut ext)
|
|
27
|
+
(global $ARGUMENTS_REGEXP_MATCH_I8B mut ext)
|
|
28
|
+
(global $ARGUMENTS_REGEXP_MATCH_I16 mut ext)
|
|
29
|
+
(global $ARGUMENTS_REGEXP_MATCH_I32 mut ext)
|
|
30
|
+
(global $ARGUMENTS_REGEXP_MATCH_I64 mut ext)
|
|
31
|
+
(global $ARGUMENTS_REGEXP_TO_STRING mut ext)
|
|
32
|
+
|
|
33
|
+
(func $forEach
|
|
34
|
+
(param $callback externref)
|
|
35
|
+
(param $thisArg externref)
|
|
36
|
+
(local $iterator v128)
|
|
37
|
+
(local $iterated v128)
|
|
38
|
+
|
|
39
|
+
(local.set $iterator (v128.const i32x4 -1 4 1 0))
|
|
40
|
+
(local.set $iterated (i32x4.replace_lane 0 (local.get $iterated) (call $count)))
|
|
41
|
+
|
|
42
|
+
(loop $iteration
|
|
43
|
+
(if (i32x4.extract_lane 0 (local.get $iterated))
|
|
44
|
+
(then
|
|
45
|
+
(reflect $apply<ext.ext.ext>
|
|
46
|
+
(local.get $callback)
|
|
47
|
+
(local.get $thisArg)
|
|
48
|
+
(array $of<ext.i32.i32>ext
|
|
49
|
+
(call $uuidAt (i32x4.extract_lane 2 (local.get $iterated)))
|
|
50
|
+
(i32.load $val (i32x4.extract_lane 1 (local.get $iterated)))
|
|
51
|
+
(i32x4.extract_lane 2 (local.get $iterated))
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
(local.set $iterated
|
|
56
|
+
(i32x4.add (local.get $iterated) (local.get $iterator))
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
(br $iteration)
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
(func $store
|
|
66
|
+
(param $index i32)
|
|
67
|
+
(param $value i32)
|
|
68
|
+
|
|
69
|
+
(i32.store $val (i32.mul (i32.const 4) (local.get $index)) (local.get $value))
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
(func $load
|
|
73
|
+
(param $index i32)
|
|
74
|
+
(result i32)
|
|
75
|
+
(i32.load $val (i32.mul (i32.const 4) (local.get $index)))
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
(func $remove
|
|
79
|
+
(param $string ext)
|
|
80
|
+
(local $index i32)
|
|
81
|
+
|
|
82
|
+
(if (i32.eq
|
|
83
|
+
(i32.const -1)
|
|
84
|
+
(local.tee $index
|
|
85
|
+
(call $indexOf (local.get $string))
|
|
86
|
+
)
|
|
87
|
+
)
|
|
88
|
+
(then return)
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
(call $set_index_vector (local.get $index) (v128.const i64x2 0 0))
|
|
92
|
+
(call $store (local.get $index) (i32.const 0))
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
(func $setValue
|
|
96
|
+
(param $string ext)
|
|
97
|
+
(param $number i32)
|
|
98
|
+
(local $index i32)
|
|
99
|
+
(local $vector v128)
|
|
100
|
+
|
|
101
|
+
(local.set $vector (call $parse_vector (local.get $string)))
|
|
102
|
+
(local.set $index (call $get_vector_index (local.get $vector)))
|
|
103
|
+
|
|
104
|
+
(if (i32.eq (i32.const -1) (local.get $index))
|
|
105
|
+
(then
|
|
106
|
+
(call $set_index_vector
|
|
107
|
+
(local.tee $index (call $next_index))
|
|
108
|
+
(local.get $vector)
|
|
109
|
+
)
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
(call $store
|
|
114
|
+
(local.get $index)
|
|
115
|
+
(local.get $number)
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
(func $randomUUID
|
|
120
|
+
(param $number i32)
|
|
121
|
+
(result externref)
|
|
122
|
+
(call $uuidAt (call $nextIndex (local.get $number)))
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
(func $nextIndex
|
|
126
|
+
(param $number i32)
|
|
127
|
+
(result i32)
|
|
128
|
+
(local $index i32)
|
|
129
|
+
|
|
130
|
+
(call $store
|
|
131
|
+
(local.tee $index (call $new_random_index))
|
|
132
|
+
(local.get $number)
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
(local.get $index)
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
(func $has
|
|
139
|
+
(param $string ext)
|
|
140
|
+
(result i32)
|
|
141
|
+
|
|
142
|
+
(i32.ne (i32.const -1) (call $indexOf (local.get $string)))
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
(func $valueOf
|
|
146
|
+
(param $string ext)
|
|
147
|
+
(result i32)
|
|
148
|
+
(local $index i32)
|
|
149
|
+
|
|
150
|
+
(if (result i32)
|
|
151
|
+
(i32.ne
|
|
152
|
+
(i32.const -1)
|
|
153
|
+
(local.tee $index
|
|
154
|
+
(call $indexOf (local.get $string))
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
(then (call $load (local.get $index)))
|
|
158
|
+
(else (i32.const 0))
|
|
159
|
+
)
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
(func $count
|
|
163
|
+
(result i32)
|
|
164
|
+
(i32.load (global.get $OFFSET_UUID_COUNT))
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
(func $indexOf
|
|
168
|
+
(param $string externref)
|
|
169
|
+
(result i32)
|
|
170
|
+
(call $get_vector_index (call $parse_vector (local.get $string)))
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
(func $uuidAt
|
|
174
|
+
(param $index i32)
|
|
175
|
+
(result externref)
|
|
176
|
+
(local $offsets v128)
|
|
177
|
+
|
|
178
|
+
(local.set $offsets
|
|
179
|
+
(i32x4.mul
|
|
180
|
+
(v128.const i32x4 1 2 4 8)
|
|
181
|
+
(i32x4.splat (local.get $index))
|
|
182
|
+
)
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
(call $join_array<ext>ext
|
|
186
|
+
(array $of<ext.ext.ext.ext.ext>ext
|
|
187
|
+
(call $to_string<i32.i32>ext (i32.load8_u $i8a (i32x4.extract_lane 0 (local.get $offsets))) (i32.const 2))
|
|
188
|
+
(call $to_string<i32.i32>ext (i32.load8_u $i8b (i32x4.extract_lane 0 (local.get $offsets))) (i32.const 2))
|
|
189
|
+
(call $to_string<i32.i32>ext (i32.load16_u $i16 (i32x4.extract_lane 1 (local.get $offsets))) (i32.const 4))
|
|
190
|
+
(call $to_string<i32.i32>ext (i32.load $i32 (i32x4.extract_lane 2 (local.get $offsets))) (i32.const 8))
|
|
191
|
+
(call $to_string<i32.i64>ext (i64.load $i64 (i32x4.extract_lane 3 (local.get $offsets))) (i32.const 16))
|
|
192
|
+
)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
(func $get_vector_index
|
|
198
|
+
(param $vector v128)
|
|
199
|
+
(result i32)
|
|
200
|
+
|
|
201
|
+
(i32.store8 $base offset=0 (global.get $OFFSET_SEARCH_VALUE) (i8x16.extract_lane_u 0 (local.get $vector)))
|
|
202
|
+
(i32.store8 $base offset=1 (global.get $OFFSET_SEARCH_VALUE) (i8x16.extract_lane_u 1 (local.get $vector)))
|
|
203
|
+
(i32.store16 $base offset=2 (global.get $OFFSET_SEARCH_VALUE) (i16x8.extract_lane_u 1 (local.get $vector)))
|
|
204
|
+
(i32.store $base offset=4 (global.get $OFFSET_SEARCH_VALUE) (i32x4.extract_lane 1 (local.get $vector)))
|
|
205
|
+
(i64.store $base offset=8 (global.get $OFFSET_SEARCH_VALUE) (i64x2.extract_lane 1 (local.get $vector)))
|
|
206
|
+
|
|
207
|
+
(call $find)
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
(func $new_random_index
|
|
211
|
+
(result i32)
|
|
212
|
+
(f64.store $base offset=0 (global.get $OFFSET_RANDOM_UUID) (call $self.Math.random<>f64))
|
|
213
|
+
(f64.store $base offset=8 (global.get $OFFSET_RANDOM_UUID) (call $self.Math.random<>f64))
|
|
214
|
+
(call $new_vector_index (v128.load $base offset=0 (global.get $OFFSET_RANDOM_UUID)))
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
(func $new_vector_index
|
|
218
|
+
(param $vector v128)
|
|
219
|
+
(result i32)
|
|
220
|
+
(local $index i32)
|
|
221
|
+
|
|
222
|
+
(call $set_index_vector
|
|
223
|
+
(local.tee $index (call $next_index))
|
|
224
|
+
(local.get $vector)
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
(local.get $index)
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
(func $set_index_vector
|
|
231
|
+
(param $index i32)
|
|
232
|
+
(param $vector v128)
|
|
233
|
+
(local $offsets v128)
|
|
234
|
+
|
|
235
|
+
(local.set $offsets
|
|
236
|
+
(i32x4.mul
|
|
237
|
+
(v128.const i32x4 1 2 4 8)
|
|
238
|
+
(i32x4.splat (local.get $index))
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
(i32.store8 $i8a (i32x4.extract_lane 0 (local.get $offsets)) (i8x16.extract_lane_u 0 (local.get $vector)))
|
|
243
|
+
(i32.store8 $i8b (i32x4.extract_lane 0 (local.get $offsets)) (i8x16.extract_lane_u 1 (local.get $vector)))
|
|
244
|
+
(i32.store16 $i16 (i32x4.extract_lane 1 (local.get $offsets)) (i16x8.extract_lane_u 1 (local.get $vector)))
|
|
245
|
+
(i32.store $i32 (i32x4.extract_lane 2 (local.get $offsets)) (i32x4.extract_lane 1 (local.get $vector)))
|
|
246
|
+
(i64.store $i64 (i32x4.extract_lane 3 (local.get $offsets)) (i64x2.extract_lane 1 (local.get $vector)))
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
(func $pad_start<ext.i32>ext
|
|
250
|
+
(param $string externref)
|
|
251
|
+
(param $padding i32)
|
|
252
|
+
(result externref)
|
|
253
|
+
|
|
254
|
+
(reflect $apply<ext.ext.ext>ext
|
|
255
|
+
(ref.extern $String:padStart)
|
|
256
|
+
(local.get $string)
|
|
257
|
+
(array $of<i32.i32>ext
|
|
258
|
+
(local.get $padding)
|
|
259
|
+
(i32.const 0)
|
|
260
|
+
)
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
(func $join_array<ext>ext
|
|
265
|
+
(param $array externref)
|
|
266
|
+
(result externref)
|
|
267
|
+
|
|
268
|
+
(reflect $apply<ext.ext.ext>ext
|
|
269
|
+
(ref.extern $Array:join)
|
|
270
|
+
(local.get $array)
|
|
271
|
+
(array $of<ext>ext (string))
|
|
272
|
+
)
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
(func $to_string<i32.i32>ext
|
|
276
|
+
(param $number i32)
|
|
277
|
+
(param $padding i32)
|
|
278
|
+
(result externref)
|
|
279
|
+
|
|
280
|
+
(call $pad_start<ext.i32>ext
|
|
281
|
+
(reflect $apply<ext.i32.ext>ext
|
|
282
|
+
(ref.extern $Number:toString)
|
|
283
|
+
(local.get $number)
|
|
284
|
+
(array $of<i32>ext (i32.const 16))
|
|
285
|
+
)
|
|
286
|
+
(local.get $padding)
|
|
287
|
+
)
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
(func $to_string<i32.i64>ext
|
|
291
|
+
(param $bigint i64)
|
|
292
|
+
(param $padding i32)
|
|
293
|
+
(result externref)
|
|
294
|
+
|
|
295
|
+
(call $pad_start<ext.i32>ext
|
|
296
|
+
(reflect $apply<ext.i64.ext>ext
|
|
297
|
+
(ref.extern $BigInt:toString)
|
|
298
|
+
(local.get $bigint)
|
|
299
|
+
(array $of<i32>ext (i32.const 16))
|
|
300
|
+
)
|
|
301
|
+
(local.get $padding)
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
(main $set_initials
|
|
306
|
+
(global.set $ARGUMENTS_REGEXP_CLEAR_STR (call $regexp_args (text "[^a-f0-9]") (string)))
|
|
307
|
+
(global.set $ARGUMENTS_REGEXP_MATCH_I8A (call $regexp_args (text "(?:[a-f0-9]{0})([a-f0-9]{2})(?:[a-f0-9]{30})") (text "0x$1")))
|
|
308
|
+
(global.set $ARGUMENTS_REGEXP_MATCH_I8B (call $regexp_args (text "(?:[a-f0-9]{2})([a-f0-9]{2})(?:[a-f0-9]{28})") (text "0x$1")))
|
|
309
|
+
(global.set $ARGUMENTS_REGEXP_MATCH_I16 (call $regexp_args (text "(?:[a-f0-9]{4})([a-f0-9]{4})(?:[a-f0-9]{24})") (text "0x$1")))
|
|
310
|
+
(global.set $ARGUMENTS_REGEXP_MATCH_I32 (call $regexp_args (text "(?:[a-f0-9]{8})([a-f0-9]{8})(?:[a-f0-9]{16})") (text "0x$1")))
|
|
311
|
+
(global.set $ARGUMENTS_REGEXP_MATCH_I64 (call $regexp_args (text "(?:[a-f0-9]{16})([a-f0-9]{16})([a-f0-9]{0}?)") (text "0x$1")))
|
|
312
|
+
(global.set $ARGUMENTS_REGEXP_TO_STRING (call $regexp_args (text "(.{8})(.{4})(.{4})(.{4})(.*)") (text "$1-$2-$3-$4-$5")))
|
|
313
|
+
|
|
314
|
+
(i32.store (global.get $OFFSET_UUID_COUNT) (i32.const 0))
|
|
315
|
+
(i32.store (global.get $OFFSET_BLOCK_COUNT) (i32.const 1))
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
(func $regexp_args
|
|
319
|
+
(param $expression externref)
|
|
320
|
+
(param $replaceWith externref)
|
|
321
|
+
(result externref)
|
|
322
|
+
|
|
323
|
+
(array $of<ext.ext>ext
|
|
324
|
+
(reflect $construct<ext.ext>ext
|
|
325
|
+
(ref.extern $RegExp)
|
|
326
|
+
(array $of<ext.ext>ext
|
|
327
|
+
(local.get $expression)
|
|
328
|
+
(text "gi")
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
(local.get $replaceWith)
|
|
332
|
+
)
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
(func $apply_regexp
|
|
336
|
+
(param $string externref)
|
|
337
|
+
(param $expargs externref)
|
|
338
|
+
(result externref)
|
|
339
|
+
|
|
340
|
+
(reflect $apply<ext.ext.ext>ext
|
|
341
|
+
(ref.extern $String:replace)
|
|
342
|
+
(local.get $string)
|
|
343
|
+
(local.get $expargs)
|
|
344
|
+
)
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
(func $parse_bigint
|
|
348
|
+
(param $string externref)
|
|
349
|
+
(param $expargs externref)
|
|
350
|
+
(result i64)
|
|
351
|
+
|
|
352
|
+
(call $self.BigInt<ext>i64
|
|
353
|
+
(call $apply_regexp
|
|
354
|
+
(local.get $string)
|
|
355
|
+
(local.get $expargs)
|
|
356
|
+
)
|
|
357
|
+
)
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
(func $parse_number
|
|
361
|
+
(param $string externref)
|
|
362
|
+
(param $expargs externref)
|
|
363
|
+
(result i32)
|
|
364
|
+
|
|
365
|
+
(call $self.Number<ext>i32
|
|
366
|
+
(call $apply_regexp
|
|
367
|
+
(local.get $string)
|
|
368
|
+
(local.get $expargs)
|
|
369
|
+
)
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
(func $parse_vector
|
|
374
|
+
(param $string externref)
|
|
375
|
+
(result v128)
|
|
376
|
+
(local $vector v128)
|
|
377
|
+
|
|
378
|
+
(local.set $string (call $apply_regexp (local.get $string) (global.get $ARGUMENTS_REGEXP_CLEAR_STR)))
|
|
379
|
+
|
|
380
|
+
(local.get $vector)
|
|
381
|
+
(local.tee $vector (i8x16.replace_lane 0 (call $parse_number (local.get $string) (global.get $ARGUMENTS_REGEXP_MATCH_I8A))))
|
|
382
|
+
(local.tee $vector (i8x16.replace_lane 1 (call $parse_number (local.get $string) (global.get $ARGUMENTS_REGEXP_MATCH_I8B))))
|
|
383
|
+
(local.tee $vector (i16x8.replace_lane 1 (call $parse_number (local.get $string) (global.get $ARGUMENTS_REGEXP_MATCH_I16))))
|
|
384
|
+
(local.tee $vector (i32x4.replace_lane 1 (call $parse_number (local.get $string) (global.get $ARGUMENTS_REGEXP_MATCH_I32))))
|
|
385
|
+
(local.tee $vector (i64x2.replace_lane 1 (call $parse_bigint (local.get $string) (global.get $ARGUMENTS_REGEXP_MATCH_I64))))
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
(func $next_index
|
|
389
|
+
(result i32)
|
|
390
|
+
(local $uuid.index i32)
|
|
391
|
+
(local.tee $uuid.index (i32.atomic.rmw.add (global.get $OFFSET_UUID_COUNT) (i32.const 1)))
|
|
392
|
+
|
|
393
|
+
(if (i32.eqz (i32.rem_u (local.get $uuid.index) (i32.const 16)))
|
|
394
|
+
(then (i32.atomic.rmw.add (global.get $OFFSET_BLOCK_COUNT) (i32.const 1))
|
|
395
|
+
(drop))
|
|
396
|
+
)
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
(func $find
|
|
400
|
+
(result i32)
|
|
401
|
+
|
|
402
|
+
(local $i8a.value i32)
|
|
403
|
+
(local $i8b.splat v128)
|
|
404
|
+
(local $i16.splat v128)
|
|
405
|
+
(local $i32.splat v128)
|
|
406
|
+
(local $i64.splat v128)
|
|
407
|
+
|
|
408
|
+
(local $offsets v128)
|
|
409
|
+
(local $offset.i8x16 i32)
|
|
410
|
+
(local $offset.i16x8 i32)
|
|
411
|
+
(local $offset.i32x4 i32)
|
|
412
|
+
(local $offset.i64x2 i32)
|
|
413
|
+
|
|
414
|
+
(local $blocks.index i32)
|
|
415
|
+
(local $blocks.count i32)
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
(local.set $i8a.value (i32.load8_u $base offset=0 (global.get $OFFSET_SEARCH_VALUE)))
|
|
420
|
+
(local.set $i8b.splat (v128.load8_splat $base offset=1 (global.get $OFFSET_SEARCH_VALUE)))
|
|
421
|
+
(local.set $i16.splat (v128.load16_splat $base offset=2 (global.get $OFFSET_SEARCH_VALUE)))
|
|
422
|
+
(local.set $i32.splat (v128.load32_splat $base offset=4 (global.get $OFFSET_SEARCH_VALUE)))
|
|
423
|
+
(local.set $i64.splat (v128.load64_splat $base offset=8 (global.get $OFFSET_SEARCH_VALUE)))
|
|
424
|
+
|
|
425
|
+
(local.set $blocks.index (i32.const 0))
|
|
426
|
+
(local.set $blocks.count (i32.load $base (global.get $OFFSET_BLOCK_COUNT)))
|
|
427
|
+
|
|
428
|
+
(loop $blocks
|
|
429
|
+
(if (local.get $blocks.count)
|
|
430
|
+
(then
|
|
431
|
+
(local.set $offsets
|
|
432
|
+
(i32x4.mul
|
|
433
|
+
(v128.const i32x4 16 32 64 128)
|
|
434
|
+
(i32x4.splat (local.get $blocks.index))
|
|
435
|
+
)
|
|
436
|
+
)
|
|
437
|
+
|
|
438
|
+
(local.set $offset.i8x16 (i32x4.extract_lane 0 (local.get $offsets)))
|
|
439
|
+
(local.set $offset.i16x8 (i32x4.extract_lane 1 (local.get $offsets)))
|
|
440
|
+
(local.set $offset.i32x4 (i32x4.extract_lane 2 (local.get $offsets)))
|
|
441
|
+
(local.set $offset.i64x2 (i32x4.extract_lane 3 (local.get $offsets)))
|
|
442
|
+
|
|
443
|
+
(local.set $blocks.index (i32.add (local.get $blocks.index) (i32.const 1)))
|
|
444
|
+
(local.set $blocks.count (i32.sub (local.get $blocks.count) (i32.const 1)))
|
|
445
|
+
|
|
446
|
+
(br_if $blocks (i8x16.all_true (i8x16.ne (local.get $i8b.splat) (v128.load $i8b offset=0 (local.get $offset.i8x16)))))
|
|
447
|
+
|
|
448
|
+
(if (v128.any_true (i16x8.eq (local.get $i16.splat) (v128.load $i16 offset=0 (local.get $offset.i16x8))))(then
|
|
449
|
+
(if (v128.any_true (i32x4.eq (local.get $i32.splat) (v128.load $i32 offset=0 (local.get $offset.i32x4))))(then
|
|
450
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=0 (local.get $offset.i64x2))))(then
|
|
451
|
+
(if (i32.eq (i32.load8_u $i8a offset=0 (local.get $offset.i8x16)) (local.get $i8a.value))(then
|
|
452
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 0)))))
|
|
453
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=1 (local.get $offset.i8x16)))(then
|
|
454
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 1)))))))
|
|
455
|
+
|
|
456
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=16 (local.get $offset.i64x2))))(then
|
|
457
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=2 (local.get $offset.i8x16)))(then
|
|
458
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 2)))))
|
|
459
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=3 (local.get $offset.i8x16)))(then
|
|
460
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 3)))))))))
|
|
461
|
+
|
|
462
|
+
(if (v128.any_true (i32x4.eq (local.get $i32.splat) (v128.load $i32 offset=16 (local.get $offset.i32x4))))(then
|
|
463
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=32 (local.get $offset.i64x2))))(then
|
|
464
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=4 (local.get $offset.i8x16)))(then
|
|
465
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 4)))))
|
|
466
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=5 (local.get $offset.i8x16)))(then
|
|
467
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 5)))))))
|
|
468
|
+
|
|
469
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=48 (local.get $offset.i64x2))))(then
|
|
470
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=6 (local.get $offset.i8x16)))(then
|
|
471
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 6)))))
|
|
472
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=7 (local.get $offset.i8x16)))(then
|
|
473
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 7)))))))))))
|
|
474
|
+
|
|
475
|
+
(if (v128.any_true (i16x8.eq (local.get $i16.splat) (v128.load $i16 offset=16 (local.get $offset.i16x8))))(then
|
|
476
|
+
(if (v128.any_true (i32x4.eq (local.get $i32.splat) (v128.load $i32 offset=32 (local.get $offset.i32x4))))(then
|
|
477
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=64 (local.get $offset.i64x2))))(then
|
|
478
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=8 (local.get $offset.i8x16)))(then
|
|
479
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 8)))))
|
|
480
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=9 (local.get $offset.i8x16)))(then
|
|
481
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 9)))))))
|
|
482
|
+
|
|
483
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=80 (local.get $offset.i64x2))))(then
|
|
484
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=10 (local.get $offset.i8x16)))(then
|
|
485
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 10)))))
|
|
486
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=11 (local.get $offset.i8x16)))(then
|
|
487
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 11)))))))))
|
|
488
|
+
|
|
489
|
+
(if (v128.any_true (i32x4.eq (local.get $i32.splat) (v128.load $i32 offset=48 (local.get $offset.i32x4))))(then
|
|
490
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=96 (local.get $offset.i64x2))))(then
|
|
491
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=12 (local.get $offset.i8x16)))(then
|
|
492
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 12)))))
|
|
493
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=13 (local.get $offset.i8x16)))(then
|
|
494
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 13)))))))
|
|
495
|
+
|
|
496
|
+
(if (v128.any_true (i64x2.eq (local.get $i64.splat) (v128.load $i64 offset=112 (local.get $offset.i64x2))))(then
|
|
497
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=14 (local.get $offset.i8x16)))(then
|
|
498
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 14)))))
|
|
499
|
+
|
|
500
|
+
(if (i32.eq (local.get $i8a.value) (i32.load8_u $i8a offset=15 (local.get $offset.i8x16)))(then
|
|
501
|
+
(return (i32.add (local.get $offset.i8x16) (i32.const 15)))))))))))
|
|
502
|
+
|
|
503
|
+
(br $blocks)
|
|
504
|
+
)
|
|
505
|
+
)
|
|
506
|
+
)
|
|
507
|
+
|
|
508
|
+
(i32.const -1)
|
|
509
|
+
)
|
|
510
|
+
)
|
package/test.html
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script type="module">
|
|
2
|
+
import "./index.js"
|
|
3
|
+
|
|
4
|
+
turboUUID.base().then(base => {
|
|
5
|
+
console.warn(self.base = base)
|
|
6
|
+
|
|
7
|
+
self.array = new Array();
|
|
8
|
+
let count, uuid, value;
|
|
9
|
+
|
|
10
|
+
count = 32768000;
|
|
11
|
+
while (count--) {
|
|
12
|
+
uuid = base.randomUUID();;
|
|
13
|
+
array.push(uuid);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
console.log({ array })
|
|
17
|
+
|
|
18
|
+
console.log("ready")
|
|
19
|
+
new BroadcastChannel("uuid").onmessage = e => {
|
|
20
|
+
const uuid = e.data;
|
|
21
|
+
console.warn(uuid)
|
|
22
|
+
|
|
23
|
+
const t0 = performance.now();
|
|
24
|
+
const vm = array.indexOf(uuid);
|
|
25
|
+
const tm = performance.now() - t0;
|
|
26
|
+
|
|
27
|
+
const t1 = performance.now();
|
|
28
|
+
const vb = base.indexOf(uuid);
|
|
29
|
+
const tb = performance.now() - t1;
|
|
30
|
+
|
|
31
|
+
console.warn({ array: tm, vm, base: tb, vb })
|
|
32
|
+
|
|
33
|
+
performance.clearMarks();
|
|
34
|
+
performance.clearMeasures();
|
|
35
|
+
performance.clearResourceTimings();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
})
|
|
40
|
+
</script>
|
package/uuid.wasm
ADDED
|
Binary file
|