@ferrybig/cgeodata-reader 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +313 -2
- package/binary-format.md +2366 -0
- package/dist/cache.d.ts +24 -0
- package/dist/cache.js +60 -0
- package/dist/cellBounds.d.ts +19 -0
- package/dist/cellBounds.js +36 -0
- package/dist/chunk.d.ts +34 -0
- package/dist/chunk.js +269 -0
- package/dist/chunkDecoder.d.ts +39 -0
- package/dist/chunkDecoder.js +116 -0
- package/dist/chunkDecoderWasm.d.ts +2 -0
- package/dist/chunkDecoderWasm.js +4 -0
- package/dist/cli/buildLocateIndex.d.ts +2 -0
- package/dist/cli/buildLocateIndex.js +46 -0
- package/dist/cli/buildSearchIndex.d.ts +2 -0
- package/dist/cli/buildSearchIndex.js +90 -0
- package/dist/cli/chunk.d.ts +2 -0
- package/dist/cli/chunk.js +67 -0
- package/dist/cli/info.d.ts +2 -0
- package/dist/cli/info.js +87 -0
- package/dist/cli/list.d.ts +2 -0
- package/dist/cli/list.js +71 -0
- package/dist/cli/locate.d.ts +2 -0
- package/dist/cli/locate.js +64 -0
- package/dist/cli/lookup.d.ts +2 -0
- package/dist/cli/lookup.js +128 -0
- package/dist/cli/search.d.ts +2 -0
- package/dist/cli/search.js +119 -0
- package/dist/cli/shared.d.ts +50 -0
- package/dist/cli/shared.js +140 -0
- package/dist/cli/show.d.ts +2 -0
- package/dist/cli/show.js +38 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +107 -0
- package/dist/container.d.ts +17 -0
- package/dist/container.js +68 -0
- package/dist/directory.d.ts +21 -0
- package/dist/directory.js +31 -0
- package/dist/errors.d.ts +52 -0
- package/dist/errors.js +56 -0
- package/dist/format.d.ts +21 -0
- package/dist/format.js +22 -0
- package/dist/header.d.ts +29 -0
- package/dist/header.js +69 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +18 -0
- package/dist/indexes.d.ts +11 -0
- package/dist/indexes.js +12 -0
- package/dist/inflate.d.ts +21 -0
- package/dist/inflate.js +61 -0
- package/dist/locateIndex.d.ts +142 -0
- package/dist/locateIndex.js +561 -0
- package/dist/morton.d.ts +28 -0
- package/dist/morton.js +51 -0
- package/dist/node.d.ts +65 -0
- package/dist/node.js +137 -0
- package/dist/placeTable.d.ts +69 -0
- package/dist/placeTable.js +177 -0
- package/dist/reader.d.ts +534 -0
- package/dist/reader.js +1128 -0
- package/dist/relevance.d.ts +184 -0
- package/dist/relevance.js +266 -0
- package/dist/searchIndex.d.ts +148 -0
- package/dist/searchIndex.js +786 -0
- package/dist/source.d.ts +49 -0
- package/dist/source.js +50 -0
- package/dist/turns.d.ts +19 -0
- package/dist/turns.js +40 -0
- package/dist/varint.d.ts +52 -0
- package/dist/varint.js +137 -0
- package/package.json +76 -5
package/dist/source.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a reader gets its bytes from. This is what lets a reader honour
|
|
3
|
+
* Section 1.2's goal 2 ("a reader MUST be able to answer a lookup by
|
|
4
|
+
* reading and decompressing only a small, bounded part of the file"): a
|
|
5
|
+
* source is only ever asked for the bytes a lookup needs.
|
|
6
|
+
*
|
|
7
|
+
* Reads are asynchronous so that a source can be anything that hands out
|
|
8
|
+
* byte ranges: a file (`FileSource` in `./node.ts`), a `Blob` or `File`
|
|
9
|
+
* in a browser, or bytes already in memory. Nothing here depends on
|
|
10
|
+
* Node.js.
|
|
11
|
+
*/
|
|
12
|
+
export interface ByteSource {
|
|
13
|
+
/** Total size in bytes. */
|
|
14
|
+
readonly size: number;
|
|
15
|
+
/** Shown in error messages about this source, e.g. a file path. */
|
|
16
|
+
readonly name?: string;
|
|
17
|
+
/**
|
|
18
|
+
* `length` bytes from `offset`, fewer only where the source ends. The
|
|
19
|
+
* returned bytes may be a view of the source's own memory, so a caller
|
|
20
|
+
* must not modify them.
|
|
21
|
+
*/
|
|
22
|
+
read(offset: number, length: number): Promise<Uint8Array>;
|
|
23
|
+
/** Releases whatever the source holds open, if anything. */
|
|
24
|
+
close?(): Promise<void> | void;
|
|
25
|
+
}
|
|
26
|
+
/** A source over bytes already in memory: a file read up front, or the
|
|
27
|
+
* body of a `fetch()`. */
|
|
28
|
+
export declare class BytesSource implements ByteSource {
|
|
29
|
+
private readonly bytes;
|
|
30
|
+
readonly name?: string;
|
|
31
|
+
constructor(bytes: Uint8Array | ArrayBuffer, name?: string);
|
|
32
|
+
get size(): number;
|
|
33
|
+
read(offset: number, length: number): Promise<Uint8Array>;
|
|
34
|
+
/** `read()` without the promise: bytes in memory need no waiting. */
|
|
35
|
+
readNow(offset: number, length: number): Uint8Array;
|
|
36
|
+
}
|
|
37
|
+
/** A source over a `Blob` -- in a browser, a `File` the user picked --
|
|
38
|
+
* reading each range as it's asked for, without loading the whole file. */
|
|
39
|
+
export declare class BlobSource implements ByteSource {
|
|
40
|
+
private readonly blob;
|
|
41
|
+
readonly name?: string;
|
|
42
|
+
constructor(blob: Blob, name?: string);
|
|
43
|
+
get size(): number;
|
|
44
|
+
read(offset: number, length: number): Promise<Uint8Array>;
|
|
45
|
+
}
|
|
46
|
+
/** What `CGeoDataReader.open()` and the index classes accept as a file. */
|
|
47
|
+
export type SourceInput = ByteSource | Uint8Array | ArrayBuffer | Blob;
|
|
48
|
+
/** `input` as a `ByteSource`. */
|
|
49
|
+
export declare function toSource(input: SourceInput): ByteSource;
|
package/dist/source.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** A source over bytes already in memory: a file read up front, or the
|
|
2
|
+
* body of a `fetch()`. */
|
|
3
|
+
export class BytesSource {
|
|
4
|
+
bytes;
|
|
5
|
+
name;
|
|
6
|
+
constructor(bytes, name) {
|
|
7
|
+
this.bytes = bytes instanceof Uint8Array ? bytes : new Uint8Array(bytes);
|
|
8
|
+
if (name !== undefined)
|
|
9
|
+
this.name = name;
|
|
10
|
+
}
|
|
11
|
+
get size() {
|
|
12
|
+
return this.bytes.length;
|
|
13
|
+
}
|
|
14
|
+
read(offset, length) {
|
|
15
|
+
return Promise.resolve(this.readNow(offset, length));
|
|
16
|
+
}
|
|
17
|
+
/** `read()` without the promise: bytes in memory need no waiting. */
|
|
18
|
+
readNow(offset, length) {
|
|
19
|
+
const start = Math.min(offset, this.bytes.length);
|
|
20
|
+
return this.bytes.subarray(start, Math.min(start + length, this.bytes.length));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/** A source over a `Blob` -- in a browser, a `File` the user picked --
|
|
24
|
+
* reading each range as it's asked for, without loading the whole file. */
|
|
25
|
+
export class BlobSource {
|
|
26
|
+
blob;
|
|
27
|
+
name;
|
|
28
|
+
constructor(blob, name) {
|
|
29
|
+
this.blob = blob;
|
|
30
|
+
const fileName = blob.name;
|
|
31
|
+
const resolved = name ?? (typeof fileName === "string" ? fileName : undefined);
|
|
32
|
+
if (resolved !== undefined)
|
|
33
|
+
this.name = resolved;
|
|
34
|
+
}
|
|
35
|
+
get size() {
|
|
36
|
+
return this.blob.size;
|
|
37
|
+
}
|
|
38
|
+
async read(offset, length) {
|
|
39
|
+
return new Uint8Array(await this.blob.slice(offset, offset + length).arrayBuffer());
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** `input` as a `ByteSource`. */
|
|
43
|
+
export function toSource(input) {
|
|
44
|
+
if (input instanceof Uint8Array || input instanceof ArrayBuffer)
|
|
45
|
+
return new BytesSource(input);
|
|
46
|
+
if (typeof Blob !== "undefined" && input instanceof Blob)
|
|
47
|
+
return new BlobSource(input);
|
|
48
|
+
return input;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=source.js.map
|
package/dist/turns.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decoding a chunk is CPU work on the calling thread, a few milliseconds
|
|
3
|
+
* for a large one. Reads run concurrently, but if every read that's done
|
|
4
|
+
* went straight on to decode, many lookups started at once would decode
|
|
5
|
+
* back to back -- Node.js delivers all finished reads in one go -- and
|
|
6
|
+
* hold the event loop for the whole batch (330 ms for 300 lookups across
|
|
7
|
+
* Europe, measured). `TurnQueue` runs decodes one at a time instead, each
|
|
8
|
+
* in a macrotask of its own, so other work gets a turn between any two.
|
|
9
|
+
*/
|
|
10
|
+
export declare class TurnQueue {
|
|
11
|
+
private tail;
|
|
12
|
+
/** Runs `work` after everything queued before it, in a fresh
|
|
13
|
+
* macrotask. */
|
|
14
|
+
run<T>(work: () => T | Promise<T>): Promise<T>;
|
|
15
|
+
}
|
|
16
|
+
/** Resolves in a new macrotask: Node's `setImmediate` (after pending I/O,
|
|
17
|
+
* before timers come round again), else a `MessageChannel` message (not
|
|
18
|
+
* clamped like a nested `setTimeout(0)` in browsers), else `setTimeout`. */
|
|
19
|
+
export declare const yieldToEventLoop: () => Promise<void>;
|
package/dist/turns.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decoding a chunk is CPU work on the calling thread, a few milliseconds
|
|
3
|
+
* for a large one. Reads run concurrently, but if every read that's done
|
|
4
|
+
* went straight on to decode, many lookups started at once would decode
|
|
5
|
+
* back to back -- Node.js delivers all finished reads in one go -- and
|
|
6
|
+
* hold the event loop for the whole batch (330 ms for 300 lookups across
|
|
7
|
+
* Europe, measured). `TurnQueue` runs decodes one at a time instead, each
|
|
8
|
+
* in a macrotask of its own, so other work gets a turn between any two.
|
|
9
|
+
*/
|
|
10
|
+
export class TurnQueue {
|
|
11
|
+
tail = Promise.resolve();
|
|
12
|
+
/** Runs `work` after everything queued before it, in a fresh
|
|
13
|
+
* macrotask. */
|
|
14
|
+
run(work) {
|
|
15
|
+
const result = this.tail.then(yieldToEventLoop).then(work);
|
|
16
|
+
this.tail = result.catch(() => { });
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/** Resolves in a new macrotask: Node's `setImmediate` (after pending I/O,
|
|
21
|
+
* before timers come round again), else a `MessageChannel` message (not
|
|
22
|
+
* clamped like a nested `setTimeout(0)` in browsers), else `setTimeout`. */
|
|
23
|
+
export const yieldToEventLoop = (() => {
|
|
24
|
+
const setImmediate = globalThis.setImmediate;
|
|
25
|
+
if (setImmediate)
|
|
26
|
+
return () => new Promise((r) => setImmediate(r));
|
|
27
|
+
if (typeof MessageChannel !== "undefined") {
|
|
28
|
+
const channel = new MessageChannel();
|
|
29
|
+
const waiting = [];
|
|
30
|
+
// A browser's MessagePort; Node's typings (which never reach here)
|
|
31
|
+
// lack `onmessage`.
|
|
32
|
+
channel.port1.onmessage = () => waiting.shift()?.();
|
|
33
|
+
return () => new Promise((resolve) => {
|
|
34
|
+
waiting.push(resolve);
|
|
35
|
+
channel.port2.postMessage(null);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return () => new Promise((resolve) => setTimeout(resolve, 0));
|
|
39
|
+
})();
|
|
40
|
+
//# sourceMappingURL=turns.js.map
|
package/dist/varint.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { CGeoDataFormatError } from "./errors.ts";
|
|
2
|
+
/**
|
|
3
|
+
* varint (LEB128) codec, per binary-format.md Section 3.2, plus the
|
|
4
|
+
* delta-coded list helper from Section 3.3.
|
|
5
|
+
*/
|
|
6
|
+
/** Thrown when a parser ran out of bytes because the given buffer was too
|
|
7
|
+
* short to hold the full structure -- distinct from a genuine format error,
|
|
8
|
+
* so callers can retry with a larger read. */
|
|
9
|
+
export declare class IncompleteBufferError extends CGeoDataFormatError {
|
|
10
|
+
name: string;
|
|
11
|
+
}
|
|
12
|
+
/** One decoded varint. */
|
|
13
|
+
export interface VarintResult {
|
|
14
|
+
/** The value, below 2^53. */
|
|
15
|
+
value: number;
|
|
16
|
+
/** How many bytes it took (1-8). */
|
|
17
|
+
bytesRead: number;
|
|
18
|
+
}
|
|
19
|
+
/** The varint (Section 3.2) at `offset`; throws a `CGeoDataFormatError`
|
|
20
|
+
* for a malformed one, an `IncompleteBufferError` for a cut-off one. */
|
|
21
|
+
export declare function readVarint(buf: Uint8Array, offset: number): VarintResult;
|
|
22
|
+
/** `value`'s minimal varint encoding (Section 3.2). */
|
|
23
|
+
export declare function writeVarint(value: number): Uint8Array;
|
|
24
|
+
/** A decoded list of varints. */
|
|
25
|
+
export interface VarintListResult {
|
|
26
|
+
/** The values, in order. */
|
|
27
|
+
values: number[];
|
|
28
|
+
/** How many bytes the whole list took. */
|
|
29
|
+
bytesRead: number;
|
|
30
|
+
}
|
|
31
|
+
/** A plain list of `count` varints (not delta-coded) -- used for
|
|
32
|
+
* region_counts, city_counts, chunk_lengths, and block_lengths. */
|
|
33
|
+
export declare function readVarintList(buf: Uint8Array, offset: number, count: number): VarintListResult;
|
|
34
|
+
/** A delta-coded list per Section 3.3 -- used for a chunk's palette and
|
|
35
|
+
* codes. Each stored varint is the difference from the previous element,
|
|
36
|
+
* with an implicit previous element of 0 before the first. */
|
|
37
|
+
export declare function readDeltaVarintList(buf: Uint8Array, offset: number, count: number): VarintListResult;
|
|
38
|
+
/**
|
|
39
|
+
* `out.length` delta-coded varints (Section 3.3) from `buf` at `offset`
|
|
40
|
+
* into `out`, returning the offset just past them. Decodes straight into
|
|
41
|
+
* a typed array, without an object per varint (see `varintEnd`).
|
|
42
|
+
*/
|
|
43
|
+
export declare function readDeltaVarintsInto(buf: Uint8Array, offset: number, out: Float64Array): number;
|
|
44
|
+
/**
|
|
45
|
+
* `readDeltaVarintsInto` for values known to fit in 32 bits, such as a
|
|
46
|
+
* chunk's codes at `max_depth` 16 and under: a running total that
|
|
47
|
+
* outgrows the `Uint32Array` is a format error, not a silent wraparound.
|
|
48
|
+
* A separate function rather than one taking either array, because V8
|
|
49
|
+
* optimizes a loop for the array types its function has seen, and a
|
|
50
|
+
* loop that has seen both decoded chunks ~10% slower.
|
|
51
|
+
*/
|
|
52
|
+
export declare function readDeltaVarints32Into(buf: Uint8Array, offset: number, out: Uint32Array): number;
|
package/dist/varint.js
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { CGeoDataFormatError } from "./errors.js";
|
|
2
|
+
/**
|
|
3
|
+
* varint (LEB128) codec, per binary-format.md Section 3.2, plus the
|
|
4
|
+
* delta-coded list helper from Section 3.3.
|
|
5
|
+
*/
|
|
6
|
+
/** Thrown when a parser ran out of bytes because the given buffer was too
|
|
7
|
+
* short to hold the full structure -- distinct from a genuine format error,
|
|
8
|
+
* so callers can retry with a larger read. */
|
|
9
|
+
export class IncompleteBufferError extends CGeoDataFormatError {
|
|
10
|
+
name = "IncompleteBufferError";
|
|
11
|
+
}
|
|
12
|
+
const CONTINUATION_BIT = 0x80;
|
|
13
|
+
const PAYLOAD_MASK = 0x7f;
|
|
14
|
+
const MAX_VARINT_BYTES = 8;
|
|
15
|
+
// Section 3.2: every varint MUST be less than 2^53, so it round-trips
|
|
16
|
+
// exactly through an IEEE 754 double.
|
|
17
|
+
const MAX_VARINT_VALUE = 2 ** 53;
|
|
18
|
+
/** The varint (Section 3.2) at `offset`; throws a `CGeoDataFormatError`
|
|
19
|
+
* for a malformed one, an `IncompleteBufferError` for a cut-off one. */
|
|
20
|
+
export function readVarint(buf, offset) {
|
|
21
|
+
const value = varintAt(buf, offset);
|
|
22
|
+
return { value, bytesRead: varintEnd - offset };
|
|
23
|
+
}
|
|
24
|
+
/** `value`'s minimal varint encoding (Section 3.2). */
|
|
25
|
+
export function writeVarint(value) {
|
|
26
|
+
if (!Number.isInteger(value) || value < 0) {
|
|
27
|
+
throw new RangeError("varint value must be a non-negative integer");
|
|
28
|
+
}
|
|
29
|
+
if (value >= MAX_VARINT_VALUE) {
|
|
30
|
+
throw new RangeError("varint value must be less than 2^53");
|
|
31
|
+
}
|
|
32
|
+
const bytes = [];
|
|
33
|
+
let remaining = value;
|
|
34
|
+
do {
|
|
35
|
+
let byte = remaining % 128;
|
|
36
|
+
remaining = Math.floor(remaining / 128);
|
|
37
|
+
if (remaining > 0)
|
|
38
|
+
byte |= CONTINUATION_BIT;
|
|
39
|
+
bytes.push(byte);
|
|
40
|
+
} while (remaining > 0);
|
|
41
|
+
return Uint8Array.from(bytes);
|
|
42
|
+
}
|
|
43
|
+
/** A plain list of `count` varints (not delta-coded) -- used for
|
|
44
|
+
* region_counts, city_counts, chunk_lengths, and block_lengths. */
|
|
45
|
+
export function readVarintList(buf, offset, count) {
|
|
46
|
+
const values = new Array(count);
|
|
47
|
+
let cursor = offset;
|
|
48
|
+
for (let i = 0; i < count; i++) {
|
|
49
|
+
const { value, bytesRead } = readVarint(buf, cursor);
|
|
50
|
+
values[i] = value;
|
|
51
|
+
cursor += bytesRead;
|
|
52
|
+
}
|
|
53
|
+
return { values, bytesRead: cursor - offset };
|
|
54
|
+
}
|
|
55
|
+
/** A delta-coded list per Section 3.3 -- used for a chunk's palette and
|
|
56
|
+
* codes. Each stored varint is the difference from the previous element,
|
|
57
|
+
* with an implicit previous element of 0 before the first. */
|
|
58
|
+
export function readDeltaVarintList(buf, offset, count) {
|
|
59
|
+
const values = new Float64Array(count);
|
|
60
|
+
const end = readDeltaVarintsInto(buf, offset, values);
|
|
61
|
+
return { values: Array.from(values), bytesRead: end - offset };
|
|
62
|
+
}
|
|
63
|
+
/** Where the varint `varintAt` last read ended: a second return value,
|
|
64
|
+
* kept here rather than in a returned object because a chunk's codes are
|
|
65
|
+
* millions of varints, and an object per varint showed up as most of a
|
|
66
|
+
* chunk's parse time. */
|
|
67
|
+
let varintEnd = 0;
|
|
68
|
+
/**
|
|
69
|
+
* The varint at `cursor`, leaving the offset just past it in
|
|
70
|
+
* `varintEnd`. The one varint decoder here, so every varint the reader
|
|
71
|
+
* reads gets the same checks.
|
|
72
|
+
*/
|
|
73
|
+
function varintAt(buf, cursor) {
|
|
74
|
+
let byte = buf[cursor++];
|
|
75
|
+
if (byte === undefined)
|
|
76
|
+
throw new IncompleteBufferError("varint runs past end of buffer");
|
|
77
|
+
let value = byte & PAYLOAD_MASK;
|
|
78
|
+
let scale = 128;
|
|
79
|
+
for (let n = 1; byte & CONTINUATION_BIT; n++) {
|
|
80
|
+
if (n === MAX_VARINT_BYTES)
|
|
81
|
+
throw new CGeoDataFormatError(`varint longer than ${MAX_VARINT_BYTES} bytes`);
|
|
82
|
+
byte = buf[cursor++];
|
|
83
|
+
if (byte === undefined)
|
|
84
|
+
throw new IncompleteBufferError("varint runs past end of buffer");
|
|
85
|
+
value += (byte & PAYLOAD_MASK) * scale;
|
|
86
|
+
if ((byte & CONTINUATION_BIT) === 0) {
|
|
87
|
+
if (value >= MAX_VARINT_VALUE) {
|
|
88
|
+
throw new CGeoDataFormatError("varint value must be less than 2^53");
|
|
89
|
+
}
|
|
90
|
+
if (byte === 0) {
|
|
91
|
+
// A minimal encoder never emits a trailing zero group (see
|
|
92
|
+
// writeVarint above), so this can only be non-minimal padding.
|
|
93
|
+
throw new CGeoDataFormatError("non-minimal varint encoding (trailing zero byte)");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
scale *= 128;
|
|
97
|
+
}
|
|
98
|
+
varintEnd = cursor;
|
|
99
|
+
return value;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* `out.length` delta-coded varints (Section 3.3) from `buf` at `offset`
|
|
103
|
+
* into `out`, returning the offset just past them. Decodes straight into
|
|
104
|
+
* a typed array, without an object per varint (see `varintEnd`).
|
|
105
|
+
*/
|
|
106
|
+
export function readDeltaVarintsInto(buf, offset, out) {
|
|
107
|
+
let cursor = offset;
|
|
108
|
+
let previous = 0;
|
|
109
|
+
for (let i = 0; i < out.length; i++) {
|
|
110
|
+
previous += varintAt(buf, cursor);
|
|
111
|
+
cursor = varintEnd;
|
|
112
|
+
out[i] = previous;
|
|
113
|
+
}
|
|
114
|
+
return cursor;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* `readDeltaVarintsInto` for values known to fit in 32 bits, such as a
|
|
118
|
+
* chunk's codes at `max_depth` 16 and under: a running total that
|
|
119
|
+
* outgrows the `Uint32Array` is a format error, not a silent wraparound.
|
|
120
|
+
* A separate function rather than one taking either array, because V8
|
|
121
|
+
* optimizes a loop for the array types its function has seen, and a
|
|
122
|
+
* loop that has seen both decoded chunks ~10% slower.
|
|
123
|
+
*/
|
|
124
|
+
export function readDeltaVarints32Into(buf, offset, out) {
|
|
125
|
+
let cursor = offset;
|
|
126
|
+
let previous = 0;
|
|
127
|
+
for (let i = 0; i < out.length; i++) {
|
|
128
|
+
previous += varintAt(buf, cursor);
|
|
129
|
+
cursor = varintEnd;
|
|
130
|
+
if (previous > 0xffffffff) {
|
|
131
|
+
throw new CGeoDataFormatError(`delta-coded value ${previous} does not fit in 32 bits`);
|
|
132
|
+
}
|
|
133
|
+
out[i] = previous;
|
|
134
|
+
}
|
|
135
|
+
return cursor;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=varint.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,77 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"name": "@ferrybig/cgeodata-reader",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reverse geocoding without a database: resolves a latitude/longitude to its country, region and city from OpenStreetMap boundaries, reading a compact CGEODATA file. No dependencies; Node.js and browsers.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"reverse-geocoding",
|
|
7
|
+
"geocoding",
|
|
8
|
+
"geodata",
|
|
9
|
+
"openstreetmap",
|
|
10
|
+
"administrative-boundaries",
|
|
11
|
+
"offline"
|
|
12
|
+
],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"author": "Fernando van Loenhout",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/ferrybig/loc-to-city.git",
|
|
18
|
+
"directory": "reader"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/ferrybig/loc-to-city/tree/master/reader#readme",
|
|
21
|
+
"bugs": "https://github.com/ferrybig/loc-to-city/issues",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=24"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"main": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"types": "./dist/index.d.ts",
|
|
32
|
+
"default": "./dist/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./node": {
|
|
35
|
+
"types": "./dist/node.d.ts",
|
|
36
|
+
"default": "./dist/node.js"
|
|
37
|
+
},
|
|
38
|
+
"./indexes": {
|
|
39
|
+
"types": "./dist/indexes.d.ts",
|
|
40
|
+
"default": "./dist/indexes.js"
|
|
41
|
+
},
|
|
42
|
+
"./format": {
|
|
43
|
+
"types": "./dist/format.d.ts",
|
|
44
|
+
"default": "./dist/format.js"
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"bin": {
|
|
49
|
+
"cgeodata": "./dist/cli.js",
|
|
50
|
+
"cgeodata-reader": "./dist/cli.js"
|
|
51
|
+
},
|
|
52
|
+
"publishConfig": {
|
|
53
|
+
"access": "public"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist",
|
|
57
|
+
"!dist/**/*.map",
|
|
58
|
+
"binary-format.md"
|
|
59
|
+
],
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\" && tsc -p tsconfig.json",
|
|
62
|
+
"test": "node --test test/*.test.ts",
|
|
63
|
+
"typecheck": "tsc -p tsconfig.test.json",
|
|
64
|
+
"bench": "node --expose-gc bench/bench.ts",
|
|
65
|
+
"docs": "typedoc",
|
|
66
|
+
"build:wasm": "node scripts/build-wasm.ts",
|
|
67
|
+
"prepack": "npm run build"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@biomejs/biome": "2.5.13",
|
|
71
|
+
"@playwright/test": "^1.48.0",
|
|
72
|
+
"@types/node": "^24.0.0",
|
|
73
|
+
"typedoc": "0.28.20",
|
|
74
|
+
"typescript": "^5.7.0",
|
|
75
|
+
"wabt": "1.0.36"
|
|
76
|
+
}
|
|
77
|
+
}
|