n3 2.2.8 → 2.2.9

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/lib/N3Reasoner.js CHANGED
@@ -33,7 +33,7 @@ class N3Reasoner {
33
33
  // Caps a rule's premise count, as `_evaluatePremise` recurses once per premise
34
34
  this._maxPremiseDepth = options.maxPremiseDepth === undefined ? Infinity : options.maxPremiseDepth;
35
35
  }
36
- _add(subject, predicate, object, graphItem, cb) {
36
+ _add(subject, predicate, object, graphItem, c, cb) {
37
37
  // Only add to the remaining indexes if there is not already a value in the index
38
38
  if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
39
39
  this._store._addToIndex(graphItem.predicates, predicate, object, subject);
@@ -42,43 +42,63 @@ class N3Reasoner {
42
42
  // after all three indexes are updated, so a caught error leaves the store
43
43
  // in a consistent state (the reasoning result is merely incomplete).
44
44
  if (++this._derivations > this._maxDerivations) throw new Error(`Reasoning exceeded the maximum of ${this._maxDerivations} derivations`);
45
- cb();
45
+ cb(c);
46
46
  }
47
+
48
+ // Emit conclusions without allocating per-match callbacks
49
+ _emit(rule, content, cb) {
50
+ const conclusion = rule.conclusion;
51
+ for (let k = 0; k < conclusion.length; k++) {
52
+ const c = conclusion[k];
53
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, c, cb);
54
+ }
55
+ }
56
+
57
+ // Bound values use direct lookups; unbound values scan the index
47
58
  _evaluatePremise(rule, content, cb, i = 0) {
48
- let v1, v2, value, index1, index2;
59
+ let value, index1;
49
60
  const [val0, val1, val2] = rule.premise[i].value,
50
61
  index = content[rule.premise[i].content];
62
+ const last = i === rule.premise.length - 1;
51
63
  const v0 = !(value = val0.value);
52
- for (value in v0 ? index : {
53
- [value]: index[value]
54
- }) {
55
- if (index1 = index[value]) {
56
- if (v0) val0.value = Number(value);
57
- v1 = !(value = val1.value);
58
- for (value in v1 ? index1 : {
59
- [value]: index1[value]
60
- }) {
61
- if (index2 = index1[value]) {
62
- if (v1) val1.value = Number(value);
63
- v2 = !(value = val2.value);
64
- for (value in v2 ? index2 : {
65
- [value]: index2[value]
66
- }) {
67
- if (v2) val2.value = Number(value);
68
- if (i === rule.premise.length - 1) rule.conclusion.forEach(c => {
69
- // eslint-disable-next-line max-nested-callbacks
70
- this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
71
- cb(c);
72
- });
73
- });else this._evaluatePremise(rule, content, cb, i + 1);
74
- }
75
- if (v2) val2.value = null;
76
- }
77
- }
78
- if (v1) val1.value = null;
64
+ if (v0) {
65
+ // Intermediate index entries are always non-empty
66
+ for (value in index) {
67
+ index1 = index[value];
68
+ val0.value = Number(value);
69
+ this._evaluateLevel1(rule, content, cb, i, last, val1, val2, index1);
70
+ }
71
+ val0.value = null;
72
+ } else if (index1 = index[value]) {
73
+ this._evaluateLevel1(rule, content, cb, i, last, val1, val2, index1);
74
+ }
75
+ }
76
+ _evaluateLevel1(rule, content, cb, i, last, val1, val2, index1) {
77
+ let value, index2;
78
+ const v1 = !(value = val1.value);
79
+ if (v1) {
80
+ for (value in index1) {
81
+ index2 = index1[value];
82
+ val1.value = Number(value);
83
+ this._evaluateLevel2(rule, content, cb, i, last, val2, index2);
84
+ }
85
+ val1.value = null;
86
+ } else if (index2 = index1[value]) {
87
+ this._evaluateLevel2(rule, content, cb, i, last, val2, index2);
88
+ }
89
+ }
90
+ _evaluateLevel2(rule, content, cb, i, last, val2, index2) {
91
+ let value;
92
+ const v2 = !(value = val2.value);
93
+ if (v2) {
94
+ for (value in index2) {
95
+ val2.value = Number(value);
96
+ if (last) this._emit(rule, content, cb);else this._evaluatePremise(rule, content, cb, i + 1);
79
97
  }
98
+ val2.value = null;
80
99
  }
81
- if (v0) val0.value = null;
100
+ // Bound leaves run once even when the key is absent
101
+ else if (last) this._emit(rule, content, cb);else this._evaluatePremise(rule, content, cb, i + 1);
82
102
  }
83
103
  _evaluateRules(rules, content, cb) {
84
104
  for (let i = 0; i < rules.length; i++) {
@@ -96,14 +116,12 @@ class N3Reasoner {
96
116
  });
97
117
  }
98
118
 
99
- // eslint-disable-next-line func-style
119
+ // Reuse addRule instead of allocating a callback per conclusion
100
120
  const addConclusions = conclusion => {
101
- conclusion.forEach(c => {
102
- // eslint-disable-next-line max-nested-callbacks
103
- this._add(c.subject.value, c.predicate.value, c.object.value, content, () => {
104
- addRule(c);
105
- });
106
- });
121
+ for (let k = 0; k < conclusion.length; k++) {
122
+ const c = conclusion[k];
123
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, c, addRule);
124
+ }
107
125
  };
108
126
  this._evaluateRules(rules, content, addRule);
109
127
  let r;
@@ -194,9 +212,7 @@ class N3Reasoner {
194
212
  basePremise: p
195
213
  });
196
214
  }
197
- r2.variables.forEach(v => {
198
- v.value = null;
199
- });
215
+ for (let k = 0; k < r2.variables.length; k++) r2.variables[k].value = null;
200
216
  }
201
217
  }
202
218
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.2.8",
3
+ "version": "2.2.9",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
package/src/N3Reasoner.js CHANGED
@@ -22,7 +22,7 @@ export default class N3Reasoner {
22
22
  this._maxPremiseDepth = options.maxPremiseDepth === undefined ? Infinity : options.maxPremiseDepth;
23
23
  }
24
24
 
25
- _add(subject, predicate, object, graphItem, cb) {
25
+ _add(subject, predicate, object, graphItem, c, cb) {
26
26
  // Only add to the remaining indexes if there is not already a value in the index
27
27
  if (!this._store._addToIndex(graphItem.subjects, subject, predicate, object)) return;
28
28
  this._store._addToIndex(graphItem.predicates, predicate, object, subject);
@@ -32,39 +32,68 @@ export default class N3Reasoner {
32
32
  // in a consistent state (the reasoning result is merely incomplete).
33
33
  if (++this._derivations > this._maxDerivations)
34
34
  throw new Error(`Reasoning exceeded the maximum of ${this._maxDerivations} derivations`);
35
- cb();
35
+ cb(c);
36
36
  }
37
37
 
38
+ // Emit conclusions without allocating per-match callbacks
39
+ _emit(rule, content, cb) {
40
+ const conclusion = rule.conclusion;
41
+ for (let k = 0; k < conclusion.length; k++) {
42
+ const c = conclusion[k];
43
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, c, cb);
44
+ }
45
+ }
46
+
47
+ // Bound values use direct lookups; unbound values scan the index
38
48
  _evaluatePremise(rule, content, cb, i = 0) {
39
- let v1, v2, value, index1, index2;
49
+ let value, index1;
40
50
  const [val0, val1, val2] = rule.premise[i].value, index = content[rule.premise[i].content];
51
+ const last = i === rule.premise.length - 1;
41
52
  const v0 = !(value = val0.value);
42
- for (value in v0 ? index : { [value]: index[value] }) {
43
- if (index1 = index[value]) {
44
- if (v0) val0.value = Number(value);
45
- v1 = !(value = val1.value);
46
- for (value in v1 ? index1 : { [value]: index1[value] }) {
47
- if (index2 = index1[value]) {
48
- if (v1) val1.value = Number(value);
49
- v2 = !(value = val2.value);
50
- for (value in v2 ? index2 : { [value]: index2[value] }) {
51
- if (v2) val2.value = Number(value);
52
-
53
- if (i === rule.premise.length - 1)
54
- rule.conclusion.forEach(c => {
55
- // eslint-disable-next-line max-nested-callbacks
56
- this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { cb(c); });
57
- });
58
- else
59
- this._evaluatePremise(rule, content, cb, i + 1);
60
- }
61
- if (v2) val2.value = null;
62
- }
63
- }
64
- if (v1) val1.value = null;
53
+ if (v0) {
54
+ // Intermediate index entries are always non-empty
55
+ for (value in index) {
56
+ index1 = index[value];
57
+ val0.value = Number(value);
58
+ this._evaluateLevel1(rule, content, cb, i, last, val1, val2, index1);
59
+ }
60
+ val0.value = null;
61
+ }
62
+ else if (index1 = index[value]) {
63
+ this._evaluateLevel1(rule, content, cb, i, last, val1, val2, index1);
64
+ }
65
+ }
66
+
67
+ _evaluateLevel1(rule, content, cb, i, last, val1, val2, index1) {
68
+ let value, index2;
69
+ const v1 = !(value = val1.value);
70
+ if (v1) {
71
+ for (value in index1) {
72
+ index2 = index1[value];
73
+ val1.value = Number(value);
74
+ this._evaluateLevel2(rule, content, cb, i, last, val2, index2);
65
75
  }
76
+ val1.value = null;
77
+ }
78
+ else if (index2 = index1[value]) {
79
+ this._evaluateLevel2(rule, content, cb, i, last, val2, index2);
66
80
  }
67
- if (v0) val0.value = null;
81
+ }
82
+
83
+ _evaluateLevel2(rule, content, cb, i, last, val2, index2) {
84
+ let value;
85
+ const v2 = !(value = val2.value);
86
+ if (v2) {
87
+ for (value in index2) {
88
+ val2.value = Number(value);
89
+ if (last) this._emit(rule, content, cb);
90
+ else this._evaluatePremise(rule, content, cb, i + 1);
91
+ }
92
+ val2.value = null;
93
+ }
94
+ // Bound leaves run once even when the key is absent
95
+ else if (last) this._emit(rule, content, cb);
96
+ else this._evaluatePremise(rule, content, cb, i + 1);
68
97
  }
69
98
 
70
99
  _evaluateRules(rules, content, cb) {
@@ -85,12 +114,12 @@ export default class N3Reasoner {
85
114
  });
86
115
  }
87
116
 
88
- // eslint-disable-next-line func-style
117
+ // Reuse addRule instead of allocating a callback per conclusion
89
118
  const addConclusions = conclusion => {
90
- conclusion.forEach(c => {
91
- // eslint-disable-next-line max-nested-callbacks
92
- this._add(c.subject.value, c.predicate.value, c.object.value, content, () => { addRule(c); });
93
- });
119
+ for (let k = 0; k < conclusion.length; k++) {
120
+ const c = conclusion[k];
121
+ this._add(c.subject.value, c.predicate.value, c.object.value, content, c, addRule);
122
+ }
94
123
  };
95
124
 
96
125
  this._evaluateRules(rules, content, addRule);
@@ -185,7 +214,7 @@ export default class N3Reasoner {
185
214
  basePremise: p,
186
215
  });
187
216
  }
188
- r2.variables.forEach(v => { v.value = null; });
217
+ for (let k = 0; k < r2.variables.length; k++) r2.variables[k].value = null;
189
218
  }
190
219
  }
191
220
  }