@osmix/core 0.1.8 → 0.2.0
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 +37 -0
- package/LICENSE +21 -0
- package/README.md +86 -69
- package/dist/contracts.d.ts +26 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +1 -0
- package/dist/contracts.js.map +1 -0
- package/dist/entities.d.ts +1 -1
- package/dist/entities.d.ts.map +1 -1
- package/dist/entities.js +2 -7
- package/dist/entities.js.map +1 -1
- package/dist/ids.d.ts +2 -0
- package/dist/ids.d.ts.map +1 -1
- package/dist/ids.js +23 -15
- package/dist/ids.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/mocks.d.ts.map +1 -1
- package/dist/mocks.js.map +1 -1
- package/dist/nodes.d.ts +9 -3
- package/dist/nodes.d.ts.map +1 -1
- package/dist/nodes.js +6 -13
- package/dist/nodes.js.map +1 -1
- package/dist/osm.d.ts +1 -1
- package/dist/osm.d.ts.map +1 -1
- package/dist/osm.js +1 -4
- package/dist/osm.js.map +1 -1
- package/dist/relations.d.ts +3 -2
- package/dist/relations.d.ts.map +1 -1
- package/dist/relations.js +15 -9
- package/dist/relations.js.map +1 -1
- package/dist/stringtable.d.ts.map +1 -1
- package/dist/stringtable.js +4 -13
- package/dist/stringtable.js.map +1 -1
- package/dist/tags.d.ts +1 -1
- package/dist/tags.d.ts.map +1 -1
- package/dist/tags.js.map +1 -1
- package/dist/typed-arrays.d.ts +1 -1
- package/dist/typed-arrays.d.ts.map +1 -1
- package/dist/typed-arrays.js.map +1 -1
- package/dist/ways.d.ts +2 -1
- package/dist/ways.d.ts.map +1 -1
- package/dist/ways.js +18 -18
- package/dist/ways.js.map +1 -1
- package/package.json +46 -31
- package/src/contracts.ts +28 -0
- package/src/entities.ts +179 -194
- package/src/ids.ts +228 -235
- package/src/index.ts +12 -9
- package/src/mocks.ts +114 -113
- package/src/nodes.ts +364 -397
- package/src/osm.ts +196 -207
- package/src/relations.ts +530 -558
- package/src/stringtable.ts +174 -183
- package/src/tags.ts +263 -271
- package/src/typed-arrays.ts +184 -194
- package/src/types/geoflatbush.d.ts +28 -33
- package/src/types/geokdbush.d.ts +28 -33
- package/src/types/kdbush.d.ts +34 -34
- package/src/ways.ts +381 -405
- package/test/ids.bench.ts +29 -0
- package/test/ids.test.ts +84 -0
- package/test/memory.test.ts +29 -30
- package/test/relations.bench.ts +27 -0
- package/test/relations.test.ts +101 -0
- package/test/tags-search.test.ts +76 -56
- package/test/typed-arrays.test.ts +100 -99
- package/tsconfig.build.json +6 -3
- package/tsconfig.json +7 -7
package/src/stringtable.ts
CHANGED
|
@@ -7,20 +7,21 @@
|
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { OsmPbfStringTable } from "@osmix/pbf"
|
|
11
|
-
import type { ContentHasher } from "@osmix/shared/content-hasher"
|
|
12
|
-
|
|
10
|
+
import type { OsmPbfStringTable } from "@osmix/pbf";
|
|
11
|
+
import type { ContentHasher } from "@osmix/shared/content-hasher";
|
|
12
|
+
|
|
13
|
+
import { type BufferType, ResizeableTypedArray as RTA } from "./typed-arrays.ts";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Serializable state for worker transfer.
|
|
16
17
|
*/
|
|
17
18
|
export interface StringTableTransferables<T extends BufferType = BufferType> {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/** Concatenated UTF-8 bytes. */
|
|
20
|
+
bytes: T;
|
|
21
|
+
/** Maps string index → byte offset. */
|
|
22
|
+
start: T;
|
|
23
|
+
/** Maps string index → byte length. */
|
|
24
|
+
count: T;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
/**
|
|
@@ -30,178 +31,168 @@ export interface StringTableTransferables<T extends BufferType = BufferType> {
|
|
|
30
31
|
* Rebuilds reverse index lazily after transfer.
|
|
31
32
|
*/
|
|
32
33
|
export default class StringTable {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Update a ContentHasher with the string table's data.
|
|
199
|
-
* Hashes the bytes, start offsets, and counts.
|
|
200
|
-
*/
|
|
201
|
-
updateHash(hasher: ContentHasher): ContentHasher {
|
|
202
|
-
return hasher
|
|
203
|
-
.update(this.bytes.array)
|
|
204
|
-
.update(this.start.array)
|
|
205
|
-
.update(this.count.array)
|
|
206
|
-
}
|
|
34
|
+
/** UTF-8 encoder for string→bytes conversion */
|
|
35
|
+
private enc = new TextEncoder();
|
|
36
|
+
/** UTF-8 decoder for bytes→string conversion */
|
|
37
|
+
private dec = new TextDecoder(); // UTF-8
|
|
38
|
+
|
|
39
|
+
// ─── Serializable State ────────────────────────────────────────────────────
|
|
40
|
+
/** Concatenated UTF-8 bytes of all strings */
|
|
41
|
+
bytes: RTA<Uint8Array>;
|
|
42
|
+
/** Maps string index → byte offset in bytes array */
|
|
43
|
+
start: RTA<Uint32Array>;
|
|
44
|
+
/** Maps string index → byte length */
|
|
45
|
+
count: RTA<Uint16Array>;
|
|
46
|
+
|
|
47
|
+
// ─── Builder State (string → index) ────────────────────────────────────────
|
|
48
|
+
/** Forward lookup: string → index (populated during add) */
|
|
49
|
+
private stringToIndex = new Map<string, number>();
|
|
50
|
+
|
|
51
|
+
/** Whether the reverse index has been built (lazy after transfer) */
|
|
52
|
+
private reverseIndexBuilt = false;
|
|
53
|
+
|
|
54
|
+
// ─── Retrieval Cache (index → string) ──────────────────────────────────────
|
|
55
|
+
/** Cache of decoded strings to avoid repeated UTF-8 decoding */
|
|
56
|
+
private indexToString = new Map<number, string>();
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Create a new StringTable.
|
|
60
|
+
*/
|
|
61
|
+
constructor(opts?: StringTableTransferables) {
|
|
62
|
+
this.bytes = opts?.bytes ? RTA.from(Uint8Array, opts.bytes) : new RTA(Uint8Array);
|
|
63
|
+
this.start = opts?.start ? RTA.from(Uint32Array, opts.start) : new RTA(Uint32Array);
|
|
64
|
+
this.count = opts?.count ? RTA.from(Uint16Array, opts.count) : new RTA(Uint16Array);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get transferable objects for passing to another thread.
|
|
69
|
+
*/
|
|
70
|
+
transferables(): StringTableTransferables {
|
|
71
|
+
return {
|
|
72
|
+
bytes: this.bytes.array.buffer,
|
|
73
|
+
start: this.start.array.buffer,
|
|
74
|
+
count: this.count.array.buffer,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Add a string to the table and return its index.
|
|
80
|
+
*/
|
|
81
|
+
add(str: string): number {
|
|
82
|
+
const existingIndex = this.stringToIndex.get(str);
|
|
83
|
+
if (existingIndex !== undefined) return existingIndex;
|
|
84
|
+
const startIndex = this.start.length;
|
|
85
|
+
const encoded = this.enc.encode(str);
|
|
86
|
+
this.start.push(this.bytes.length);
|
|
87
|
+
this.bytes.pushMany(encoded);
|
|
88
|
+
this.count.push(encoded.length);
|
|
89
|
+
this.stringToIndex.set(str, startIndex);
|
|
90
|
+
return startIndex;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Decode all the strings in a primitive block and add them to the string table.
|
|
95
|
+
* Return a mapping of block index -> string table index
|
|
96
|
+
*/
|
|
97
|
+
createBlockIndexMap(blockStringtable: OsmPbfStringTable) {
|
|
98
|
+
const index = new Uint32Array(blockStringtable.length);
|
|
99
|
+
for (let i = 0; i < blockStringtable.length; i++) {
|
|
100
|
+
const bytesString = blockStringtable[i];
|
|
101
|
+
const str = this.dec.decode(bytesString);
|
|
102
|
+
const existingIndex = this.stringToIndex.get(str);
|
|
103
|
+
if (existingIndex !== undefined) {
|
|
104
|
+
index[i] = existingIndex;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
index[i] = this.add(str);
|
|
108
|
+
}
|
|
109
|
+
return index;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get a string by its index.
|
|
114
|
+
* Caches results to avoid repeated UTF-8 decoding.
|
|
115
|
+
*/
|
|
116
|
+
get(index: number): string {
|
|
117
|
+
const string = this.indexToString.get(index);
|
|
118
|
+
if (string) return string;
|
|
119
|
+
const bytes = this.getBytes(index);
|
|
120
|
+
const tempBuffer = new ArrayBuffer(bytes.byteLength);
|
|
121
|
+
const tempBytes = new Uint8Array(tempBuffer);
|
|
122
|
+
tempBytes.set(bytes);
|
|
123
|
+
const decoded = this.dec.decode(tempBytes);
|
|
124
|
+
this.indexToString.set(index, decoded);
|
|
125
|
+
return decoded;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Get the raw UTF-8 bytes of a string.
|
|
130
|
+
* Returns a subarray view (not a copy).
|
|
131
|
+
*/
|
|
132
|
+
getBytes(index: number): Uint8Array {
|
|
133
|
+
if (index < 0 || index >= this.length) throw Error(`String index out of range: ${index}`);
|
|
134
|
+
const start = this.start.at(index);
|
|
135
|
+
const count = this.count.at(index);
|
|
136
|
+
return this.bytes.array.subarray(start, start + count);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Number of strings in the table. */
|
|
140
|
+
get length() {
|
|
141
|
+
return this.start.length;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Finalize the string table by compacting internal arrays.
|
|
146
|
+
*
|
|
147
|
+
* This releases unused buffer capacity and marks the reverse index as built
|
|
148
|
+
* (since all strings were added before this call).
|
|
149
|
+
*/
|
|
150
|
+
buildIndex() {
|
|
151
|
+
this.bytes.compact();
|
|
152
|
+
this.start.compact();
|
|
153
|
+
this.count.compact();
|
|
154
|
+
this.reverseIndexBuilt = true;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Convert the string table to an OSM PBF string table.
|
|
159
|
+
*/
|
|
160
|
+
toOsmPbfStringTable(): OsmPbfStringTable {
|
|
161
|
+
const stringTable: OsmPbfStringTable = [];
|
|
162
|
+
for (let i = 0; i < this.length; i++) {
|
|
163
|
+
stringTable.push(this.getBytes(i));
|
|
164
|
+
}
|
|
165
|
+
return stringTable;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Lazily build the reverse index (string → index).
|
|
170
|
+
* Decodes all strings once to populate the lookup map.
|
|
171
|
+
*/
|
|
172
|
+
private ensureReverseIndex() {
|
|
173
|
+
if (this.reverseIndexBuilt) return;
|
|
174
|
+
// Decode all strings and populate the forward lookup map
|
|
175
|
+
for (let i = 0; i < this.length; i++) {
|
|
176
|
+
this.stringToIndex.set(this.get(i), i);
|
|
177
|
+
}
|
|
178
|
+
this.reverseIndexBuilt = true;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Find the index of a string.
|
|
183
|
+
*/
|
|
184
|
+
find(str: string): number {
|
|
185
|
+
const existing = this.stringToIndex.get(str);
|
|
186
|
+
if (existing !== undefined) return existing;
|
|
187
|
+
this.ensureReverseIndex();
|
|
188
|
+
return this.stringToIndex.get(str) ?? -1;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Update a ContentHasher with the string table's data.
|
|
193
|
+
* Hashes the bytes, start offsets, and counts.
|
|
194
|
+
*/
|
|
195
|
+
updateHash(hasher: ContentHasher): ContentHasher {
|
|
196
|
+
return hasher.update(this.bytes.array).update(this.start.array).update(this.count.array);
|
|
197
|
+
}
|
|
207
198
|
}
|