@dra2020/baseclient 1.0.12 → 1.0.13
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/package.json +16 -15
- package/LICENSE +0 -21
- package/README.md +0 -26
- package/dist/all/all.d.ts +0 -20
- package/dist/baseclient.js +0 -10113
- package/dist/baseclient.js.map +0 -1
- package/dist/context/all.d.ts +0 -1
- package/dist/context/context.d.ts +0 -13
- package/dist/filterexpr/all.d.ts +0 -1
- package/dist/filterexpr/filterexpr.d.ts +0 -67
- package/dist/fsm/all.d.ts +0 -1
- package/dist/fsm/fsm.d.ts +0 -119
- package/dist/geo/all.d.ts +0 -2
- package/dist/geo/geo.d.ts +0 -67
- package/dist/geo/vfeature.d.ts +0 -4
- package/dist/logabstract/all.d.ts +0 -1
- package/dist/logabstract/log.d.ts +0 -26
- package/dist/logclient/all.d.ts +0 -1
- package/dist/logclient/log.d.ts +0 -6
- package/dist/ot-editutil/all.d.ts +0 -2
- package/dist/ot-editutil/oteditutil.d.ts +0 -14
- package/dist/ot-editutil/otmaputil.d.ts +0 -21
- package/dist/ot-js/all.d.ts +0 -9
- package/dist/ot-js/otarray.d.ts +0 -111
- package/dist/ot-js/otclientengine.d.ts +0 -38
- package/dist/ot-js/otcomposite.d.ts +0 -37
- package/dist/ot-js/otcounter.d.ts +0 -17
- package/dist/ot-js/otengine.d.ts +0 -22
- package/dist/ot-js/otmap.d.ts +0 -19
- package/dist/ot-js/otserverengine.d.ts +0 -38
- package/dist/ot-js/otsession.d.ts +0 -114
- package/dist/ot-js/ottypes.d.ts +0 -29
- package/dist/poly/all.d.ts +0 -15
- package/dist/poly/blend.d.ts +0 -1
- package/dist/poly/boundbox.d.ts +0 -16
- package/dist/poly/cartesian.d.ts +0 -5
- package/dist/poly/graham-scan.d.ts +0 -8
- package/dist/poly/hash.d.ts +0 -1
- package/dist/poly/matrix.d.ts +0 -24
- package/dist/poly/minbound.d.ts +0 -1
- package/dist/poly/poly.d.ts +0 -52
- package/dist/poly/polybin.d.ts +0 -5
- package/dist/poly/polylabel.d.ts +0 -7
- package/dist/poly/polypack.d.ts +0 -30
- package/dist/poly/polyround.d.ts +0 -1
- package/dist/poly/polysimplify.d.ts +0 -1
- package/dist/poly/quad.d.ts +0 -48
- package/dist/poly/selfintersect.d.ts +0 -1
- package/dist/poly/shamos.d.ts +0 -1
- package/dist/poly/simplify.d.ts +0 -2
- package/dist/poly/topo.d.ts +0 -46
- package/dist/poly/union.d.ts +0 -49
- package/dist/util/all.d.ts +0 -5
- package/dist/util/bintrie.d.ts +0 -93
- package/dist/util/countedhash.d.ts +0 -19
- package/dist/util/gradient.d.ts +0 -15
- package/dist/util/indexedarray.d.ts +0 -15
- package/dist/util/util.d.ts +0 -68
- package/docs/context.md +0 -2
- package/docs/filterexpr.md +0 -22
- package/docs/fsm.md +0 -243
- package/docs/logabstract.md +0 -2
- package/docs/logclient.md +0 -2
- package/docs/ot-editutil.md +0 -2
- package/docs/ot-js.md +0 -95
- package/docs/poly.md +0 -103
- package/docs/util.md +0 -2
- package/lib/all/all.ts +0 -21
- package/lib/context/all.ts +0 -1
- package/lib/context/context.ts +0 -82
- package/lib/filterexpr/all.ts +0 -1
- package/lib/filterexpr/filterexpr.ts +0 -699
- package/lib/fsm/all.ts +0 -1
- package/lib/fsm/fsm.ts +0 -559
- package/lib/geo/all.ts +0 -2
- package/lib/geo/geo.ts +0 -452
- package/lib/geo/vfeature.ts +0 -34
- package/lib/logabstract/all.ts +0 -1
- package/lib/logabstract/log.ts +0 -55
- package/lib/logclient/all.ts +0 -1
- package/lib/logclient/log.ts +0 -105
- package/lib/ot-editutil/all.ts +0 -2
- package/lib/ot-editutil/oteditutil.ts +0 -180
- package/lib/ot-editutil/otmaputil.ts +0 -209
- package/lib/ot-js/all.ts +0 -9
- package/lib/ot-js/otarray.ts +0 -1168
- package/lib/ot-js/otclientengine.ts +0 -327
- package/lib/ot-js/otcomposite.ts +0 -247
- package/lib/ot-js/otcounter.ts +0 -145
- package/lib/ot-js/otengine.ts +0 -71
- package/lib/ot-js/otmap.ts +0 -144
- package/lib/ot-js/otserverengine.ts +0 -329
- package/lib/ot-js/otsession.ts +0 -202
- package/lib/ot-js/ottypes.ts +0 -98
- package/lib/poly/all.ts +0 -15
- package/lib/poly/blend.ts +0 -27
- package/lib/poly/boundbox.ts +0 -102
- package/lib/poly/cartesian.ts +0 -130
- package/lib/poly/graham-scan.ts +0 -401
- package/lib/poly/hash.ts +0 -15
- package/lib/poly/matrix.ts +0 -309
- package/lib/poly/minbound.ts +0 -211
- package/lib/poly/poly.ts +0 -767
- package/lib/poly/polybin.ts +0 -218
- package/lib/poly/polylabel.ts +0 -204
- package/lib/poly/polypack.ts +0 -468
- package/lib/poly/polyround.ts +0 -30
- package/lib/poly/polysimplify.ts +0 -24
- package/lib/poly/quad.ts +0 -272
- package/lib/poly/selfintersect.ts +0 -87
- package/lib/poly/shamos.ts +0 -297
- package/lib/poly/simplify.ts +0 -119
- package/lib/poly/topo.ts +0 -499
- package/lib/poly/union.ts +0 -388
- package/lib/util/all.ts +0 -5
- package/lib/util/bintrie.ts +0 -603
- package/lib/util/countedhash.ts +0 -83
- package/lib/util/gradient.ts +0 -108
- package/lib/util/indexedarray.ts +0 -80
- package/lib/util/util.ts +0 -695
package/lib/util/bintrie.ts
DELETED
|
@@ -1,603 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Packed format Trie for mapping string to string
|
|
3
|
-
// Assumptions:
|
|
4
|
-
// 1. Lots of duplicate prefix strings in keys (so branching in trie happens late).
|
|
5
|
-
// 2. Lots of duplicate prefix strings in values.
|
|
6
|
-
// 3. Lots of keys with duplicate prefix map to the same string value.
|
|
7
|
-
// Especially good for something like our blockmapping.json file since both the keys (blockIDs)
|
|
8
|
-
// and values (precinct IDs) have a ton of redundancy and ~250 avg keys (blockID) map to same
|
|
9
|
-
// precinctID.
|
|
10
|
-
// The packed structure is just read directly into memory and walked in packed format.
|
|
11
|
-
|
|
12
|
-
// The structure is divided into two pieces, a node "tree" (flat n-ary trie with offsets
|
|
13
|
-
// to next nodes) and a value table. A value is a pair of string fragment offsets.
|
|
14
|
-
//
|
|
15
|
-
// Main header is:
|
|
16
|
-
// value table offset (32 bit value)
|
|
17
|
-
// [ node table ]
|
|
18
|
-
// [ value table ]
|
|
19
|
-
|
|
20
|
-
// A tree node is:
|
|
21
|
-
// node length / value - (length of byte and node offset table)
|
|
22
|
-
// [ bytes ]* (padded to 4)
|
|
23
|
-
// [ node or value offset ]* (32 bit signed values, negative values are value table refs)
|
|
24
|
-
//
|
|
25
|
-
// We just do a linear scan through the bytes since we assume many will only have a single child,
|
|
26
|
-
// max ~15.
|
|
27
|
-
// The byte array contains the next byte to match, the node offset is the respective next node.
|
|
28
|
-
// A negative node offset is the actual value.
|
|
29
|
-
//
|
|
30
|
-
// A value is an entry in the value table. It is:
|
|
31
|
-
// fragment offset 1 (from start of value table) (offset zero means null, not a legal offset)
|
|
32
|
-
// fragment offset 2 (from start of value table)
|
|
33
|
-
//
|
|
34
|
-
// where a fragment is:
|
|
35
|
-
// length (byte)
|
|
36
|
-
// [ bytes ]*
|
|
37
|
-
//
|
|
38
|
-
// value table is:
|
|
39
|
-
// number of pairs (32 bit value)
|
|
40
|
-
// [ fragment offset pairs ]*
|
|
41
|
-
// [ fragment values ]*
|
|
42
|
-
|
|
43
|
-
export interface Coder
|
|
44
|
-
{
|
|
45
|
-
encoder: { encode: (s: string) => Uint8Array };
|
|
46
|
-
decoder: { decode: (u8: Uint8Array) => string };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/*
|
|
50
|
-
-- For Node
|
|
51
|
-
import * as u from 'util';
|
|
52
|
-
Util.setCoder({ encoder: new u.TextEncoder(), decoder: new u.TextDecoder('utf-8') });
|
|
53
|
-
|
|
54
|
-
-- For Browser
|
|
55
|
-
Util.setCoder({ encoder: new TextEncoder(), decoder: new TextDecoder('utf-8') });
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
export function s2u8(coder: Coder, s: string): Uint8Array
|
|
59
|
-
{
|
|
60
|
-
return coder.encoder.encode(s);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export function u82s(coder: Coder, u8: Uint8Array, offset: number, n: number): string
|
|
64
|
-
{
|
|
65
|
-
return coder.decoder.decode(u8.subarray(offset, offset+n));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// String table algorithm:
|
|
69
|
-
// For each string, divide into fragments of n to 3 bytes
|
|
70
|
-
// Allocate an occurence for each fragment.
|
|
71
|
-
// Sort the fragments by number of occurrences.
|
|
72
|
-
// For each string, pick fragmentation that maximizes occurrence count and mark
|
|
73
|
-
// fragmentation as "in use"
|
|
74
|
-
|
|
75
|
-
interface Fragment
|
|
76
|
-
{
|
|
77
|
-
count: number;
|
|
78
|
-
used: number;
|
|
79
|
-
offset: number;
|
|
80
|
-
s: string;
|
|
81
|
-
u8?: Uint8Array;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
type FragmentTable = { [frag: string]: Fragment };
|
|
85
|
-
type FragmentPair = { f1: Fragment, f2: Fragment, offset?: number };
|
|
86
|
-
const NullFragment = { count: 0, used: 0, offset: 0, s: '' };
|
|
87
|
-
|
|
88
|
-
function sortBestPair(p1: FragmentPair, p2: FragmentPair): number
|
|
89
|
-
{
|
|
90
|
-
let d = (p1.f1.count+p1.f2.count) - (p2.f1.count+p2.f2.count);
|
|
91
|
-
if (d) return d;
|
|
92
|
-
d = (p1.f1.used + p1.f2.used) - (p2.f1.used+p2.f2.used);
|
|
93
|
-
return d;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function unique(a: string[]): string[]
|
|
97
|
-
{
|
|
98
|
-
a = a.slice().sort();
|
|
99
|
-
return a.filter((s: string, i: number) => { return i == 0 || s !== a[i-1] });
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
class ValueTable
|
|
103
|
-
{
|
|
104
|
-
coder: Coder;
|
|
105
|
-
ab: ArrayBuffer;
|
|
106
|
-
u8: Uint8Array;
|
|
107
|
-
u32: Uint32Array;
|
|
108
|
-
|
|
109
|
-
constructor(coder: Coder) { this.coder = coder }
|
|
110
|
-
|
|
111
|
-
static fromBuffer(coder: Coder, ab: ArrayBuffer, offset: number, length: number): ValueTable
|
|
112
|
-
{
|
|
113
|
-
let vt = new ValueTable(coder);
|
|
114
|
-
vt.ab = ab;
|
|
115
|
-
vt.u8 = new Uint8Array(ab, offset, length);
|
|
116
|
-
let u32 = new Uint32Array(ab, offset, 1);
|
|
117
|
-
let n = u32[0];
|
|
118
|
-
vt.u32 = new Uint32Array(ab, offset, 1+2*n);
|
|
119
|
-
return vt;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Returns string given offset into value table
|
|
123
|
-
fromOffset(offset: number): string
|
|
124
|
-
{
|
|
125
|
-
let o1 = this.u32[offset];
|
|
126
|
-
let o2 = this.u32[offset+1];
|
|
127
|
-
let n = 0;
|
|
128
|
-
if (o1) n += this.u8[o1];
|
|
129
|
-
if (o2) n += this.u8[o2];
|
|
130
|
-
let ab = new ArrayBuffer(n);
|
|
131
|
-
let u8 = new Uint8Array(ab);
|
|
132
|
-
n = this.u8[o1];
|
|
133
|
-
let j = 0;
|
|
134
|
-
while (j < n) u8[j++] = this.u8[++o1];
|
|
135
|
-
n = this.u8[o2];
|
|
136
|
-
let k = 0;
|
|
137
|
-
while (k < n) k++, u8[j++] = this.u8[++o2];
|
|
138
|
-
return u82s(this.coder, u8, 0, j);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
class ValueTableBuilder
|
|
143
|
-
{
|
|
144
|
-
coder: Coder;
|
|
145
|
-
values: string[];
|
|
146
|
-
fragments: FragmentTable;
|
|
147
|
-
pairs: { [value: string]: FragmentPair };
|
|
148
|
-
ab: ArrayBuffer;
|
|
149
|
-
u8: Uint8Array;
|
|
150
|
-
u32: Uint32Array;
|
|
151
|
-
|
|
152
|
-
constructor(coder: Coder) { this.coder = coder }
|
|
153
|
-
|
|
154
|
-
// Building
|
|
155
|
-
static fromStrings(coder: Coder, values: string[]): ValueTableBuilder
|
|
156
|
-
{
|
|
157
|
-
let nc = 0;
|
|
158
|
-
values.forEach(s => nc += s.length);
|
|
159
|
-
//console.log(`bintrie: ValueTable: ${values.length} initial values, ${nc} initial char count`);
|
|
160
|
-
values = unique(values);
|
|
161
|
-
//console.log(`bintrie: ValueTable: ${values.length} unique values`);
|
|
162
|
-
let vtb = new ValueTableBuilder(coder);
|
|
163
|
-
vtb.values = values;
|
|
164
|
-
vtb.fragments = {};
|
|
165
|
-
vtb.pairs = {};
|
|
166
|
-
values.forEach(s => vtb.extractFragments(s));
|
|
167
|
-
values.forEach(s => vtb.pickFragments(s));
|
|
168
|
-
//console.log(`bintrie: ValueTable: ${Object.keys(vtb.fragments).length} initial fragments`);
|
|
169
|
-
Object.keys(vtb.fragments).forEach(s => { if (! vtb.fragments[s].used) delete vtb.fragments[s] });
|
|
170
|
-
//console.log(`bintrie: ValueTable: ${Object.keys(vtb.fragments).length} final fragments`);
|
|
171
|
-
vtb.toBinary();
|
|
172
|
-
vtb.validateStrings(values);
|
|
173
|
-
//console.log(`bintrie: ValueTable: ${vtb.u8.length} final byte length`);
|
|
174
|
-
return vtb;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Validation
|
|
178
|
-
validateStrings(values: string[]): void
|
|
179
|
-
{
|
|
180
|
-
let vt = ValueTable.fromBuffer(this.coder, this.ab, 0, this.ab.byteLength);
|
|
181
|
-
let orig = values.slice().sort();
|
|
182
|
-
let here: string[] = [];
|
|
183
|
-
let n = this.u32[0];
|
|
184
|
-
for (let i = 0; i < n; i++)
|
|
185
|
-
here.push(vt.fromOffset(i*2+1));
|
|
186
|
-
here.sort();
|
|
187
|
-
for (let i = 0; i < here.length; i++)
|
|
188
|
-
if (orig[i] !== here[i])
|
|
189
|
-
{
|
|
190
|
-
console.error('ValueTable: content mismatch');
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Building
|
|
196
|
-
addFragment(s: string): void
|
|
197
|
-
{
|
|
198
|
-
let f = this.fragments[s];
|
|
199
|
-
if (f === undefined)
|
|
200
|
-
f = { count: 0, used: 0, s: s, offset: 0, u8: s2u8(this.coder, s) }, this.fragments[s] = f;
|
|
201
|
-
f.count++;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Building
|
|
205
|
-
extractFragments(s: string): void
|
|
206
|
-
{
|
|
207
|
-
let n = s.length;
|
|
208
|
-
if (n < 6)
|
|
209
|
-
this.addFragment(s);
|
|
210
|
-
else
|
|
211
|
-
for (let j = 3; j < n-2; j++)
|
|
212
|
-
{
|
|
213
|
-
this.addFragment(s.substring(0, j));
|
|
214
|
-
this.addFragment(s.substring(j));
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Building
|
|
219
|
-
pickFragments(s: string): void
|
|
220
|
-
{
|
|
221
|
-
let a: { f1: Fragment, f2: Fragment }[] = [];
|
|
222
|
-
let n = s.length;
|
|
223
|
-
if (n < 6)
|
|
224
|
-
a.push({ f1: this.fragments[s], f2: NullFragment });
|
|
225
|
-
else
|
|
226
|
-
for (let j = 3; j < n-2; j++)
|
|
227
|
-
a.push({ f1: this.fragments[s.substring(0, j)], f2: this.fragments[s.substring(j)] });
|
|
228
|
-
a.sort(sortBestPair);
|
|
229
|
-
let p = a[0];
|
|
230
|
-
p.f1.used = 1;
|
|
231
|
-
p.f2.used = 1;
|
|
232
|
-
this.pairs[s] = p;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Building
|
|
236
|
-
toOffset(s: string): number
|
|
237
|
-
{
|
|
238
|
-
return this.pairs[s].offset;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Building
|
|
242
|
-
toBinary(): void
|
|
243
|
-
{
|
|
244
|
-
let byteLength = 0;
|
|
245
|
-
byteLength += (this.values.length * 2 * 4) + 4;
|
|
246
|
-
let keys = Object.keys(this.fragments);
|
|
247
|
-
keys.forEach(s => {
|
|
248
|
-
let f = this.fragments[s];
|
|
249
|
-
f.offset = byteLength;
|
|
250
|
-
byteLength += f.u8.byteLength + 1;
|
|
251
|
-
});
|
|
252
|
-
this.ab = new ArrayBuffer(byteLength);
|
|
253
|
-
this.u8 = new Uint8Array(this.ab);
|
|
254
|
-
this.u32 = new Uint32Array(this.ab, 0, this.values.length*2+1);
|
|
255
|
-
let pOffset = 0;
|
|
256
|
-
this.u32[pOffset++] = this.values.length;
|
|
257
|
-
this.values.forEach(s => {
|
|
258
|
-
let p = this.pairs[s];
|
|
259
|
-
p.offset = pOffset;
|
|
260
|
-
this.u32[pOffset++] = p.f1.offset;
|
|
261
|
-
this.u32[pOffset++] = p.f2.offset;
|
|
262
|
-
});
|
|
263
|
-
let fOffset = (this.values.length * 2 * 4) + 4;
|
|
264
|
-
keys.forEach(s => {
|
|
265
|
-
let f = this.fragments[s];
|
|
266
|
-
this.u8[fOffset++] = f.u8.length;
|
|
267
|
-
for (let i = 0; i < f.u8.length; i++)
|
|
268
|
-
this.u8[fOffset++] = f.u8[i];
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
export type StringMap = { [key: string]: string };
|
|
274
|
-
|
|
275
|
-
// Building
|
|
276
|
-
interface UnpackedNode
|
|
277
|
-
{
|
|
278
|
-
// This for leaf node
|
|
279
|
-
suffix: Uint8Array;
|
|
280
|
-
value: number;
|
|
281
|
-
|
|
282
|
-
// This for internal node
|
|
283
|
-
bytes: number[] | null;
|
|
284
|
-
nodes: UnpackedNode[] | null;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function pad(n: number, pad: number): number { let mod = n % pad; return mod ? pad - mod : 0; }
|
|
288
|
-
function pad4(n: number): number { return pad(n, 4) }
|
|
289
|
-
|
|
290
|
-
export class BinTrie
|
|
291
|
-
{
|
|
292
|
-
coder: Coder;
|
|
293
|
-
ab: ArrayBuffer;
|
|
294
|
-
vt: ValueTable;
|
|
295
|
-
u8: Uint8Array;
|
|
296
|
-
i32: Int32Array;
|
|
297
|
-
|
|
298
|
-
constructor(coder: Coder)
|
|
299
|
-
{
|
|
300
|
-
this.coder = coder;
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
static fromBuffer(coder: Coder, ab: ArrayBuffer): BinTrie
|
|
304
|
-
{
|
|
305
|
-
let bt = new BinTrie(coder);
|
|
306
|
-
bt.ab = ab;
|
|
307
|
-
bt.u8 = new Uint8Array(bt.ab);
|
|
308
|
-
let i32 = new Int32Array(bt.ab, 0, 1);
|
|
309
|
-
let valueOffset = i32[0];
|
|
310
|
-
bt.i32 = new Int32Array(bt.ab, 0, valueOffset >> 2);
|
|
311
|
-
bt.vt = ValueTable.fromBuffer(coder, bt.ab, valueOffset, bt.u8.length - valueOffset);
|
|
312
|
-
return bt;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
get(key: string): string
|
|
316
|
-
{
|
|
317
|
-
let u8 = s2u8(this.coder, key);
|
|
318
|
-
let byteOffset = 4;
|
|
319
|
-
for (let i = 0; i <= u8.length; i++)
|
|
320
|
-
{
|
|
321
|
-
let iOffset = byteOffset >> 2;
|
|
322
|
-
let n = this.i32[iOffset];
|
|
323
|
-
if (i == u8.length)
|
|
324
|
-
return undefined;
|
|
325
|
-
let b = u8[i];
|
|
326
|
-
byteOffset += 4;
|
|
327
|
-
let j: number;
|
|
328
|
-
for (j = 0; j < n; j++)
|
|
329
|
-
if (this.u8[byteOffset+j] === b)
|
|
330
|
-
{
|
|
331
|
-
byteOffset += n + pad4(n); // move past byte table
|
|
332
|
-
iOffset = byteOffset >> 2; // convert ioffset to that location
|
|
333
|
-
iOffset += j; // index intoo node offset table
|
|
334
|
-
byteOffset = this.i32[iOffset]; // and move to child node
|
|
335
|
-
if (byteOffset < 0)
|
|
336
|
-
return this.vt.fromOffset(-byteOffset);
|
|
337
|
-
break;
|
|
338
|
-
}
|
|
339
|
-
if (j === n)
|
|
340
|
-
return undefined;
|
|
341
|
-
}
|
|
342
|
-
return undefined;
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
export class BinTrieBuilder
|
|
347
|
-
{
|
|
348
|
-
coder: Coder;
|
|
349
|
-
root: UnpackedNode;
|
|
350
|
-
vtb: ValueTableBuilder;
|
|
351
|
-
vt: ValueTable;
|
|
352
|
-
ab: ArrayBuffer;
|
|
353
|
-
u8: Uint8Array;
|
|
354
|
-
i32: Int32Array;
|
|
355
|
-
|
|
356
|
-
constructor(coder: Coder)
|
|
357
|
-
{
|
|
358
|
-
this.coder = coder;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Building
|
|
362
|
-
nodeCount(node: UnpackedNode): number
|
|
363
|
-
{
|
|
364
|
-
let n = 1;
|
|
365
|
-
if (node.nodes)
|
|
366
|
-
node.nodes.forEach(child => n += this.nodeCount(child))
|
|
367
|
-
return n;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
// Validation
|
|
371
|
-
nodeBranching(node: UnpackedNode, counts: number[]): number
|
|
372
|
-
{
|
|
373
|
-
let n = node.nodes ? node.nodes.length : 0;
|
|
374
|
-
counts[n] = counts[n] === undefined ? 1 : counts[n]+1;
|
|
375
|
-
if (node.nodes)
|
|
376
|
-
node.nodes.forEach(child => n += this.nodeBranching(child, counts))
|
|
377
|
-
return n;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
// Validation
|
|
381
|
-
nodeValueCount(node: UnpackedNode): number
|
|
382
|
-
{
|
|
383
|
-
let n = node.value ? 1 : 0;
|
|
384
|
-
if (node.nodes)
|
|
385
|
-
node.nodes.forEach(child => n += this.nodeValueCount(child))
|
|
386
|
-
return n;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Building
|
|
390
|
-
nodeByteLength(node: UnpackedNode): number
|
|
391
|
-
{
|
|
392
|
-
let byteLength = 0; // length of child arrays
|
|
393
|
-
if (node.nodes)
|
|
394
|
-
{
|
|
395
|
-
byteLength += 4; // length of child arrays
|
|
396
|
-
byteLength += node.bytes.length + pad4(node.bytes.length);
|
|
397
|
-
byteLength += node.nodes.length * 4;
|
|
398
|
-
node.nodes.forEach(n => { byteLength += this.nodeByteLength(n) });
|
|
399
|
-
}
|
|
400
|
-
return byteLength;
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Building
|
|
404
|
-
addString(s: string, value: number): void
|
|
405
|
-
{
|
|
406
|
-
let u8 = s2u8(this.coder, s);
|
|
407
|
-
if (this.root == null)
|
|
408
|
-
this.root = { suffix: u8, value: value, bytes: null, nodes: null };
|
|
409
|
-
else
|
|
410
|
-
{
|
|
411
|
-
let node = this.root;
|
|
412
|
-
let n = u8.length;
|
|
413
|
-
let j = 0;
|
|
414
|
-
while (j < n)
|
|
415
|
-
{
|
|
416
|
-
// If at leaf node, need to split it
|
|
417
|
-
if (node.bytes == null)
|
|
418
|
-
{
|
|
419
|
-
node.bytes = [ node.suffix[0] ];
|
|
420
|
-
node.nodes = [ { suffix: node.suffix.subarray(1), value: node.value, bytes: null, nodes: null } ];
|
|
421
|
-
node.suffix = null;
|
|
422
|
-
node.value = 0;
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
let k: number;
|
|
426
|
-
for (k = 0; k < node.bytes.length; k++)
|
|
427
|
-
if (node.bytes[k] == u8[j])
|
|
428
|
-
break;
|
|
429
|
-
|
|
430
|
-
if (k < node.bytes.length)
|
|
431
|
-
{
|
|
432
|
-
node = node.nodes[k];
|
|
433
|
-
j++;
|
|
434
|
-
}
|
|
435
|
-
else
|
|
436
|
-
{
|
|
437
|
-
node.bytes.push(u8[j++]);
|
|
438
|
-
let nNew: UnpackedNode = { suffix: u8.subarray(j), value: value, bytes: null, nodes: null };
|
|
439
|
-
node.nodes.push(nNew);
|
|
440
|
-
node = nNew;
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Building
|
|
447
|
-
dedup(node: UnpackedNode): void
|
|
448
|
-
{
|
|
449
|
-
// If all subnodes point to the same value, we can just turn this node into a value node
|
|
450
|
-
if (node.nodes)
|
|
451
|
-
{
|
|
452
|
-
node.nodes.forEach(n => this.dedup(n));
|
|
453
|
-
let value = node.nodes[0].value;
|
|
454
|
-
if (value)
|
|
455
|
-
{
|
|
456
|
-
node.nodes.forEach(n => { if (n.value != value) value = 0 });
|
|
457
|
-
if (value)
|
|
458
|
-
{
|
|
459
|
-
node.value = value;
|
|
460
|
-
delete node.nodes;
|
|
461
|
-
delete node.bytes;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
// Validation
|
|
468
|
-
getUnpacked(key: string): string
|
|
469
|
-
{
|
|
470
|
-
function getFromNode(vt: ValueTable, node: UnpackedNode, u8: Uint8Array, offset: number): string
|
|
471
|
-
{
|
|
472
|
-
if (node.value)
|
|
473
|
-
return vt.fromOffset(node.value);
|
|
474
|
-
else
|
|
475
|
-
{
|
|
476
|
-
if (offset >= u8.length)
|
|
477
|
-
{
|
|
478
|
-
console.error('bintrie: failure during lookup in unpacked format');
|
|
479
|
-
return 'undefined';
|
|
480
|
-
}
|
|
481
|
-
let j = node.bytes.findIndex(e => e === u8[offset]);
|
|
482
|
-
if (j === undefined)
|
|
483
|
-
{
|
|
484
|
-
console.error('bintrie: failure during lookup in unpacked format');
|
|
485
|
-
return 'undefined';
|
|
486
|
-
}
|
|
487
|
-
return getFromNode(vt, node.nodes[j], u8, offset+1);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
return getFromNode(this.vt, this.root, s2u8(this.coder, key), 0);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
// Building
|
|
495
|
-
packNode(node: UnpackedNode, byteOffset: number): number
|
|
496
|
-
{
|
|
497
|
-
if (node.nodes)
|
|
498
|
-
{
|
|
499
|
-
let i;
|
|
500
|
-
let iOffset = byteOffset >> 2;
|
|
501
|
-
this.i32[iOffset] = node.nodes.length;
|
|
502
|
-
byteOffset += 4;
|
|
503
|
-
for (i = 0; i < node.bytes.length; i++)
|
|
504
|
-
this.u8[byteOffset++] = node.bytes[i];
|
|
505
|
-
byteOffset += pad4(byteOffset);
|
|
506
|
-
iOffset = byteOffset >> 2;
|
|
507
|
-
byteOffset += node.nodes.length * 4;
|
|
508
|
-
for (i = 0; i < node.nodes.length; i++)
|
|
509
|
-
{
|
|
510
|
-
let n = node.nodes[i];
|
|
511
|
-
if (n.value)
|
|
512
|
-
this.i32[iOffset++] = - n.value;
|
|
513
|
-
else
|
|
514
|
-
{
|
|
515
|
-
this.i32[iOffset++] = byteOffset;
|
|
516
|
-
byteOffset = this.packNode(n, byteOffset);
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
return byteOffset;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
// Building
|
|
524
|
-
toBinary(): void
|
|
525
|
-
{
|
|
526
|
-
let byteLength = 4 + this.nodeByteLength(this.root);
|
|
527
|
-
let valueOffset = byteLength;
|
|
528
|
-
byteLength += this.vtb.u8.length;
|
|
529
|
-
this.ab = new ArrayBuffer(byteLength);
|
|
530
|
-
this.u8 = new Uint8Array(this.ab);
|
|
531
|
-
this.i32 = new Int32Array(this.ab, 0, valueOffset >> 2);
|
|
532
|
-
this.i32[0] = valueOffset;
|
|
533
|
-
let byteOffset = this.packNode(this.root, 4);
|
|
534
|
-
if (byteOffset != valueOffset)
|
|
535
|
-
throw 'unexpected result from packNode';
|
|
536
|
-
|
|
537
|
-
// Now copy in ValueTable
|
|
538
|
-
let u8 = this.vtb.u8;
|
|
539
|
-
let n = u8.length;
|
|
540
|
-
for (let j = 0, k = valueOffset; j < n; j++, k++)
|
|
541
|
-
this.u8[k] = u8[j];
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
// Building
|
|
545
|
-
static fromMap(coder: Coder, o: StringMap): BinTrie
|
|
546
|
-
{
|
|
547
|
-
let btb = new BinTrieBuilder(coder);
|
|
548
|
-
btb.vtb = ValueTableBuilder.fromStrings(coder, Object.values(o));
|
|
549
|
-
btb.vt = ValueTable.fromBuffer(coder, btb.vtb.ab, 0, btb.vtb.ab.byteLength);
|
|
550
|
-
let keys = Object.keys(o);
|
|
551
|
-
keys.forEach(s => btb.addString(s, btb.vtb.toOffset(o[s])));
|
|
552
|
-
|
|
553
|
-
//console.log(`bintrie: initial node count: ${btb.nodeCount(btb.root)}`);
|
|
554
|
-
|
|
555
|
-
// validate
|
|
556
|
-
let good = true;
|
|
557
|
-
keys.forEach(k => {
|
|
558
|
-
if (good && btb.getUnpacked(k) !== o[k])
|
|
559
|
-
{
|
|
560
|
-
//console.error('bintrie: missing key in unpacked, un-deduped tree');
|
|
561
|
-
good = false;
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
|
|
565
|
-
// dedup (collapse branches pointing to same value)
|
|
566
|
-
btb.dedup(btb.root);
|
|
567
|
-
|
|
568
|
-
// validate
|
|
569
|
-
keys.forEach(k => {
|
|
570
|
-
if (good && btb.getUnpacked(k) !== o[k])
|
|
571
|
-
{
|
|
572
|
-
//console.error('bintrie: missing key in unpacked, deduped tree');
|
|
573
|
-
good = false;
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
|
|
577
|
-
//console.log(`bintrie: final node count after dedup: ${btb.nodeCount(btb.root)}`);
|
|
578
|
-
//console.log(`bintrie: value nodes after dedup: ${btb.nodeValueCount(btb.root)}`);
|
|
579
|
-
let counts: number[] = [];
|
|
580
|
-
//console.log(`bintrie: singleton nodes after dedup: ${btb.nodeBranching(btb.root, counts)}`);
|
|
581
|
-
counts.forEach((count: number, i: number) => {
|
|
582
|
-
//if (count !== undefined)
|
|
583
|
-
//console.log(`bintrie: branch factor: ${i}, count: ${count}`);
|
|
584
|
-
});
|
|
585
|
-
|
|
586
|
-
btb.toBinary();
|
|
587
|
-
|
|
588
|
-
let bt = BinTrie.fromBuffer(coder, btb.ab);
|
|
589
|
-
|
|
590
|
-
// validate
|
|
591
|
-
keys.forEach((k: string, i: number) => {
|
|
592
|
-
if (good && bt.get(k) !== o[k])
|
|
593
|
-
{
|
|
594
|
-
console.error(`bintrie: missing key (${i}th) in packed structure`);
|
|
595
|
-
good = false;
|
|
596
|
-
}
|
|
597
|
-
});
|
|
598
|
-
|
|
599
|
-
console.log(`bintrie: total size: ${btb.u8.length}, value table size: ${btb.vtb.u8.length}`);
|
|
600
|
-
|
|
601
|
-
return bt;
|
|
602
|
-
}
|
|
603
|
-
}
|
package/lib/util/countedhash.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
export class CountedHash
|
|
2
|
-
{
|
|
3
|
-
n: number;
|
|
4
|
-
val: { [id: string]: true|null }; // true === isset, null === indeterminant
|
|
5
|
-
|
|
6
|
-
constructor()
|
|
7
|
-
{
|
|
8
|
-
this.n = 0;
|
|
9
|
-
this.val = {};
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
get length(): number { return this.n; }
|
|
13
|
-
|
|
14
|
-
indeterminate(id: string): boolean
|
|
15
|
-
{
|
|
16
|
-
return id != '' && this.val[id] === null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
test(id: string): boolean
|
|
20
|
-
{
|
|
21
|
-
return id != '' && this.val[id] !== undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
set(id: string, val: true|null = true): void
|
|
25
|
-
{
|
|
26
|
-
if (id != '')
|
|
27
|
-
{
|
|
28
|
-
if (! this.test(id))
|
|
29
|
-
this.n++;
|
|
30
|
-
this.val[id] = val;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
clear(id: string): void
|
|
35
|
-
{
|
|
36
|
-
if (this.test(id))
|
|
37
|
-
{
|
|
38
|
-
this.n--;
|
|
39
|
-
delete this.val[id];
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
apply(vals: { [id: string]: boolean|null }): void
|
|
44
|
-
{
|
|
45
|
-
this.empty();
|
|
46
|
-
|
|
47
|
-
if (vals)
|
|
48
|
-
Object.keys(vals).forEach((id) => {
|
|
49
|
-
if (vals[id] !== false)
|
|
50
|
-
this.set(id, vals[id] === true ? true : null);
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
empty(): void
|
|
55
|
-
{
|
|
56
|
-
this.n = 0;
|
|
57
|
-
this.val = {};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
asArray(): string[]
|
|
61
|
-
{
|
|
62
|
-
let a: string[] = [];
|
|
63
|
-
|
|
64
|
-
this.forEach(id => { a.push(id) });
|
|
65
|
-
|
|
66
|
-
return a;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// This really only useful when length === 0|1
|
|
70
|
-
asString(): string
|
|
71
|
-
{
|
|
72
|
-
for (var id in this.val) if (this.val.hasOwnProperty(id))
|
|
73
|
-
return id;
|
|
74
|
-
|
|
75
|
-
return '';
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
forEach(f: (id: string) => void): void
|
|
79
|
-
{
|
|
80
|
-
for (var id in this.val) if (this.val.hasOwnProperty(id))
|
|
81
|
-
f(id);
|
|
82
|
-
}
|
|
83
|
-
}
|