|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 /* |
|
7 |
|
8 A rule discrimination network implementation based on ideas from |
|
9 RETE and TREAT. |
|
10 |
|
11 RETE is described in Charles Forgy, "Rete: A Fast Algorithm for the |
|
12 Many Patterns/Many Objects Match Problem", Artificial Intelligence |
|
13 19(1): pp. 17-37, 1982. |
|
14 |
|
15 TREAT is described in Daniel P. Miranker, "TREAT: A Better Match |
|
16 Algorithm for AI Production System Matching", AAAI 1987: pp. 42-47. |
|
17 |
|
18 -- |
|
19 |
|
20 TO DO: |
|
21 |
|
22 . nsAssignmentSet::List objects are allocated by the gallon. We |
|
23 should make it so that these are always allocated from a pool, |
|
24 maybe owned by the nsRuleNetwork? |
|
25 |
|
26 */ |
|
27 |
|
28 #ifndef nsRuleNetwork_h__ |
|
29 #define nsRuleNetwork_h__ |
|
30 |
|
31 #include "mozilla/Attributes.h" |
|
32 #include "nsCOMPtr.h" |
|
33 #include "nsCOMArray.h" |
|
34 #include "nsIAtom.h" |
|
35 #include "nsIDOMNode.h" |
|
36 #include "plhash.h" |
|
37 #include "pldhash.h" |
|
38 #include "nsIRDFNode.h" |
|
39 |
|
40 class nsIRDFResource; |
|
41 class nsXULTemplateResultSetRDF; |
|
42 class nsXULTemplateQueryProcessorRDF; |
|
43 |
|
44 //---------------------------------------------------------------------- |
|
45 |
|
46 /** |
|
47 * A memory element that supports an instantiation. A memory element holds a |
|
48 * set of nodes involved in an RDF test such as <member> or <triple> test. A |
|
49 * memory element is created when a specific test matches. The query processor |
|
50 * maintains a map between the memory elements and the results they eventually |
|
51 * matched. When an assertion is removed from the graph, this map is consulted |
|
52 * to determine which results will no longer match. |
|
53 */ |
|
54 class MemoryElement { |
|
55 protected: |
|
56 MemoryElement() { MOZ_COUNT_CTOR(MemoryElement); } |
|
57 |
|
58 public: |
|
59 virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); } |
|
60 |
|
61 virtual const char* Type() const = 0; |
|
62 virtual PLHashNumber Hash() const = 0; |
|
63 virtual bool Equals(const MemoryElement& aElement) const = 0; |
|
64 |
|
65 bool operator==(const MemoryElement& aMemoryElement) const { |
|
66 return Equals(aMemoryElement); |
|
67 } |
|
68 |
|
69 bool operator!=(const MemoryElement& aMemoryElement) const { |
|
70 return !Equals(aMemoryElement); |
|
71 } |
|
72 }; |
|
73 |
|
74 //---------------------------------------------------------------------- |
|
75 |
|
76 /** |
|
77 * A collection of memory elements |
|
78 */ |
|
79 class MemoryElementSet { |
|
80 public: |
|
81 class ConstIterator; |
|
82 friend class ConstIterator; |
|
83 |
|
84 protected: |
|
85 class List { |
|
86 public: |
|
87 List() { MOZ_COUNT_CTOR(MemoryElementSet::List); } |
|
88 |
|
89 ~List() { |
|
90 MOZ_COUNT_DTOR(MemoryElementSet::List); |
|
91 delete mElement; |
|
92 NS_IF_RELEASE(mNext); } |
|
93 |
|
94 int32_t AddRef() { return ++mRefCnt; } |
|
95 |
|
96 int32_t Release() { |
|
97 int32_t refcnt = --mRefCnt; |
|
98 if (refcnt == 0) delete this; |
|
99 return refcnt; } |
|
100 |
|
101 MemoryElement* mElement; |
|
102 int32_t mRefCnt; |
|
103 List* mNext; |
|
104 }; |
|
105 |
|
106 List* mElements; |
|
107 |
|
108 public: |
|
109 MemoryElementSet() : mElements(nullptr) { |
|
110 MOZ_COUNT_CTOR(MemoryElementSet); } |
|
111 |
|
112 MemoryElementSet(const MemoryElementSet& aSet) : mElements(aSet.mElements) { |
|
113 MOZ_COUNT_CTOR(MemoryElementSet); |
|
114 NS_IF_ADDREF(mElements); } |
|
115 |
|
116 MemoryElementSet& operator=(const MemoryElementSet& aSet) { |
|
117 NS_IF_RELEASE(mElements); |
|
118 mElements = aSet.mElements; |
|
119 NS_IF_ADDREF(mElements); |
|
120 return *this; } |
|
121 |
|
122 ~MemoryElementSet() { |
|
123 MOZ_COUNT_DTOR(MemoryElementSet); |
|
124 NS_IF_RELEASE(mElements); } |
|
125 |
|
126 public: |
|
127 class ConstIterator { |
|
128 public: |
|
129 ConstIterator(List* aElementList) : mCurrent(aElementList) { |
|
130 NS_IF_ADDREF(mCurrent); } |
|
131 |
|
132 ConstIterator(const ConstIterator& aConstIterator) |
|
133 : mCurrent(aConstIterator.mCurrent) { |
|
134 NS_IF_ADDREF(mCurrent); } |
|
135 |
|
136 ConstIterator& operator=(const ConstIterator& aConstIterator) { |
|
137 NS_IF_RELEASE(mCurrent); |
|
138 mCurrent = aConstIterator.mCurrent; |
|
139 NS_IF_ADDREF(mCurrent); |
|
140 return *this; } |
|
141 |
|
142 ~ConstIterator() { NS_IF_RELEASE(mCurrent); } |
|
143 |
|
144 ConstIterator& operator++() { |
|
145 List* next = mCurrent->mNext; |
|
146 NS_RELEASE(mCurrent); |
|
147 mCurrent = next; |
|
148 NS_IF_ADDREF(mCurrent); |
|
149 return *this; } |
|
150 |
|
151 ConstIterator operator++(int) { |
|
152 ConstIterator result(*this); |
|
153 List* next = mCurrent->mNext; |
|
154 NS_RELEASE(mCurrent); |
|
155 mCurrent = next; |
|
156 NS_IF_ADDREF(mCurrent); |
|
157 return result; } |
|
158 |
|
159 const MemoryElement& operator*() const { |
|
160 return *mCurrent->mElement; } |
|
161 |
|
162 const MemoryElement* operator->() const { |
|
163 return mCurrent->mElement; } |
|
164 |
|
165 bool operator==(const ConstIterator& aConstIterator) const { |
|
166 return mCurrent == aConstIterator.mCurrent; } |
|
167 |
|
168 bool operator!=(const ConstIterator& aConstIterator) const { |
|
169 return mCurrent != aConstIterator.mCurrent; } |
|
170 |
|
171 protected: |
|
172 List* mCurrent; |
|
173 }; |
|
174 |
|
175 ConstIterator First() const { return ConstIterator(mElements); } |
|
176 ConstIterator Last() const { return ConstIterator(nullptr); } |
|
177 |
|
178 // N.B. that the set assumes ownership of the element |
|
179 nsresult Add(MemoryElement* aElement); |
|
180 }; |
|
181 |
|
182 //---------------------------------------------------------------------- |
|
183 |
|
184 /** |
|
185 * An assignment of a value to a variable |
|
186 */ |
|
187 class nsAssignment { |
|
188 public: |
|
189 const nsCOMPtr<nsIAtom> mVariable; |
|
190 nsCOMPtr<nsIRDFNode> mValue; |
|
191 |
|
192 nsAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) |
|
193 : mVariable(aVariable), |
|
194 mValue(aValue) |
|
195 { MOZ_COUNT_CTOR(nsAssignment); } |
|
196 |
|
197 nsAssignment(const nsAssignment& aAssignment) |
|
198 : mVariable(aAssignment.mVariable), |
|
199 mValue(aAssignment.mValue) |
|
200 { MOZ_COUNT_CTOR(nsAssignment); } |
|
201 |
|
202 ~nsAssignment() { MOZ_COUNT_DTOR(nsAssignment); } |
|
203 |
|
204 bool operator==(const nsAssignment& aAssignment) const { |
|
205 return mVariable == aAssignment.mVariable && mValue == aAssignment.mValue; } |
|
206 |
|
207 bool operator!=(const nsAssignment& aAssignment) const { |
|
208 return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; } |
|
209 |
|
210 PLHashNumber Hash() const { |
|
211 // XXX I have no idea if this hashing function is good or not // XXX change this |
|
212 PLHashNumber temp = PLHashNumber(NS_PTR_TO_INT32(mValue.get())) >> 2; // strip alignment bits |
|
213 return (temp & 0xffff) | NS_PTR_TO_INT32(mVariable.get()); } |
|
214 }; |
|
215 |
|
216 |
|
217 //---------------------------------------------------------------------- |
|
218 |
|
219 /** |
|
220 * A collection of value-to-variable assignments that minimizes |
|
221 * copying by sharing subsets when possible. |
|
222 */ |
|
223 class nsAssignmentSet { |
|
224 public: |
|
225 class ConstIterator; |
|
226 friend class ConstIterator; |
|
227 |
|
228 protected: |
|
229 class List { |
|
230 public: |
|
231 List(const nsAssignment &aAssignment) : mAssignment(aAssignment) { |
|
232 MOZ_COUNT_CTOR(nsAssignmentSet::List); } |
|
233 |
|
234 ~List() { |
|
235 MOZ_COUNT_DTOR(nsAssignmentSet::List); |
|
236 NS_IF_RELEASE(mNext); } |
|
237 |
|
238 int32_t AddRef() { return ++mRefCnt; } |
|
239 |
|
240 int32_t Release() { |
|
241 int32_t refcnt = --mRefCnt; |
|
242 if (refcnt == 0) delete this; |
|
243 return refcnt; } |
|
244 |
|
245 nsAssignment mAssignment; |
|
246 int32_t mRefCnt; |
|
247 List* mNext; |
|
248 }; |
|
249 |
|
250 List* mAssignments; |
|
251 |
|
252 public: |
|
253 nsAssignmentSet() |
|
254 : mAssignments(nullptr) |
|
255 { MOZ_COUNT_CTOR(nsAssignmentSet); } |
|
256 |
|
257 nsAssignmentSet(const nsAssignmentSet& aSet) |
|
258 : mAssignments(aSet.mAssignments) { |
|
259 MOZ_COUNT_CTOR(nsAssignmentSet); |
|
260 NS_IF_ADDREF(mAssignments); } |
|
261 |
|
262 nsAssignmentSet& operator=(const nsAssignmentSet& aSet) { |
|
263 NS_IF_RELEASE(mAssignments); |
|
264 mAssignments = aSet.mAssignments; |
|
265 NS_IF_ADDREF(mAssignments); |
|
266 return *this; } |
|
267 |
|
268 ~nsAssignmentSet() { |
|
269 MOZ_COUNT_DTOR(nsAssignmentSet); |
|
270 NS_IF_RELEASE(mAssignments); } |
|
271 |
|
272 public: |
|
273 class ConstIterator { |
|
274 public: |
|
275 ConstIterator(List* aAssignmentList) : mCurrent(aAssignmentList) { |
|
276 NS_IF_ADDREF(mCurrent); } |
|
277 |
|
278 ConstIterator(const ConstIterator& aConstIterator) |
|
279 : mCurrent(aConstIterator.mCurrent) { |
|
280 NS_IF_ADDREF(mCurrent); } |
|
281 |
|
282 ConstIterator& operator=(const ConstIterator& aConstIterator) { |
|
283 NS_IF_RELEASE(mCurrent); |
|
284 mCurrent = aConstIterator.mCurrent; |
|
285 NS_IF_ADDREF(mCurrent); |
|
286 return *this; } |
|
287 |
|
288 ~ConstIterator() { NS_IF_RELEASE(mCurrent); } |
|
289 |
|
290 ConstIterator& operator++() { |
|
291 List* next = mCurrent->mNext; |
|
292 NS_RELEASE(mCurrent); |
|
293 mCurrent = next; |
|
294 NS_IF_ADDREF(mCurrent); |
|
295 return *this; } |
|
296 |
|
297 ConstIterator operator++(int) { |
|
298 ConstIterator result(*this); |
|
299 List* next = mCurrent->mNext; |
|
300 NS_RELEASE(mCurrent); |
|
301 mCurrent = next; |
|
302 NS_IF_ADDREF(mCurrent); |
|
303 return result; } |
|
304 |
|
305 const nsAssignment& operator*() const { |
|
306 return mCurrent->mAssignment; } |
|
307 |
|
308 const nsAssignment* operator->() const { |
|
309 return &mCurrent->mAssignment; } |
|
310 |
|
311 bool operator==(const ConstIterator& aConstIterator) const { |
|
312 return mCurrent == aConstIterator.mCurrent; } |
|
313 |
|
314 bool operator!=(const ConstIterator& aConstIterator) const { |
|
315 return mCurrent != aConstIterator.mCurrent; } |
|
316 |
|
317 protected: |
|
318 List* mCurrent; |
|
319 }; |
|
320 |
|
321 ConstIterator First() const { return ConstIterator(mAssignments); } |
|
322 ConstIterator Last() const { return ConstIterator(nullptr); } |
|
323 |
|
324 public: |
|
325 /** |
|
326 * Add an assignment to the set |
|
327 * @param aElement the assigment to add |
|
328 * @return NS_OK if all is well, NS_ERROR_OUT_OF_MEMORY if memory |
|
329 * could not be allocated for the addition. |
|
330 */ |
|
331 nsresult Add(const nsAssignment& aElement); |
|
332 |
|
333 /** |
|
334 * Determine if the assignment set contains the specified variable |
|
335 * to value assignment. |
|
336 * @param aVariable the variable for which to lookup the binding |
|
337 * @param aValue the value to query |
|
338 * @return true if aVariable is bound to aValue; false otherwise. |
|
339 */ |
|
340 bool HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const; |
|
341 |
|
342 /** |
|
343 * Determine if the assignment set contains the specified assignment |
|
344 * @param aAssignment the assignment to search for |
|
345 * @return true if the set contains the assignment, false otherwise. |
|
346 */ |
|
347 bool HasAssignment(const nsAssignment& aAssignment) const { |
|
348 return HasAssignment(aAssignment.mVariable, aAssignment.mValue); } |
|
349 |
|
350 /** |
|
351 * Determine whether the assignment set has an assignment for the |
|
352 * specified variable. |
|
353 * @param aVariable the variable to query |
|
354 * @return true if the assignment set has an assignment for the variable, |
|
355 * false otherwise. |
|
356 */ |
|
357 bool HasAssignmentFor(nsIAtom* aVariable) const; |
|
358 |
|
359 /** |
|
360 * Retrieve the assignment for the specified variable |
|
361 * @param aVariable the variable to query |
|
362 * @param aValue an out parameter that will receive the value assigned |
|
363 * to the variable, if any. |
|
364 * @return true if the variable has an assignment, false |
|
365 * if there was no assignment for the variable. |
|
366 */ |
|
367 bool GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const; |
|
368 |
|
369 /** |
|
370 * Count the number of assignments in the set |
|
371 * @return the number of assignments in the set |
|
372 */ |
|
373 int32_t Count() const; |
|
374 |
|
375 /** |
|
376 * Determine if the set is empty |
|
377 * @return true if the assignment set is empty, false otherwise. |
|
378 */ |
|
379 bool IsEmpty() const { return mAssignments == nullptr; } |
|
380 |
|
381 bool Equals(const nsAssignmentSet& aSet) const; |
|
382 bool operator==(const nsAssignmentSet& aSet) const { return Equals(aSet); } |
|
383 bool operator!=(const nsAssignmentSet& aSet) const { return !Equals(aSet); } |
|
384 }; |
|
385 |
|
386 |
|
387 //---------------------------------------------------------------------- |
|
388 |
|
389 /** |
|
390 * A collection of variable-to-value bindings, with the memory elements |
|
391 * that support those bindings. Essentially, an instantiation is the |
|
392 * collection of variables and values assigned to those variables for a single |
|
393 * result. For each RDF rule in the rule network, each instantiation is |
|
394 * examined and either extended with additional bindings specified by the RDF |
|
395 * rule, or removed if the rule doesn't apply (for instance if a node has no |
|
396 * children). When an instantiation gets to the last node of the rule network, |
|
397 * which is always an nsInstantiationNode, a result is created for it. |
|
398 * |
|
399 * An instantiation object is typically created by "extending" another |
|
400 * instantiation object. That is, using the copy constructor, and |
|
401 * adding bindings and support to the instantiation. |
|
402 */ |
|
403 class Instantiation |
|
404 { |
|
405 public: |
|
406 /** |
|
407 * The variable-to-value bindings |
|
408 */ |
|
409 nsAssignmentSet mAssignments; |
|
410 |
|
411 /** |
|
412 * The memory elements that support the bindings. |
|
413 */ |
|
414 MemoryElementSet mSupport; |
|
415 |
|
416 Instantiation() { MOZ_COUNT_CTOR(Instantiation); } |
|
417 |
|
418 Instantiation(const Instantiation& aInstantiation) |
|
419 : mAssignments(aInstantiation.mAssignments), |
|
420 mSupport(aInstantiation.mSupport) { |
|
421 MOZ_COUNT_CTOR(Instantiation); } |
|
422 |
|
423 Instantiation& operator=(const Instantiation& aInstantiation) { |
|
424 mAssignments = aInstantiation.mAssignments; |
|
425 mSupport = aInstantiation.mSupport; |
|
426 return *this; } |
|
427 |
|
428 ~Instantiation() { MOZ_COUNT_DTOR(Instantiation); } |
|
429 |
|
430 /** |
|
431 * Add the specified variable-to-value assignment to the instantiation's |
|
432 * set of assignments. |
|
433 * @param aVariable the variable to which is being assigned |
|
434 * @param aValue the value that is being assigned |
|
435 * @return NS_OK if no errors, NS_ERROR_OUT_OF_MEMORY if there |
|
436 * is not enough memory to perform the operation |
|
437 */ |
|
438 nsresult AddAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) { |
|
439 mAssignments.Add(nsAssignment(aVariable, aValue)); |
|
440 return NS_OK; } |
|
441 |
|
442 /** |
|
443 * Add a memory element to the set of memory elements that are |
|
444 * supporting the instantiation |
|
445 * @param aMemoryElement the memory element to add to the |
|
446 * instantiation's set of support |
|
447 * @return NS_OK if no errors occurred, NS_ERROR_OUT_OF_MEMORY |
|
448 * if there is not enough memory to perform the operation. |
|
449 */ |
|
450 nsresult AddSupportingElement(MemoryElement* aMemoryElement) { |
|
451 mSupport.Add(aMemoryElement); |
|
452 return NS_OK; } |
|
453 |
|
454 bool Equals(const Instantiation& aInstantiation) const { |
|
455 return mAssignments == aInstantiation.mAssignments; } |
|
456 |
|
457 bool operator==(const Instantiation& aInstantiation) const { |
|
458 return Equals(aInstantiation); } |
|
459 |
|
460 bool operator!=(const Instantiation& aInstantiation) const { |
|
461 return !Equals(aInstantiation); } |
|
462 |
|
463 static PLHashNumber Hash(const void* aKey); |
|
464 static int Compare(const void* aLeft, const void* aRight); |
|
465 }; |
|
466 |
|
467 |
|
468 //---------------------------------------------------------------------- |
|
469 |
|
470 /** |
|
471 * A collection of intantiations |
|
472 */ |
|
473 class InstantiationSet |
|
474 { |
|
475 public: |
|
476 InstantiationSet(); |
|
477 InstantiationSet(const InstantiationSet& aInstantiationSet); |
|
478 InstantiationSet& operator=(const InstantiationSet& aInstantiationSet); |
|
479 |
|
480 ~InstantiationSet() { |
|
481 MOZ_COUNT_DTOR(InstantiationSet); |
|
482 Clear(); } |
|
483 |
|
484 class ConstIterator; |
|
485 friend class ConstIterator; |
|
486 |
|
487 class Iterator; |
|
488 friend class Iterator; |
|
489 |
|
490 friend class nsXULTemplateResultSetRDF; // so it can get to the List |
|
491 |
|
492 protected: |
|
493 class List { |
|
494 public: |
|
495 Instantiation mInstantiation; |
|
496 List* mNext; |
|
497 List* mPrev; |
|
498 |
|
499 List() { MOZ_COUNT_CTOR(InstantiationSet::List); } |
|
500 ~List() { MOZ_COUNT_DTOR(InstantiationSet::List); } |
|
501 }; |
|
502 |
|
503 List mHead; |
|
504 |
|
505 public: |
|
506 class ConstIterator { |
|
507 protected: |
|
508 friend class Iterator; // XXXwaterson so broken. |
|
509 List* mCurrent; |
|
510 |
|
511 public: |
|
512 ConstIterator(List* aList) : mCurrent(aList) {} |
|
513 |
|
514 ConstIterator(const ConstIterator& aConstIterator) |
|
515 : mCurrent(aConstIterator.mCurrent) {} |
|
516 |
|
517 ConstIterator& operator=(const ConstIterator& aConstIterator) { |
|
518 mCurrent = aConstIterator.mCurrent; |
|
519 return *this; } |
|
520 |
|
521 ConstIterator& operator++() { |
|
522 mCurrent = mCurrent->mNext; |
|
523 return *this; } |
|
524 |
|
525 ConstIterator operator++(int) { |
|
526 ConstIterator result(*this); |
|
527 mCurrent = mCurrent->mNext; |
|
528 return result; } |
|
529 |
|
530 ConstIterator& operator--() { |
|
531 mCurrent = mCurrent->mPrev; |
|
532 return *this; } |
|
533 |
|
534 ConstIterator operator--(int) { |
|
535 ConstIterator result(*this); |
|
536 mCurrent = mCurrent->mPrev; |
|
537 return result; } |
|
538 |
|
539 const Instantiation& operator*() const { |
|
540 return mCurrent->mInstantiation; } |
|
541 |
|
542 const Instantiation* operator->() const { |
|
543 return &mCurrent->mInstantiation; } |
|
544 |
|
545 bool operator==(const ConstIterator& aConstIterator) const { |
|
546 return mCurrent == aConstIterator.mCurrent; } |
|
547 |
|
548 bool operator!=(const ConstIterator& aConstIterator) const { |
|
549 return mCurrent != aConstIterator.mCurrent; } |
|
550 }; |
|
551 |
|
552 ConstIterator First() const { return ConstIterator(mHead.mNext); } |
|
553 ConstIterator Last() const { return ConstIterator(const_cast<List*>(&mHead)); } |
|
554 |
|
555 class Iterator : public ConstIterator { |
|
556 public: |
|
557 Iterator(List* aList) : ConstIterator(aList) {} |
|
558 |
|
559 Iterator& operator++() { |
|
560 mCurrent = mCurrent->mNext; |
|
561 return *this; } |
|
562 |
|
563 Iterator operator++(int) { |
|
564 Iterator result(*this); |
|
565 mCurrent = mCurrent->mNext; |
|
566 return result; } |
|
567 |
|
568 Iterator& operator--() { |
|
569 mCurrent = mCurrent->mPrev; |
|
570 return *this; } |
|
571 |
|
572 Iterator operator--(int) { |
|
573 Iterator result(*this); |
|
574 mCurrent = mCurrent->mPrev; |
|
575 return result; } |
|
576 |
|
577 Instantiation& operator*() const { |
|
578 return mCurrent->mInstantiation; } |
|
579 |
|
580 Instantiation* operator->() const { |
|
581 return &mCurrent->mInstantiation; } |
|
582 |
|
583 bool operator==(const ConstIterator& aConstIterator) const { |
|
584 return mCurrent == aConstIterator.mCurrent; } |
|
585 |
|
586 bool operator!=(const ConstIterator& aConstIterator) const { |
|
587 return mCurrent != aConstIterator.mCurrent; } |
|
588 |
|
589 friend class InstantiationSet; |
|
590 }; |
|
591 |
|
592 Iterator First() { return Iterator(mHead.mNext); } |
|
593 Iterator Last() { return Iterator(&mHead); } |
|
594 |
|
595 bool Empty() const { return First() == Last(); } |
|
596 |
|
597 Iterator Append(const Instantiation& aInstantiation) { |
|
598 return Insert(Last(), aInstantiation); } |
|
599 |
|
600 Iterator Insert(Iterator aBefore, const Instantiation& aInstantiation); |
|
601 |
|
602 Iterator Erase(Iterator aElement); |
|
603 |
|
604 void Clear(); |
|
605 |
|
606 bool HasAssignmentFor(nsIAtom* aVariable) const; |
|
607 }; |
|
608 |
|
609 //---------------------------------------------------------------------- |
|
610 |
|
611 /** |
|
612 * A abstract base class for all nodes in the rule network |
|
613 */ |
|
614 class ReteNode |
|
615 { |
|
616 public: |
|
617 ReteNode() {} |
|
618 virtual ~ReteNode() {} |
|
619 |
|
620 /** |
|
621 * Propagate a set of instantiations "down" through the |
|
622 * network. Each instantiation is a partial set of |
|
623 * variable-to-value assignments, along with the memory elements |
|
624 * that support it. |
|
625 * |
|
626 * The node must evaluate each instantiation, and either 1) |
|
627 * extend it with additional assignments and memory-element |
|
628 * support, or 2) remove it from the set because it is |
|
629 * inconsistent with the constraints that this node applies. |
|
630 * |
|
631 * The node must then pass the resulting instantiation set along |
|
632 * to any of its children in the network. (In other words, the |
|
633 * node must recursively call Propagate() on its children. We |
|
634 * should fix this to make the algorithm interruptable.) |
|
635 * |
|
636 * See TestNode::Propagate for details about instantiation set ownership |
|
637 * |
|
638 * @param aInstantiations the set of instantiations to propagate |
|
639 * down through the network. |
|
640 * @param aIsUpdate true if updating, false for first generation |
|
641 * @param aTakenInstantiations true if the ownership over aInstantiations |
|
642 * has been taken from the caller. If false, |
|
643 * the caller owns it. |
|
644 * @return NS_OK if no errors occurred. |
|
645 */ |
|
646 virtual nsresult Propagate(InstantiationSet& aInstantiations, |
|
647 bool aIsUpdate, bool& aTakenInstantiations) = 0; |
|
648 }; |
|
649 |
|
650 //---------------------------------------------------------------------- |
|
651 |
|
652 /** |
|
653 * A collection of nodes in the rule network |
|
654 */ |
|
655 class ReteNodeSet |
|
656 { |
|
657 public: |
|
658 ReteNodeSet(); |
|
659 ~ReteNodeSet(); |
|
660 |
|
661 nsresult Add(ReteNode* aNode); |
|
662 nsresult Clear(); |
|
663 |
|
664 class Iterator; |
|
665 |
|
666 class ConstIterator { |
|
667 public: |
|
668 ConstIterator(ReteNode** aNode) : mCurrent(aNode) {} |
|
669 |
|
670 ConstIterator(const ConstIterator& aConstIterator) |
|
671 : mCurrent(aConstIterator.mCurrent) {} |
|
672 |
|
673 ConstIterator& operator=(const ConstIterator& aConstIterator) { |
|
674 mCurrent = aConstIterator.mCurrent; |
|
675 return *this; } |
|
676 |
|
677 ConstIterator& operator++() { |
|
678 ++mCurrent; |
|
679 return *this; } |
|
680 |
|
681 ConstIterator operator++(int) { |
|
682 ConstIterator result(*this); |
|
683 ++mCurrent; |
|
684 return result; } |
|
685 |
|
686 const ReteNode* operator*() const { |
|
687 return *mCurrent; } |
|
688 |
|
689 const ReteNode* operator->() const { |
|
690 return *mCurrent; } |
|
691 |
|
692 bool operator==(const ConstIterator& aConstIterator) const { |
|
693 return mCurrent == aConstIterator.mCurrent; } |
|
694 |
|
695 bool operator!=(const ConstIterator& aConstIterator) const { |
|
696 return mCurrent != aConstIterator.mCurrent; } |
|
697 |
|
698 protected: |
|
699 friend class Iterator; // XXXwaterson this is so wrong! |
|
700 ReteNode** mCurrent; |
|
701 }; |
|
702 |
|
703 ConstIterator First() const { return ConstIterator(mNodes); } |
|
704 ConstIterator Last() const { return ConstIterator(mNodes + mCount); } |
|
705 |
|
706 class Iterator : public ConstIterator { |
|
707 public: |
|
708 Iterator(ReteNode** aNode) : ConstIterator(aNode) {} |
|
709 |
|
710 Iterator& operator++() { |
|
711 ++mCurrent; |
|
712 return *this; } |
|
713 |
|
714 Iterator operator++(int) { |
|
715 Iterator result(*this); |
|
716 ++mCurrent; |
|
717 return result; } |
|
718 |
|
719 ReteNode* operator*() const { |
|
720 return *mCurrent; } |
|
721 |
|
722 ReteNode* operator->() const { |
|
723 return *mCurrent; } |
|
724 |
|
725 bool operator==(const ConstIterator& aConstIterator) const { |
|
726 return mCurrent == aConstIterator.mCurrent; } |
|
727 |
|
728 bool operator!=(const ConstIterator& aConstIterator) const { |
|
729 return mCurrent != aConstIterator.mCurrent; } |
|
730 }; |
|
731 |
|
732 Iterator First() { return Iterator(mNodes); } |
|
733 Iterator Last() { return Iterator(mNodes + mCount); } |
|
734 |
|
735 int32_t Count() const { return mCount; } |
|
736 |
|
737 protected: |
|
738 ReteNode** mNodes; |
|
739 int32_t mCount; |
|
740 int32_t mCapacity; |
|
741 }; |
|
742 |
|
743 //---------------------------------------------------------------------- |
|
744 |
|
745 /** |
|
746 * A node that applies a test condition to a set of instantiations. |
|
747 * |
|
748 * This class provides implementations of Propagate() and Constrain() |
|
749 * in terms of one simple operation, FilterInstantiations(). A node |
|
750 * that is a "simple test node" in a rule network should derive from |
|
751 * this class, and need only implement FilterInstantiations(). |
|
752 */ |
|
753 class TestNode : public ReteNode |
|
754 { |
|
755 public: |
|
756 TestNode(TestNode* aParent); |
|
757 |
|
758 /** |
|
759 * Retrieve the test node's parent |
|
760 * @return the test node's parent |
|
761 */ |
|
762 TestNode* GetParent() const { return mParent; } |
|
763 |
|
764 /** |
|
765 * Calls FilterInstantiations() on the instantiation set, and if |
|
766 * the resulting set isn't empty, propagates the new set down to |
|
767 * each of the test node's children. |
|
768 * |
|
769 * Note that the caller of Propagate is responsible for deleting |
|
770 * aInstantiations if necessary as described below. |
|
771 * |
|
772 * Propagate may be called in update or non-update mode as indicated |
|
773 * by the aIsUpdate argument. Non-update mode is used when initially |
|
774 * generating results, whereas update mode is used when the datasource |
|
775 * changes and new results might be available. |
|
776 * |
|
777 * The last node in a chain of TestNodes is always an nsInstantiationNode. |
|
778 * In non-update mode, this nsInstantiationNode will cache the results |
|
779 * in the query using the SetCachedResults method. The query processor |
|
780 * takes these cached results and creates a nsXULTemplateResultSetRDF |
|
781 * which is the enumeration returned to the template builder. This |
|
782 * nsXULTemplateResultSetRDF owns the instantiations and they will be |
|
783 * deleted when the nsXULTemplateResultSetRDF goes away. |
|
784 * |
|
785 * In update mode, the nsInstantiationNode node will iterate over the |
|
786 * instantiations itself and callback to the builder to update any matches |
|
787 * and generated content. If no instantiations match, then the builder |
|
788 * will never be called. |
|
789 * |
|
790 * Thus, the difference between update and non-update modes is that in |
|
791 * update mode, the results and instantiations have been already handled |
|
792 * whereas in non-update mode they are expected to be returned in an |
|
793 * nsXULTemplateResultSetRDF for further processing by the builder. |
|
794 * |
|
795 * Regardless, aTakenInstantiations will be set to true if the |
|
796 * ownership over aInstantiations has been transferred to a result set. |
|
797 * If set to false, the caller is still responsible for aInstantiations. |
|
798 * aTakenInstantiations will be set properly even if an error occurs. |
|
799 */ |
|
800 virtual nsresult Propagate(InstantiationSet& aInstantiations, |
|
801 bool aIsUpdate, bool& aTakenInstantiations) MOZ_OVERRIDE; |
|
802 |
|
803 /** |
|
804 * This is called by a child node on its parent to allow the |
|
805 * parent's constraints to apply to the set of instantiations. |
|
806 * |
|
807 * A node must iterate through the set of instantiations, and for |
|
808 * each instantiation, either 1) extend the instantiation by |
|
809 * adding variable-to-value assignments and memory element support |
|
810 * for those assignments, or 2) remove the instantiation because |
|
811 * it is inconsistent. |
|
812 * |
|
813 * The node must then pass the resulting set of instantiations up |
|
814 * to its parent (by recursive call; we should make this iterative |
|
815 * & interruptable at some point.) |
|
816 * |
|
817 * @param aInstantiations the set of instantiations that must |
|
818 * be constrained |
|
819 * @return NS_OK if no errors occurred |
|
820 */ |
|
821 virtual nsresult Constrain(InstantiationSet& aInstantiations); |
|
822 |
|
823 /** |
|
824 * Given a set of instantiations, filter out any that are |
|
825 * inconsistent with the test node's test, and append |
|
826 * variable-to-value assignments and memory element support for |
|
827 * those which do pass the test node's test. |
|
828 * |
|
829 * @param aInstantiations the set of instantiations to be |
|
830 * filtered |
|
831 * @param aCantHandleYet [out] true if the instantiations do not contain |
|
832 * enough information to constrain the data. May be null if this |
|
833 * isn't important to the caller. |
|
834 * @return NS_OK if no errors occurred. |
|
835 */ |
|
836 virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, |
|
837 bool* aCantHandleYet) const = 0; |
|
838 //XXX probably better named "ApplyConstraints" or "Discrminiate" or something |
|
839 |
|
840 /** |
|
841 * Add another node as a child of this node. |
|
842 * @param aNode the node to add. |
|
843 * @return NS_OK if no errors occur. |
|
844 */ |
|
845 nsresult AddChild(ReteNode* aNode) { return mKids.Add(aNode); } |
|
846 |
|
847 /** |
|
848 * Remove all the children of this node |
|
849 * @return NS_OK if no errors occur. |
|
850 */ |
|
851 nsresult RemoveAllChildren() { return mKids.Clear(); } |
|
852 |
|
853 protected: |
|
854 TestNode* mParent; |
|
855 ReteNodeSet mKids; |
|
856 }; |
|
857 |
|
858 #endif // nsRuleNetwork_h__ |