content/xul/templates/src/nsRuleNetwork.h

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:bac4dba5de34
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__

mercurial