content/xul/templates/src/nsRuleNetwork.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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/. */
     6 /*
     8   A rule discrimination network implementation based on ideas from
     9   RETE and TREAT.
    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.
    15   TREAT is described in Daniel P. Miranker, "TREAT: A Better Match
    16   Algorithm for AI Production System Matching", AAAI 1987: pp. 42-47.
    18   --
    20   TO DO:
    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?
    26  */
    28 #ifndef nsRuleNetwork_h__
    29 #define nsRuleNetwork_h__
    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"
    40 class nsIRDFResource;
    41 class nsXULTemplateResultSetRDF;
    42 class nsXULTemplateQueryProcessorRDF;
    44 //----------------------------------------------------------------------
    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); }
    58 public:
    59     virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); }
    61     virtual const char* Type() const = 0;
    62     virtual PLHashNumber Hash() const = 0;
    63     virtual bool Equals(const MemoryElement& aElement) const = 0;
    65     bool operator==(const MemoryElement& aMemoryElement) const {
    66         return Equals(aMemoryElement);
    67     }
    69     bool operator!=(const MemoryElement& aMemoryElement) const {
    70         return !Equals(aMemoryElement);
    71     }
    72 };
    74 //----------------------------------------------------------------------
    76 /**
    77  * A collection of memory elements
    78  */
    79 class MemoryElementSet {
    80 public:
    81     class ConstIterator;
    82     friend class ConstIterator;
    84 protected:
    85     class List {
    86     public:
    87         List() { MOZ_COUNT_CTOR(MemoryElementSet::List); }
    89         ~List() {
    90             MOZ_COUNT_DTOR(MemoryElementSet::List);
    91             delete mElement;
    92             NS_IF_RELEASE(mNext); }
    94         int32_t AddRef() { return ++mRefCnt; }
    96         int32_t Release() {
    97             int32_t refcnt = --mRefCnt;
    98             if (refcnt == 0) delete this;
    99             return refcnt; }
   101         MemoryElement* mElement;
   102         int32_t        mRefCnt;
   103         List*          mNext;
   104     };
   106     List* mElements;
   108 public:
   109     MemoryElementSet() : mElements(nullptr) {
   110         MOZ_COUNT_CTOR(MemoryElementSet); }
   112     MemoryElementSet(const MemoryElementSet& aSet) : mElements(aSet.mElements) {
   113         MOZ_COUNT_CTOR(MemoryElementSet);
   114         NS_IF_ADDREF(mElements); }
   116     MemoryElementSet& operator=(const MemoryElementSet& aSet) {
   117         NS_IF_RELEASE(mElements);
   118         mElements = aSet.mElements;
   119         NS_IF_ADDREF(mElements);
   120         return *this; }
   122     ~MemoryElementSet() {
   123         MOZ_COUNT_DTOR(MemoryElementSet);
   124         NS_IF_RELEASE(mElements); }
   126 public:
   127     class ConstIterator {
   128     public:
   129         ConstIterator(List* aElementList) : mCurrent(aElementList) {
   130             NS_IF_ADDREF(mCurrent); }
   132         ConstIterator(const ConstIterator& aConstIterator)
   133             : mCurrent(aConstIterator.mCurrent) {
   134             NS_IF_ADDREF(mCurrent); }
   136         ConstIterator& operator=(const ConstIterator& aConstIterator) {
   137             NS_IF_RELEASE(mCurrent);
   138             mCurrent = aConstIterator.mCurrent;
   139             NS_IF_ADDREF(mCurrent);
   140             return *this; }
   142         ~ConstIterator() { NS_IF_RELEASE(mCurrent); }
   144         ConstIterator& operator++() {
   145             List* next = mCurrent->mNext;
   146             NS_RELEASE(mCurrent);
   147             mCurrent = next;
   148             NS_IF_ADDREF(mCurrent);
   149             return *this; }
   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; }
   159         const MemoryElement& operator*() const {
   160             return *mCurrent->mElement; }
   162         const MemoryElement* operator->() const {
   163             return mCurrent->mElement; }
   165         bool operator==(const ConstIterator& aConstIterator) const {
   166             return mCurrent == aConstIterator.mCurrent; }
   168         bool operator!=(const ConstIterator& aConstIterator) const {
   169             return mCurrent != aConstIterator.mCurrent; }
   171     protected:
   172         List* mCurrent;
   173     };
   175     ConstIterator First() const { return ConstIterator(mElements); }
   176     ConstIterator Last() const { return ConstIterator(nullptr); }
   178     // N.B. that the set assumes ownership of the element
   179     nsresult Add(MemoryElement* aElement);
   180 };
   182 //----------------------------------------------------------------------
   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;
   192     nsAssignment(nsIAtom* aVariable, nsIRDFNode* aValue)
   193         : mVariable(aVariable),
   194           mValue(aValue)
   195         { MOZ_COUNT_CTOR(nsAssignment); }
   197     nsAssignment(const nsAssignment& aAssignment)
   198         : mVariable(aAssignment.mVariable),
   199           mValue(aAssignment.mValue)
   200         { MOZ_COUNT_CTOR(nsAssignment); }
   202     ~nsAssignment() { MOZ_COUNT_DTOR(nsAssignment); }
   204     bool operator==(const nsAssignment& aAssignment) const {
   205         return mVariable == aAssignment.mVariable && mValue == aAssignment.mValue; }
   207     bool operator!=(const nsAssignment& aAssignment) const {
   208         return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; }
   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 };
   217 //----------------------------------------------------------------------
   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;
   228 protected:
   229     class List {
   230     public:
   231         List(const nsAssignment &aAssignment) : mAssignment(aAssignment) {
   232             MOZ_COUNT_CTOR(nsAssignmentSet::List); }
   234         ~List() {
   235             MOZ_COUNT_DTOR(nsAssignmentSet::List);
   236             NS_IF_RELEASE(mNext); }
   238         int32_t AddRef() { return ++mRefCnt; }
   240         int32_t Release() {
   241             int32_t refcnt = --mRefCnt;
   242             if (refcnt == 0) delete this;
   243             return refcnt; }
   245         nsAssignment mAssignment;
   246         int32_t mRefCnt;
   247         List*   mNext;
   248     };
   250     List* mAssignments;
   252 public:
   253     nsAssignmentSet()
   254         : mAssignments(nullptr)
   255         { MOZ_COUNT_CTOR(nsAssignmentSet); }
   257     nsAssignmentSet(const nsAssignmentSet& aSet)
   258         : mAssignments(aSet.mAssignments) {
   259         MOZ_COUNT_CTOR(nsAssignmentSet);
   260         NS_IF_ADDREF(mAssignments); }
   262     nsAssignmentSet& operator=(const nsAssignmentSet& aSet) {
   263         NS_IF_RELEASE(mAssignments);
   264         mAssignments = aSet.mAssignments;
   265         NS_IF_ADDREF(mAssignments);
   266         return *this; }
   268     ~nsAssignmentSet() {
   269         MOZ_COUNT_DTOR(nsAssignmentSet);
   270         NS_IF_RELEASE(mAssignments); }
   272 public:
   273     class ConstIterator {
   274     public:
   275         ConstIterator(List* aAssignmentList) : mCurrent(aAssignmentList) {
   276             NS_IF_ADDREF(mCurrent); }
   278         ConstIterator(const ConstIterator& aConstIterator)
   279             : mCurrent(aConstIterator.mCurrent) {
   280             NS_IF_ADDREF(mCurrent); }
   282         ConstIterator& operator=(const ConstIterator& aConstIterator) {
   283             NS_IF_RELEASE(mCurrent);
   284             mCurrent = aConstIterator.mCurrent;
   285             NS_IF_ADDREF(mCurrent);
   286             return *this; }
   288         ~ConstIterator() { NS_IF_RELEASE(mCurrent); }
   290         ConstIterator& operator++() {
   291             List* next = mCurrent->mNext;
   292             NS_RELEASE(mCurrent);
   293             mCurrent = next;
   294             NS_IF_ADDREF(mCurrent);
   295             return *this; }
   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; }
   305         const nsAssignment& operator*() const {
   306             return mCurrent->mAssignment; }
   308         const nsAssignment* operator->() const {
   309             return &mCurrent->mAssignment; }
   311         bool operator==(const ConstIterator& aConstIterator) const {
   312             return mCurrent == aConstIterator.mCurrent; }
   314         bool operator!=(const ConstIterator& aConstIterator) const {
   315             return mCurrent != aConstIterator.mCurrent; }
   317     protected:
   318         List* mCurrent;
   319     };
   321     ConstIterator First() const { return ConstIterator(mAssignments); }
   322     ConstIterator Last() const { return ConstIterator(nullptr); }
   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);
   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;
   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); }
   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;
   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;
   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;
   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; }
   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 };
   387 //----------------------------------------------------------------------
   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;
   411     /**
   412      * The memory elements that support the bindings.
   413      */
   414     MemoryElementSet mSupport;
   416     Instantiation() { MOZ_COUNT_CTOR(Instantiation); }
   418     Instantiation(const Instantiation& aInstantiation)
   419         : mAssignments(aInstantiation.mAssignments),
   420           mSupport(aInstantiation.mSupport) {
   421         MOZ_COUNT_CTOR(Instantiation); }
   423     Instantiation& operator=(const Instantiation& aInstantiation) {
   424         mAssignments = aInstantiation.mAssignments;
   425         mSupport  = aInstantiation.mSupport;
   426         return *this; }
   428     ~Instantiation() { MOZ_COUNT_DTOR(Instantiation); }
   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; }
   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; }
   454     bool Equals(const Instantiation& aInstantiation) const {
   455         return mAssignments == aInstantiation.mAssignments; }
   457     bool operator==(const Instantiation& aInstantiation) const {
   458         return Equals(aInstantiation); }
   460     bool operator!=(const Instantiation& aInstantiation) const {
   461         return !Equals(aInstantiation); }
   463     static PLHashNumber Hash(const void* aKey);
   464     static int Compare(const void* aLeft, const void* aRight);
   465 };
   468 //----------------------------------------------------------------------
   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);
   480     ~InstantiationSet() {
   481         MOZ_COUNT_DTOR(InstantiationSet);
   482         Clear(); }
   484     class ConstIterator;
   485     friend class ConstIterator;
   487     class Iterator;
   488     friend class Iterator;
   490     friend class nsXULTemplateResultSetRDF; // so it can get to the List
   492 protected:
   493     class List {
   494     public:
   495         Instantiation mInstantiation;
   496         List*         mNext;
   497         List*         mPrev;
   499         List() { MOZ_COUNT_CTOR(InstantiationSet::List); }
   500         ~List() { MOZ_COUNT_DTOR(InstantiationSet::List); }
   501     };
   503     List mHead;
   505 public:
   506     class ConstIterator {
   507     protected:
   508         friend class Iterator; // XXXwaterson so broken.
   509         List* mCurrent;
   511     public:
   512         ConstIterator(List* aList) : mCurrent(aList) {}
   514         ConstIterator(const ConstIterator& aConstIterator)
   515             : mCurrent(aConstIterator.mCurrent) {}
   517         ConstIterator& operator=(const ConstIterator& aConstIterator) {
   518             mCurrent = aConstIterator.mCurrent;
   519             return *this; }
   521         ConstIterator& operator++() {
   522             mCurrent = mCurrent->mNext;
   523             return *this; }
   525         ConstIterator operator++(int) {
   526             ConstIterator result(*this);
   527             mCurrent = mCurrent->mNext;
   528             return result; }
   530         ConstIterator& operator--() {
   531             mCurrent = mCurrent->mPrev;
   532             return *this; }
   534         ConstIterator operator--(int) {
   535             ConstIterator result(*this);
   536             mCurrent = mCurrent->mPrev;
   537             return result; }
   539         const Instantiation& operator*() const {
   540             return mCurrent->mInstantiation; }
   542         const Instantiation* operator->() const {
   543             return &mCurrent->mInstantiation; }
   545         bool operator==(const ConstIterator& aConstIterator) const {
   546             return mCurrent == aConstIterator.mCurrent; }
   548         bool operator!=(const ConstIterator& aConstIterator) const {
   549             return mCurrent != aConstIterator.mCurrent; }
   550     };
   552     ConstIterator First() const { return ConstIterator(mHead.mNext); }
   553     ConstIterator Last() const { return ConstIterator(const_cast<List*>(&mHead)); }
   555     class Iterator : public ConstIterator {
   556     public:
   557         Iterator(List* aList) : ConstIterator(aList) {}
   559         Iterator& operator++() {
   560             mCurrent = mCurrent->mNext;
   561             return *this; }
   563         Iterator operator++(int) {
   564             Iterator result(*this);
   565             mCurrent = mCurrent->mNext;
   566             return result; }
   568         Iterator& operator--() {
   569             mCurrent = mCurrent->mPrev;
   570             return *this; }
   572         Iterator operator--(int) {
   573             Iterator result(*this);
   574             mCurrent = mCurrent->mPrev;
   575             return result; }
   577         Instantiation& operator*() const {
   578             return mCurrent->mInstantiation; }
   580         Instantiation* operator->() const {
   581             return &mCurrent->mInstantiation; }
   583         bool operator==(const ConstIterator& aConstIterator) const {
   584             return mCurrent == aConstIterator.mCurrent; }
   586         bool operator!=(const ConstIterator& aConstIterator) const {
   587             return mCurrent != aConstIterator.mCurrent; }
   589         friend class InstantiationSet;
   590     };
   592     Iterator First() { return Iterator(mHead.mNext); }
   593     Iterator Last() { return Iterator(&mHead); }
   595     bool Empty() const { return First() == Last(); }
   597     Iterator Append(const Instantiation& aInstantiation) {
   598         return Insert(Last(), aInstantiation); }
   600     Iterator Insert(Iterator aBefore, const Instantiation& aInstantiation);
   602     Iterator Erase(Iterator aElement);
   604     void Clear();
   606     bool HasAssignmentFor(nsIAtom* aVariable) const;
   607 };
   609 //----------------------------------------------------------------------
   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() {}
   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 };
   650 //----------------------------------------------------------------------
   652 /**
   653  * A collection of nodes in the rule network
   654  */
   655 class ReteNodeSet
   656 {
   657 public:
   658     ReteNodeSet();
   659     ~ReteNodeSet();
   661     nsresult Add(ReteNode* aNode);
   662     nsresult Clear();
   664     class Iterator;
   666     class ConstIterator {
   667     public:
   668         ConstIterator(ReteNode** aNode) : mCurrent(aNode) {}
   670         ConstIterator(const ConstIterator& aConstIterator)
   671             : mCurrent(aConstIterator.mCurrent) {}
   673         ConstIterator& operator=(const ConstIterator& aConstIterator) {
   674             mCurrent = aConstIterator.mCurrent;
   675             return *this; }
   677         ConstIterator& operator++() {
   678             ++mCurrent;
   679             return *this; }
   681         ConstIterator operator++(int) {
   682             ConstIterator result(*this);
   683             ++mCurrent;
   684             return result; }
   686         const ReteNode* operator*() const {
   687             return *mCurrent; }
   689         const ReteNode* operator->() const {
   690             return *mCurrent; }
   692         bool operator==(const ConstIterator& aConstIterator) const {
   693             return mCurrent == aConstIterator.mCurrent; }
   695         bool operator!=(const ConstIterator& aConstIterator) const {
   696             return mCurrent != aConstIterator.mCurrent; }
   698     protected:
   699         friend class Iterator; // XXXwaterson this is so wrong!
   700         ReteNode** mCurrent;
   701     };
   703     ConstIterator First() const { return ConstIterator(mNodes); }
   704     ConstIterator Last() const { return ConstIterator(mNodes + mCount); }
   706     class Iterator : public ConstIterator {
   707     public:
   708         Iterator(ReteNode** aNode) : ConstIterator(aNode) {}
   710         Iterator& operator++() {
   711             ++mCurrent;
   712             return *this; }
   714         Iterator operator++(int) {
   715             Iterator result(*this);
   716             ++mCurrent;
   717             return result; }
   719         ReteNode* operator*() const {
   720             return *mCurrent; }
   722         ReteNode* operator->() const {
   723             return *mCurrent; }
   725         bool operator==(const ConstIterator& aConstIterator) const {
   726             return mCurrent == aConstIterator.mCurrent; }
   728         bool operator!=(const ConstIterator& aConstIterator) const {
   729             return mCurrent != aConstIterator.mCurrent; }
   730     };
   732     Iterator First() { return Iterator(mNodes); }
   733     Iterator Last() { return Iterator(mNodes + mCount); }
   735     int32_t Count() const { return mCount; }
   737 protected:
   738     ReteNode** mNodes;
   739     int32_t mCount;
   740     int32_t mCapacity;
   741 };
   743 //----------------------------------------------------------------------
   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);
   758     /**
   759      * Retrieve the test node's parent
   760      * @return the test node's parent
   761      */
   762     TestNode* GetParent() const { return mParent; }
   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;
   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);
   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
   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); }
   847     /**
   848      * Remove all the children of this node
   849      * @return NS_OK if no errors occur.
   850      */
   851     nsresult RemoveAllChildren() { return mKids.Clear(); }
   853 protected:
   854     TestNode* mParent;
   855     ReteNodeSet mKids;
   856 };
   858 #endif // nsRuleNetwork_h__

mercurial