mongodb-livedata-server 0.0.1
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 +63 -0
- package/dist/livedata_server.js +9 -0
- package/dist/meteor/binary-heap/max_heap.js +186 -0
- package/dist/meteor/binary-heap/min_heap.js +17 -0
- package/dist/meteor/binary-heap/min_max_heap.js +48 -0
- package/dist/meteor/callback-hook/hook.js +78 -0
- package/dist/meteor/ddp/crossbar.js +136 -0
- package/dist/meteor/ddp/heartbeat.js +77 -0
- package/dist/meteor/ddp/livedata_server.js +403 -0
- package/dist/meteor/ddp/method-invocation.js +72 -0
- package/dist/meteor/ddp/random-stream.js +100 -0
- package/dist/meteor/ddp/session-collection-view.js +106 -0
- package/dist/meteor/ddp/session-document-view.js +82 -0
- package/dist/meteor/ddp/session.js +570 -0
- package/dist/meteor/ddp/stream_server.js +181 -0
- package/dist/meteor/ddp/subscription.js +347 -0
- package/dist/meteor/ddp/utils.js +104 -0
- package/dist/meteor/ddp/writefence.js +111 -0
- package/dist/meteor/diff-sequence/diff.js +257 -0
- package/dist/meteor/ejson/ejson.js +569 -0
- package/dist/meteor/ejson/stringify.js +119 -0
- package/dist/meteor/ejson/utils.js +42 -0
- package/dist/meteor/id-map/id_map.js +92 -0
- package/dist/meteor/mongo/caching_change_observer.js +94 -0
- package/dist/meteor/mongo/doc_fetcher.js +53 -0
- package/dist/meteor/mongo/geojson_utils.js +41 -0
- package/dist/meteor/mongo/live_connection.js +264 -0
- package/dist/meteor/mongo/live_cursor.js +57 -0
- package/dist/meteor/mongo/minimongo_common.js +2002 -0
- package/dist/meteor/mongo/minimongo_matcher.js +217 -0
- package/dist/meteor/mongo/minimongo_sorter.js +268 -0
- package/dist/meteor/mongo/observe_driver_utils.js +73 -0
- package/dist/meteor/mongo/observe_multiplexer.js +228 -0
- package/dist/meteor/mongo/oplog-observe-driver.js +919 -0
- package/dist/meteor/mongo/oplog_tailing.js +352 -0
- package/dist/meteor/mongo/oplog_v2_converter.js +126 -0
- package/dist/meteor/mongo/polling_observe_driver.js +195 -0
- package/dist/meteor/mongo/synchronous-cursor.js +261 -0
- package/dist/meteor/mongo/synchronous-queue.js +110 -0
- package/dist/meteor/ordered-dict/ordered_dict.js +198 -0
- package/dist/meteor/random/AbstractRandomGenerator.js +92 -0
- package/dist/meteor/random/AleaRandomGenerator.js +90 -0
- package/dist/meteor/random/NodeRandomGenerator.js +42 -0
- package/dist/meteor/random/createAleaGenerator.js +32 -0
- package/dist/meteor/random/createRandom.js +22 -0
- package/dist/meteor/random/main.js +12 -0
- package/livedata_server.ts +3 -0
- package/meteor/LICENSE +28 -0
- package/meteor/binary-heap/max_heap.ts +225 -0
- package/meteor/binary-heap/min_heap.ts +15 -0
- package/meteor/binary-heap/min_max_heap.ts +53 -0
- package/meteor/callback-hook/hook.ts +85 -0
- package/meteor/ddp/crossbar.ts +148 -0
- package/meteor/ddp/heartbeat.ts +97 -0
- package/meteor/ddp/livedata_server.ts +473 -0
- package/meteor/ddp/method-invocation.ts +86 -0
- package/meteor/ddp/random-stream.ts +102 -0
- package/meteor/ddp/session-collection-view.ts +119 -0
- package/meteor/ddp/session-document-view.ts +92 -0
- package/meteor/ddp/session.ts +708 -0
- package/meteor/ddp/stream_server.ts +204 -0
- package/meteor/ddp/subscription.ts +392 -0
- package/meteor/ddp/utils.ts +119 -0
- package/meteor/ddp/writefence.ts +130 -0
- package/meteor/diff-sequence/diff.ts +295 -0
- package/meteor/ejson/ejson.ts +601 -0
- package/meteor/ejson/stringify.ts +122 -0
- package/meteor/ejson/utils.ts +38 -0
- package/meteor/id-map/id_map.ts +84 -0
- package/meteor/mongo/caching_change_observer.ts +120 -0
- package/meteor/mongo/doc_fetcher.ts +52 -0
- package/meteor/mongo/geojson_utils.ts +42 -0
- package/meteor/mongo/live_connection.ts +302 -0
- package/meteor/mongo/live_cursor.ts +79 -0
- package/meteor/mongo/minimongo_common.ts +2440 -0
- package/meteor/mongo/minimongo_matcher.ts +275 -0
- package/meteor/mongo/minimongo_sorter.ts +331 -0
- package/meteor/mongo/observe_driver_utils.ts +79 -0
- package/meteor/mongo/observe_multiplexer.ts +256 -0
- package/meteor/mongo/oplog-observe-driver.ts +1049 -0
- package/meteor/mongo/oplog_tailing.ts +414 -0
- package/meteor/mongo/oplog_v2_converter.ts +124 -0
- package/meteor/mongo/polling_observe_driver.ts +247 -0
- package/meteor/mongo/synchronous-cursor.ts +293 -0
- package/meteor/mongo/synchronous-queue.ts +119 -0
- package/meteor/ordered-dict/ordered_dict.ts +229 -0
- package/meteor/random/AbstractRandomGenerator.ts +99 -0
- package/meteor/random/AleaRandomGenerator.ts +96 -0
- package/meteor/random/NodeRandomGenerator.ts +37 -0
- package/meteor/random/createAleaGenerator.ts +31 -0
- package/meteor/random/createRandom.ts +19 -0
- package/meteor/random/main.ts +8 -0
- package/package.json +30 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const AbstractRandomGenerator_1 = __importDefault(require("./AbstractRandomGenerator"));
|
|
7
|
+
// Alea PRNG, which is not cryptographically strong
|
|
8
|
+
// see http://baagoe.org/en/wiki/Better_random_numbers_for_javascript
|
|
9
|
+
// for a full discussion and Alea implementation.
|
|
10
|
+
function Alea(seeds) {
|
|
11
|
+
function Mash() {
|
|
12
|
+
let n = 0xefc8249d;
|
|
13
|
+
const mash = (data) => {
|
|
14
|
+
data = data.toString();
|
|
15
|
+
for (let i = 0; i < data.length; i++) {
|
|
16
|
+
n += data.charCodeAt(i);
|
|
17
|
+
let h = 0.02519603282416938 * n;
|
|
18
|
+
n = h >>> 0;
|
|
19
|
+
h -= n;
|
|
20
|
+
h *= n;
|
|
21
|
+
n = h >>> 0;
|
|
22
|
+
h -= n;
|
|
23
|
+
n += h * 0x100000000; // 2^32
|
|
24
|
+
}
|
|
25
|
+
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
|
|
26
|
+
};
|
|
27
|
+
mash.version = 'Mash 0.9';
|
|
28
|
+
return mash;
|
|
29
|
+
}
|
|
30
|
+
let s0 = 0;
|
|
31
|
+
let s1 = 0;
|
|
32
|
+
let s2 = 0;
|
|
33
|
+
let c = 1;
|
|
34
|
+
if (seeds.length === 0) {
|
|
35
|
+
seeds = [+new Date];
|
|
36
|
+
}
|
|
37
|
+
let mash = Mash();
|
|
38
|
+
s0 = mash(' ');
|
|
39
|
+
s1 = mash(' ');
|
|
40
|
+
s2 = mash(' ');
|
|
41
|
+
for (let i = 0; i < seeds.length; i++) {
|
|
42
|
+
s0 -= mash(seeds[i]);
|
|
43
|
+
if (s0 < 0) {
|
|
44
|
+
s0 += 1;
|
|
45
|
+
}
|
|
46
|
+
s1 -= mash(seeds[i]);
|
|
47
|
+
if (s1 < 0) {
|
|
48
|
+
s1 += 1;
|
|
49
|
+
}
|
|
50
|
+
s2 -= mash(seeds[i]);
|
|
51
|
+
if (s2 < 0) {
|
|
52
|
+
s2 += 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
mash = null;
|
|
56
|
+
const random = () => {
|
|
57
|
+
const t = (2091639 * s0) + (c * 2.3283064365386963e-10); // 2^-32
|
|
58
|
+
s0 = s1;
|
|
59
|
+
s1 = s2;
|
|
60
|
+
return s2 = t - (c = t | 0);
|
|
61
|
+
};
|
|
62
|
+
random.uint32 = () => random() * 0x100000000; // 2^32
|
|
63
|
+
random.fract53 = () => random() +
|
|
64
|
+
((random() * 0x200000 | 0) * 1.1102230246251565e-16); // 2^-53
|
|
65
|
+
random.version = 'Alea 0.9';
|
|
66
|
+
random.args = seeds;
|
|
67
|
+
return random;
|
|
68
|
+
}
|
|
69
|
+
// options:
|
|
70
|
+
// - seeds: an array
|
|
71
|
+
// whose items will be `toString`ed and used as the seed to the Alea
|
|
72
|
+
// algorithm
|
|
73
|
+
class AleaRandomGenerator extends AbstractRandomGenerator_1.default {
|
|
74
|
+
constructor({ seeds = [] } = {}) {
|
|
75
|
+
super();
|
|
76
|
+
if (!seeds) {
|
|
77
|
+
throw new Error('No seeds were provided for Alea PRNG');
|
|
78
|
+
}
|
|
79
|
+
this.alea = Alea(seeds);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* @name Random.fraction
|
|
83
|
+
* @summary Return a number between 0 and 1, like `Math.random`.
|
|
84
|
+
* @locus Anywhere
|
|
85
|
+
*/
|
|
86
|
+
fraction() {
|
|
87
|
+
return this.alea();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.default = AleaRandomGenerator;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
7
|
+
const AbstractRandomGenerator_1 = __importDefault(require("./AbstractRandomGenerator"));
|
|
8
|
+
class NodeRandomGenerator extends AbstractRandomGenerator_1.default {
|
|
9
|
+
/**
|
|
10
|
+
* @name Random.fraction
|
|
11
|
+
* @summary Return a number between 0 and 1, like `Math.random`.
|
|
12
|
+
* @locus Anywhere
|
|
13
|
+
*/
|
|
14
|
+
fraction() {
|
|
15
|
+
const numerator = Number.parseInt(this.hexString(8), 16);
|
|
16
|
+
return numerator * 2.3283064365386963e-10; // 2^-3;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* @name Random.hexString
|
|
20
|
+
* @summary Return a random string of `n` hexadecimal digits.
|
|
21
|
+
* @locus Anywhere
|
|
22
|
+
* @param {Number} n Length of the string
|
|
23
|
+
*/
|
|
24
|
+
hexString(digits) {
|
|
25
|
+
const numBytes = Math.ceil(digits / 2);
|
|
26
|
+
let bytes;
|
|
27
|
+
// Try to get cryptographically strong randomness. Fall back to
|
|
28
|
+
// non-cryptographically strong if not available.
|
|
29
|
+
try {
|
|
30
|
+
bytes = crypto_1.default.randomBytes(numBytes);
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
// XXX should re-throw any error except insufficient entropy
|
|
34
|
+
bytes = crypto_1.default.pseudoRandomBytes(numBytes);
|
|
35
|
+
}
|
|
36
|
+
const result = bytes.toString('hex');
|
|
37
|
+
// If the number of digits is odd, we'll have generated an extra 4 bits
|
|
38
|
+
// of randomness, so we need to trim the last digit.
|
|
39
|
+
return result.substring(0, digits);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.default = NodeRandomGenerator;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const AleaRandomGenerator_1 = __importDefault(require("./AleaRandomGenerator"));
|
|
7
|
+
// instantiate RNG. Heuristically collect entropy from various sources when a
|
|
8
|
+
// cryptographic PRNG isn't available.
|
|
9
|
+
// client sources
|
|
10
|
+
const height = (typeof window !== 'undefined' && window.innerHeight) ||
|
|
11
|
+
(typeof document !== 'undefined'
|
|
12
|
+
&& document.documentElement
|
|
13
|
+
&& document.documentElement.clientHeight) ||
|
|
14
|
+
(typeof document !== 'undefined'
|
|
15
|
+
&& document.body
|
|
16
|
+
&& document.body.clientHeight) ||
|
|
17
|
+
1;
|
|
18
|
+
const width = (typeof window !== 'undefined' && window.innerWidth) ||
|
|
19
|
+
(typeof document !== 'undefined'
|
|
20
|
+
&& document.documentElement
|
|
21
|
+
&& document.documentElement.clientWidth) ||
|
|
22
|
+
(typeof document !== 'undefined'
|
|
23
|
+
&& document.body
|
|
24
|
+
&& document.body.clientWidth) ||
|
|
25
|
+
1;
|
|
26
|
+
const agent = (typeof navigator !== 'undefined' && navigator.userAgent) || '';
|
|
27
|
+
function createAleaGenerator() {
|
|
28
|
+
return new AleaRandomGenerator_1.default({
|
|
29
|
+
seeds: [new Date, height, width, agent, Math.random()],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
exports.default = createAleaGenerator;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const AleaRandomGenerator_1 = __importDefault(require("./AleaRandomGenerator"));
|
|
7
|
+
const createAleaGenerator_1 = __importDefault(require("./createAleaGenerator"));
|
|
8
|
+
function createRandom(generator) {
|
|
9
|
+
// Create a non-cryptographically secure PRNG with a given seed (using
|
|
10
|
+
// the Alea algorithm)
|
|
11
|
+
generator.createWithSeeds = (...seeds) => {
|
|
12
|
+
if (seeds.length === 0) {
|
|
13
|
+
throw new Error('No seeds were provided');
|
|
14
|
+
}
|
|
15
|
+
return new AleaRandomGenerator_1.default({ seeds });
|
|
16
|
+
};
|
|
17
|
+
// Used like `Random`, but much faster and not cryptographically
|
|
18
|
+
// secure
|
|
19
|
+
generator.insecure = (0, createAleaGenerator_1.default)();
|
|
20
|
+
return generator;
|
|
21
|
+
}
|
|
22
|
+
exports.default = createRandom;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// We use cryptographically strong PRNGs (crypto.getRandomBytes())
|
|
3
|
+
// When using crypto.getRandomValues(), our primitive is hexString(),
|
|
4
|
+
// from which we construct fraction().
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.Random = void 0;
|
|
10
|
+
const NodeRandomGenerator_1 = __importDefault(require("./NodeRandomGenerator"));
|
|
11
|
+
const createRandom_1 = __importDefault(require("./createRandom"));
|
|
12
|
+
exports.Random = (0, createRandom_1.default)(new NodeRandomGenerator_1.default());
|
package/meteor/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2011 - present Meteor Software Ltd.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
====================================================================
|
|
25
|
+
This license applies to all code in Meteor that is not an externally
|
|
26
|
+
maintained library. Externally maintained libraries have their own
|
|
27
|
+
licenses, included in the LICENSES directory.
|
|
28
|
+
====================================================================
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
export interface MaxHeapOptions {
|
|
2
|
+
initData?: {id: string, value: any}[],
|
|
3
|
+
IdMap?: any
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
// Constructor of Heap
|
|
7
|
+
// - comparator - Function - given two items returns a number
|
|
8
|
+
// - options:
|
|
9
|
+
// - initData - Array - Optional - the initial data in a format:
|
|
10
|
+
// Object:
|
|
11
|
+
// - id - String - unique id of the item
|
|
12
|
+
// - value - Any - the data value
|
|
13
|
+
// each value is retained
|
|
14
|
+
// - IdMap - Constructor - Optional - custom IdMap class to store id->index
|
|
15
|
+
// mappings internally. Standard IdMap is used by default.
|
|
16
|
+
export class MaxHeap {
|
|
17
|
+
protected _comparator: (a: any, b: any) => number;
|
|
18
|
+
protected _heap: any[];
|
|
19
|
+
private _heapIdx: any;
|
|
20
|
+
constructor(comparator: (a: any, b: any) => number, options: MaxHeapOptions = {}) {
|
|
21
|
+
if (typeof comparator !== 'function') {
|
|
22
|
+
throw new Error('Passed comparator is invalid, should be a comparison function');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// a C-style comparator that is given two values and returns a number,
|
|
26
|
+
// negative if the first value is less than the second, positive if the second
|
|
27
|
+
// value is greater than the first and zero if they are equal.
|
|
28
|
+
this._comparator = comparator;
|
|
29
|
+
|
|
30
|
+
if (!options.IdMap) {
|
|
31
|
+
options.IdMap = Map;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// _heapIdx maps an id to an index in the Heap array the corresponding value
|
|
35
|
+
// is located on.
|
|
36
|
+
this._heapIdx = new options.IdMap;
|
|
37
|
+
|
|
38
|
+
// The Heap data-structure implemented as a 0-based contiguous array where
|
|
39
|
+
// every item on index idx is a node in a complete binary tree. Every node can
|
|
40
|
+
// have children on indexes idx*2+1 and idx*2+2, except for the leaves. Every
|
|
41
|
+
// node has a parent on index (idx-1)/2;
|
|
42
|
+
this._heap = [];
|
|
43
|
+
|
|
44
|
+
// If the initial array is passed, we can build the heap in linear time
|
|
45
|
+
// complexity (O(N)) compared to linearithmic time complexity (O(nlogn)) if
|
|
46
|
+
// we push elements one by one.
|
|
47
|
+
if (Array.isArray(options.initData)) {
|
|
48
|
+
this._initFromData(options.initData);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Builds a new heap in-place in linear time based on passed data
|
|
53
|
+
_initFromData(data) {
|
|
54
|
+
this._heap = data.map(({ id, value }) => ({ id, value }));
|
|
55
|
+
|
|
56
|
+
data.forEach(({ id }, i) => this._heapIdx.set(id, i));
|
|
57
|
+
|
|
58
|
+
if (!data.length) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// start from the first non-leaf - the parent of the last leaf
|
|
63
|
+
for (let i = parentIdx(data.length - 1); i >= 0; i--) {
|
|
64
|
+
this._downHeap(i);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_downHeap(idx) {
|
|
69
|
+
while (leftChildIdx(idx) < this.size()) {
|
|
70
|
+
const left = leftChildIdx(idx);
|
|
71
|
+
const right = rightChildIdx(idx);
|
|
72
|
+
let largest = idx;
|
|
73
|
+
|
|
74
|
+
if (left < this.size()) {
|
|
75
|
+
largest = this._maxIndex(largest, left);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (right < this.size()) {
|
|
79
|
+
largest = this._maxIndex(largest, right);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (largest === idx) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
this._swap(largest, idx);
|
|
87
|
+
idx = largest;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_upHeap(idx) {
|
|
92
|
+
while (idx > 0) {
|
|
93
|
+
const parent = parentIdx(idx);
|
|
94
|
+
if (this._maxIndex(parent, idx) === idx) {
|
|
95
|
+
this._swap(parent, idx)
|
|
96
|
+
idx = parent;
|
|
97
|
+
} else {
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_maxIndex(idxA, idxB) {
|
|
104
|
+
const valueA = this._get(idxA);
|
|
105
|
+
const valueB = this._get(idxB);
|
|
106
|
+
return this._comparator(valueA, valueB) >= 0 ? idxA : idxB;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Internal: gets raw data object placed on idxth place in heap
|
|
110
|
+
_get(idx) {
|
|
111
|
+
return this._heap[idx].value;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
_swap(idxA, idxB) {
|
|
115
|
+
const recA = this._heap[idxA];
|
|
116
|
+
const recB = this._heap[idxB];
|
|
117
|
+
|
|
118
|
+
this._heapIdx.set(recA.id, idxB);
|
|
119
|
+
this._heapIdx.set(recB.id, idxA);
|
|
120
|
+
|
|
121
|
+
this._heap[idxA] = recB;
|
|
122
|
+
this._heap[idxB] = recA;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get(id) {
|
|
126
|
+
return this.has(id) ?
|
|
127
|
+
this._get(this._heapIdx.get(id)) :
|
|
128
|
+
null;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
set(id, value) {
|
|
132
|
+
if (this.has(id)) {
|
|
133
|
+
if (this.get(id) === value) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const idx = this._heapIdx.get(id);
|
|
138
|
+
this._heap[idx].value = value;
|
|
139
|
+
|
|
140
|
+
// Fix the new value's position
|
|
141
|
+
// Either bubble new value up if it is greater than its parent
|
|
142
|
+
this._upHeap(idx);
|
|
143
|
+
// or bubble it down if it is smaller than one of its children
|
|
144
|
+
this._downHeap(idx);
|
|
145
|
+
} else {
|
|
146
|
+
this._heapIdx.set(id, this._heap.length);
|
|
147
|
+
this._heap.push({ id, value });
|
|
148
|
+
this._upHeap(this._heap.length - 1);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
remove(id) {
|
|
153
|
+
if (this.has(id)) {
|
|
154
|
+
const last = this._heap.length - 1;
|
|
155
|
+
const idx = this._heapIdx.get(id);
|
|
156
|
+
|
|
157
|
+
if (idx !== last) {
|
|
158
|
+
this._swap(idx, last);
|
|
159
|
+
this._heap.pop();
|
|
160
|
+
this._heapIdx.remove(id);
|
|
161
|
+
|
|
162
|
+
// Fix the swapped value's position
|
|
163
|
+
this._upHeap(idx);
|
|
164
|
+
this._downHeap(idx);
|
|
165
|
+
} else {
|
|
166
|
+
this._heap.pop();
|
|
167
|
+
this._heapIdx.remove(id);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
has(id) {
|
|
173
|
+
return this._heapIdx.has(id);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
empty() {
|
|
177
|
+
return !this.size();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
clear() {
|
|
181
|
+
this._heap = [];
|
|
182
|
+
this._heapIdx.clear();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// iterate over values in no particular order
|
|
186
|
+
forEach(iterator) {
|
|
187
|
+
this._heap.forEach(obj => iterator(obj.value, obj.id));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
size() {
|
|
191
|
+
return this._heap.length;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
setDefault(id, def) {
|
|
195
|
+
if (this.has(id)) {
|
|
196
|
+
return this.get(id);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.set(id, def);
|
|
200
|
+
return def;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
clone() {
|
|
204
|
+
const clone = new MaxHeap(this._comparator, { initData: this._heap });
|
|
205
|
+
return clone;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
maxElementId() {
|
|
209
|
+
return this.size() ? this._heap[0].id : null;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
_selfCheck() {
|
|
213
|
+
for (let i = 1; i < this._heap.length; i++) {
|
|
214
|
+
if (this._maxIndex(parentIdx(i), i) !== parentIdx(i)) {
|
|
215
|
+
throw new Error(`An item with id ${this._heap[i].id}` +
|
|
216
|
+
" has a parent younger than it: " +
|
|
217
|
+
this._heap[parentIdx(i)].id);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const leftChildIdx = i => i * 2 + 1;
|
|
224
|
+
const rightChildIdx = i => i * 2 + 2;
|
|
225
|
+
const parentIdx = i => (i - 1) >> 1;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MaxHeap, MaxHeapOptions } from './max_heap';
|
|
2
|
+
|
|
3
|
+
export class MinHeap extends MaxHeap {
|
|
4
|
+
constructor(comparator, options?: MaxHeapOptions) {
|
|
5
|
+
super((a, b) => -comparator(a, b), options);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
maxElementId() {
|
|
9
|
+
throw new Error("Cannot call maxElementId on MinHeap");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
minElementId() {
|
|
13
|
+
return super.maxElementId();
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { MaxHeap, MaxHeapOptions } from './max_heap';
|
|
2
|
+
import { MinHeap } from './min_heap';
|
|
3
|
+
|
|
4
|
+
// This implementation of Min/Max-Heap is just a subclass of Max-Heap
|
|
5
|
+
// with a Min-Heap as an encapsulated property.
|
|
6
|
+
//
|
|
7
|
+
// Most of the operations are just proxy methods to call the same method on both
|
|
8
|
+
// heaps.
|
|
9
|
+
//
|
|
10
|
+
// This implementation takes 2*N memory but is fairly simple to write and
|
|
11
|
+
// understand. And the constant factor of a simple Heap is usually smaller
|
|
12
|
+
// compared to other two-way priority queues like Min/Max Heaps
|
|
13
|
+
// (http://www.cs.otago.ac.nz/staffpriv/mike/Papers/MinMaxHeaps/MinMaxHeaps.pdf)
|
|
14
|
+
// and Interval Heaps
|
|
15
|
+
// (http://www.cise.ufl.edu/~sahni/dsaac/enrich/c13/double.htm)
|
|
16
|
+
export class MinMaxHeap extends MaxHeap {
|
|
17
|
+
private _minHeap: MinHeap;
|
|
18
|
+
|
|
19
|
+
constructor(comparator, options?: MaxHeapOptions) {
|
|
20
|
+
super(comparator, options);
|
|
21
|
+
this._minHeap = new MinHeap(comparator, options);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
set(id: string, value: any) {
|
|
25
|
+
super.set(id, value);
|
|
26
|
+
this._minHeap.set(id, value);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
remove(id: string) {
|
|
30
|
+
super.remove(id);
|
|
31
|
+
this._minHeap.remove(id);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
clear() {
|
|
35
|
+
super.clear();
|
|
36
|
+
this._minHeap.clear();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
setDefault(id: string, def: any) {
|
|
40
|
+
super.setDefault(id, def);
|
|
41
|
+
return this._minHeap.setDefault(id, def);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
clone() {
|
|
45
|
+
const clone = new MinMaxHeap(this._comparator, { initData: this._heap });
|
|
46
|
+
return clone;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
minElementId() {
|
|
50
|
+
return this._minHeap.minElementId();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
2
|
+
|
|
3
|
+
export class Hook {
|
|
4
|
+
private nextCallbackId: number;
|
|
5
|
+
private callbacks: Record<string, Function>;
|
|
6
|
+
private exceptionHandler: Function;
|
|
7
|
+
|
|
8
|
+
constructor(options?) {
|
|
9
|
+
options = options || {};
|
|
10
|
+
this.nextCallbackId = 0;
|
|
11
|
+
this.callbacks = Object.create(null);
|
|
12
|
+
// Whether to wrap callbacks with Meteor.bindEnvironment
|
|
13
|
+
|
|
14
|
+
if (options.exceptionHandler) {
|
|
15
|
+
this.exceptionHandler = options.exceptionHandler;
|
|
16
|
+
} else if (options.debugPrintExceptions) {
|
|
17
|
+
if (typeof options.debugPrintExceptions !== "string") {
|
|
18
|
+
throw new Error("Hook option debugPrintExceptions should be a string");
|
|
19
|
+
}
|
|
20
|
+
this.exceptionHandler = options.debugPrintExceptions;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
register(callback) {
|
|
25
|
+
var exceptionHandler = this.exceptionHandler || function (exception) {
|
|
26
|
+
// Note: this relies on the undocumented fact that if bindEnvironment's
|
|
27
|
+
// onException throws, and you are invoking the callback either in the
|
|
28
|
+
// browser or from within a Fiber in Node, the exception is propagated.
|
|
29
|
+
throw exception;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
callback = dontBindEnvironment(callback, exceptionHandler);
|
|
33
|
+
|
|
34
|
+
var id = this.nextCallbackId++;
|
|
35
|
+
this.callbacks[id] = callback;
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
callback,
|
|
39
|
+
stop: () => {
|
|
40
|
+
delete this.callbacks[id];
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// For each registered callback, call the passed iterator function
|
|
46
|
+
// with the callback.
|
|
47
|
+
//
|
|
48
|
+
// The iterator function can choose whether or not to call the
|
|
49
|
+
// callback. (For example, it might not call the callback if the
|
|
50
|
+
// observed object has been closed or terminated).
|
|
51
|
+
//
|
|
52
|
+
// The iteration is stopped if the iterator function returns a falsy
|
|
53
|
+
// value or throws an exception.
|
|
54
|
+
each(iterator: (callback: Function) => boolean) {
|
|
55
|
+
var ids = Object.keys(this.callbacks);
|
|
56
|
+
for (var i = 0; i < ids.length; ++i) {
|
|
57
|
+
var id = ids[i];
|
|
58
|
+
// check to see if the callback was removed during iteration
|
|
59
|
+
if (hasOwn.call(this.callbacks, id)) {
|
|
60
|
+
var callback = this.callbacks[id];
|
|
61
|
+
if (!iterator(callback)) {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function dontBindEnvironment(func, onException, _this?) {
|
|
70
|
+
if (!onException || typeof (onException) === 'string') {
|
|
71
|
+
var description = onException || "callback of async function";
|
|
72
|
+
onException = function (error) {
|
|
73
|
+
console.error("Exception in " + description, error);
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return function (...args) {
|
|
78
|
+
try {
|
|
79
|
+
var ret = func.apply(_this, args);
|
|
80
|
+
} catch (e) {
|
|
81
|
+
onException(e);
|
|
82
|
+
}
|
|
83
|
+
return ret;
|
|
84
|
+
};
|
|
85
|
+
}
|