1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/xul/templates/src/nsRuleNetwork.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,858 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + 1.11 + A rule discrimination network implementation based on ideas from 1.12 + RETE and TREAT. 1.13 + 1.14 + RETE is described in Charles Forgy, "Rete: A Fast Algorithm for the 1.15 + Many Patterns/Many Objects Match Problem", Artificial Intelligence 1.16 + 19(1): pp. 17-37, 1982. 1.17 + 1.18 + TREAT is described in Daniel P. Miranker, "TREAT: A Better Match 1.19 + Algorithm for AI Production System Matching", AAAI 1987: pp. 42-47. 1.20 + 1.21 + -- 1.22 + 1.23 + TO DO: 1.24 + 1.25 + . nsAssignmentSet::List objects are allocated by the gallon. We 1.26 + should make it so that these are always allocated from a pool, 1.27 + maybe owned by the nsRuleNetwork? 1.28 + 1.29 + */ 1.30 + 1.31 +#ifndef nsRuleNetwork_h__ 1.32 +#define nsRuleNetwork_h__ 1.33 + 1.34 +#include "mozilla/Attributes.h" 1.35 +#include "nsCOMPtr.h" 1.36 +#include "nsCOMArray.h" 1.37 +#include "nsIAtom.h" 1.38 +#include "nsIDOMNode.h" 1.39 +#include "plhash.h" 1.40 +#include "pldhash.h" 1.41 +#include "nsIRDFNode.h" 1.42 + 1.43 +class nsIRDFResource; 1.44 +class nsXULTemplateResultSetRDF; 1.45 +class nsXULTemplateQueryProcessorRDF; 1.46 + 1.47 +//---------------------------------------------------------------------- 1.48 + 1.49 +/** 1.50 + * A memory element that supports an instantiation. A memory element holds a 1.51 + * set of nodes involved in an RDF test such as <member> or <triple> test. A 1.52 + * memory element is created when a specific test matches. The query processor 1.53 + * maintains a map between the memory elements and the results they eventually 1.54 + * matched. When an assertion is removed from the graph, this map is consulted 1.55 + * to determine which results will no longer match. 1.56 + */ 1.57 +class MemoryElement { 1.58 +protected: 1.59 + MemoryElement() { MOZ_COUNT_CTOR(MemoryElement); } 1.60 + 1.61 +public: 1.62 + virtual ~MemoryElement() { MOZ_COUNT_DTOR(MemoryElement); } 1.63 + 1.64 + virtual const char* Type() const = 0; 1.65 + virtual PLHashNumber Hash() const = 0; 1.66 + virtual bool Equals(const MemoryElement& aElement) const = 0; 1.67 + 1.68 + bool operator==(const MemoryElement& aMemoryElement) const { 1.69 + return Equals(aMemoryElement); 1.70 + } 1.71 + 1.72 + bool operator!=(const MemoryElement& aMemoryElement) const { 1.73 + return !Equals(aMemoryElement); 1.74 + } 1.75 +}; 1.76 + 1.77 +//---------------------------------------------------------------------- 1.78 + 1.79 +/** 1.80 + * A collection of memory elements 1.81 + */ 1.82 +class MemoryElementSet { 1.83 +public: 1.84 + class ConstIterator; 1.85 + friend class ConstIterator; 1.86 + 1.87 +protected: 1.88 + class List { 1.89 + public: 1.90 + List() { MOZ_COUNT_CTOR(MemoryElementSet::List); } 1.91 + 1.92 + ~List() { 1.93 + MOZ_COUNT_DTOR(MemoryElementSet::List); 1.94 + delete mElement; 1.95 + NS_IF_RELEASE(mNext); } 1.96 + 1.97 + int32_t AddRef() { return ++mRefCnt; } 1.98 + 1.99 + int32_t Release() { 1.100 + int32_t refcnt = --mRefCnt; 1.101 + if (refcnt == 0) delete this; 1.102 + return refcnt; } 1.103 + 1.104 + MemoryElement* mElement; 1.105 + int32_t mRefCnt; 1.106 + List* mNext; 1.107 + }; 1.108 + 1.109 + List* mElements; 1.110 + 1.111 +public: 1.112 + MemoryElementSet() : mElements(nullptr) { 1.113 + MOZ_COUNT_CTOR(MemoryElementSet); } 1.114 + 1.115 + MemoryElementSet(const MemoryElementSet& aSet) : mElements(aSet.mElements) { 1.116 + MOZ_COUNT_CTOR(MemoryElementSet); 1.117 + NS_IF_ADDREF(mElements); } 1.118 + 1.119 + MemoryElementSet& operator=(const MemoryElementSet& aSet) { 1.120 + NS_IF_RELEASE(mElements); 1.121 + mElements = aSet.mElements; 1.122 + NS_IF_ADDREF(mElements); 1.123 + return *this; } 1.124 + 1.125 + ~MemoryElementSet() { 1.126 + MOZ_COUNT_DTOR(MemoryElementSet); 1.127 + NS_IF_RELEASE(mElements); } 1.128 + 1.129 +public: 1.130 + class ConstIterator { 1.131 + public: 1.132 + ConstIterator(List* aElementList) : mCurrent(aElementList) { 1.133 + NS_IF_ADDREF(mCurrent); } 1.134 + 1.135 + ConstIterator(const ConstIterator& aConstIterator) 1.136 + : mCurrent(aConstIterator.mCurrent) { 1.137 + NS_IF_ADDREF(mCurrent); } 1.138 + 1.139 + ConstIterator& operator=(const ConstIterator& aConstIterator) { 1.140 + NS_IF_RELEASE(mCurrent); 1.141 + mCurrent = aConstIterator.mCurrent; 1.142 + NS_IF_ADDREF(mCurrent); 1.143 + return *this; } 1.144 + 1.145 + ~ConstIterator() { NS_IF_RELEASE(mCurrent); } 1.146 + 1.147 + ConstIterator& operator++() { 1.148 + List* next = mCurrent->mNext; 1.149 + NS_RELEASE(mCurrent); 1.150 + mCurrent = next; 1.151 + NS_IF_ADDREF(mCurrent); 1.152 + return *this; } 1.153 + 1.154 + ConstIterator operator++(int) { 1.155 + ConstIterator result(*this); 1.156 + List* next = mCurrent->mNext; 1.157 + NS_RELEASE(mCurrent); 1.158 + mCurrent = next; 1.159 + NS_IF_ADDREF(mCurrent); 1.160 + return result; } 1.161 + 1.162 + const MemoryElement& operator*() const { 1.163 + return *mCurrent->mElement; } 1.164 + 1.165 + const MemoryElement* operator->() const { 1.166 + return mCurrent->mElement; } 1.167 + 1.168 + bool operator==(const ConstIterator& aConstIterator) const { 1.169 + return mCurrent == aConstIterator.mCurrent; } 1.170 + 1.171 + bool operator!=(const ConstIterator& aConstIterator) const { 1.172 + return mCurrent != aConstIterator.mCurrent; } 1.173 + 1.174 + protected: 1.175 + List* mCurrent; 1.176 + }; 1.177 + 1.178 + ConstIterator First() const { return ConstIterator(mElements); } 1.179 + ConstIterator Last() const { return ConstIterator(nullptr); } 1.180 + 1.181 + // N.B. that the set assumes ownership of the element 1.182 + nsresult Add(MemoryElement* aElement); 1.183 +}; 1.184 + 1.185 +//---------------------------------------------------------------------- 1.186 + 1.187 +/** 1.188 + * An assignment of a value to a variable 1.189 + */ 1.190 +class nsAssignment { 1.191 +public: 1.192 + const nsCOMPtr<nsIAtom> mVariable; 1.193 + nsCOMPtr<nsIRDFNode> mValue; 1.194 + 1.195 + nsAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) 1.196 + : mVariable(aVariable), 1.197 + mValue(aValue) 1.198 + { MOZ_COUNT_CTOR(nsAssignment); } 1.199 + 1.200 + nsAssignment(const nsAssignment& aAssignment) 1.201 + : mVariable(aAssignment.mVariable), 1.202 + mValue(aAssignment.mValue) 1.203 + { MOZ_COUNT_CTOR(nsAssignment); } 1.204 + 1.205 + ~nsAssignment() { MOZ_COUNT_DTOR(nsAssignment); } 1.206 + 1.207 + bool operator==(const nsAssignment& aAssignment) const { 1.208 + return mVariable == aAssignment.mVariable && mValue == aAssignment.mValue; } 1.209 + 1.210 + bool operator!=(const nsAssignment& aAssignment) const { 1.211 + return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; } 1.212 + 1.213 + PLHashNumber Hash() const { 1.214 + // XXX I have no idea if this hashing function is good or not // XXX change this 1.215 + PLHashNumber temp = PLHashNumber(NS_PTR_TO_INT32(mValue.get())) >> 2; // strip alignment bits 1.216 + return (temp & 0xffff) | NS_PTR_TO_INT32(mVariable.get()); } 1.217 +}; 1.218 + 1.219 + 1.220 +//---------------------------------------------------------------------- 1.221 + 1.222 +/** 1.223 + * A collection of value-to-variable assignments that minimizes 1.224 + * copying by sharing subsets when possible. 1.225 + */ 1.226 +class nsAssignmentSet { 1.227 +public: 1.228 + class ConstIterator; 1.229 + friend class ConstIterator; 1.230 + 1.231 +protected: 1.232 + class List { 1.233 + public: 1.234 + List(const nsAssignment &aAssignment) : mAssignment(aAssignment) { 1.235 + MOZ_COUNT_CTOR(nsAssignmentSet::List); } 1.236 + 1.237 + ~List() { 1.238 + MOZ_COUNT_DTOR(nsAssignmentSet::List); 1.239 + NS_IF_RELEASE(mNext); } 1.240 + 1.241 + int32_t AddRef() { return ++mRefCnt; } 1.242 + 1.243 + int32_t Release() { 1.244 + int32_t refcnt = --mRefCnt; 1.245 + if (refcnt == 0) delete this; 1.246 + return refcnt; } 1.247 + 1.248 + nsAssignment mAssignment; 1.249 + int32_t mRefCnt; 1.250 + List* mNext; 1.251 + }; 1.252 + 1.253 + List* mAssignments; 1.254 + 1.255 +public: 1.256 + nsAssignmentSet() 1.257 + : mAssignments(nullptr) 1.258 + { MOZ_COUNT_CTOR(nsAssignmentSet); } 1.259 + 1.260 + nsAssignmentSet(const nsAssignmentSet& aSet) 1.261 + : mAssignments(aSet.mAssignments) { 1.262 + MOZ_COUNT_CTOR(nsAssignmentSet); 1.263 + NS_IF_ADDREF(mAssignments); } 1.264 + 1.265 + nsAssignmentSet& operator=(const nsAssignmentSet& aSet) { 1.266 + NS_IF_RELEASE(mAssignments); 1.267 + mAssignments = aSet.mAssignments; 1.268 + NS_IF_ADDREF(mAssignments); 1.269 + return *this; } 1.270 + 1.271 + ~nsAssignmentSet() { 1.272 + MOZ_COUNT_DTOR(nsAssignmentSet); 1.273 + NS_IF_RELEASE(mAssignments); } 1.274 + 1.275 +public: 1.276 + class ConstIterator { 1.277 + public: 1.278 + ConstIterator(List* aAssignmentList) : mCurrent(aAssignmentList) { 1.279 + NS_IF_ADDREF(mCurrent); } 1.280 + 1.281 + ConstIterator(const ConstIterator& aConstIterator) 1.282 + : mCurrent(aConstIterator.mCurrent) { 1.283 + NS_IF_ADDREF(mCurrent); } 1.284 + 1.285 + ConstIterator& operator=(const ConstIterator& aConstIterator) { 1.286 + NS_IF_RELEASE(mCurrent); 1.287 + mCurrent = aConstIterator.mCurrent; 1.288 + NS_IF_ADDREF(mCurrent); 1.289 + return *this; } 1.290 + 1.291 + ~ConstIterator() { NS_IF_RELEASE(mCurrent); } 1.292 + 1.293 + ConstIterator& operator++() { 1.294 + List* next = mCurrent->mNext; 1.295 + NS_RELEASE(mCurrent); 1.296 + mCurrent = next; 1.297 + NS_IF_ADDREF(mCurrent); 1.298 + return *this; } 1.299 + 1.300 + ConstIterator operator++(int) { 1.301 + ConstIterator result(*this); 1.302 + List* next = mCurrent->mNext; 1.303 + NS_RELEASE(mCurrent); 1.304 + mCurrent = next; 1.305 + NS_IF_ADDREF(mCurrent); 1.306 + return result; } 1.307 + 1.308 + const nsAssignment& operator*() const { 1.309 + return mCurrent->mAssignment; } 1.310 + 1.311 + const nsAssignment* operator->() const { 1.312 + return &mCurrent->mAssignment; } 1.313 + 1.314 + bool operator==(const ConstIterator& aConstIterator) const { 1.315 + return mCurrent == aConstIterator.mCurrent; } 1.316 + 1.317 + bool operator!=(const ConstIterator& aConstIterator) const { 1.318 + return mCurrent != aConstIterator.mCurrent; } 1.319 + 1.320 + protected: 1.321 + List* mCurrent; 1.322 + }; 1.323 + 1.324 + ConstIterator First() const { return ConstIterator(mAssignments); } 1.325 + ConstIterator Last() const { return ConstIterator(nullptr); } 1.326 + 1.327 +public: 1.328 + /** 1.329 + * Add an assignment to the set 1.330 + * @param aElement the assigment to add 1.331 + * @return NS_OK if all is well, NS_ERROR_OUT_OF_MEMORY if memory 1.332 + * could not be allocated for the addition. 1.333 + */ 1.334 + nsresult Add(const nsAssignment& aElement); 1.335 + 1.336 + /** 1.337 + * Determine if the assignment set contains the specified variable 1.338 + * to value assignment. 1.339 + * @param aVariable the variable for which to lookup the binding 1.340 + * @param aValue the value to query 1.341 + * @return true if aVariable is bound to aValue; false otherwise. 1.342 + */ 1.343 + bool HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const; 1.344 + 1.345 + /** 1.346 + * Determine if the assignment set contains the specified assignment 1.347 + * @param aAssignment the assignment to search for 1.348 + * @return true if the set contains the assignment, false otherwise. 1.349 + */ 1.350 + bool HasAssignment(const nsAssignment& aAssignment) const { 1.351 + return HasAssignment(aAssignment.mVariable, aAssignment.mValue); } 1.352 + 1.353 + /** 1.354 + * Determine whether the assignment set has an assignment for the 1.355 + * specified variable. 1.356 + * @param aVariable the variable to query 1.357 + * @return true if the assignment set has an assignment for the variable, 1.358 + * false otherwise. 1.359 + */ 1.360 + bool HasAssignmentFor(nsIAtom* aVariable) const; 1.361 + 1.362 + /** 1.363 + * Retrieve the assignment for the specified variable 1.364 + * @param aVariable the variable to query 1.365 + * @param aValue an out parameter that will receive the value assigned 1.366 + * to the variable, if any. 1.367 + * @return true if the variable has an assignment, false 1.368 + * if there was no assignment for the variable. 1.369 + */ 1.370 + bool GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const; 1.371 + 1.372 + /** 1.373 + * Count the number of assignments in the set 1.374 + * @return the number of assignments in the set 1.375 + */ 1.376 + int32_t Count() const; 1.377 + 1.378 + /** 1.379 + * Determine if the set is empty 1.380 + * @return true if the assignment set is empty, false otherwise. 1.381 + */ 1.382 + bool IsEmpty() const { return mAssignments == nullptr; } 1.383 + 1.384 + bool Equals(const nsAssignmentSet& aSet) const; 1.385 + bool operator==(const nsAssignmentSet& aSet) const { return Equals(aSet); } 1.386 + bool operator!=(const nsAssignmentSet& aSet) const { return !Equals(aSet); } 1.387 +}; 1.388 + 1.389 + 1.390 +//---------------------------------------------------------------------- 1.391 + 1.392 +/** 1.393 + * A collection of variable-to-value bindings, with the memory elements 1.394 + * that support those bindings. Essentially, an instantiation is the 1.395 + * collection of variables and values assigned to those variables for a single 1.396 + * result. For each RDF rule in the rule network, each instantiation is 1.397 + * examined and either extended with additional bindings specified by the RDF 1.398 + * rule, or removed if the rule doesn't apply (for instance if a node has no 1.399 + * children). When an instantiation gets to the last node of the rule network, 1.400 + * which is always an nsInstantiationNode, a result is created for it. 1.401 + * 1.402 + * An instantiation object is typically created by "extending" another 1.403 + * instantiation object. That is, using the copy constructor, and 1.404 + * adding bindings and support to the instantiation. 1.405 + */ 1.406 +class Instantiation 1.407 +{ 1.408 +public: 1.409 + /** 1.410 + * The variable-to-value bindings 1.411 + */ 1.412 + nsAssignmentSet mAssignments; 1.413 + 1.414 + /** 1.415 + * The memory elements that support the bindings. 1.416 + */ 1.417 + MemoryElementSet mSupport; 1.418 + 1.419 + Instantiation() { MOZ_COUNT_CTOR(Instantiation); } 1.420 + 1.421 + Instantiation(const Instantiation& aInstantiation) 1.422 + : mAssignments(aInstantiation.mAssignments), 1.423 + mSupport(aInstantiation.mSupport) { 1.424 + MOZ_COUNT_CTOR(Instantiation); } 1.425 + 1.426 + Instantiation& operator=(const Instantiation& aInstantiation) { 1.427 + mAssignments = aInstantiation.mAssignments; 1.428 + mSupport = aInstantiation.mSupport; 1.429 + return *this; } 1.430 + 1.431 + ~Instantiation() { MOZ_COUNT_DTOR(Instantiation); } 1.432 + 1.433 + /** 1.434 + * Add the specified variable-to-value assignment to the instantiation's 1.435 + * set of assignments. 1.436 + * @param aVariable the variable to which is being assigned 1.437 + * @param aValue the value that is being assigned 1.438 + * @return NS_OK if no errors, NS_ERROR_OUT_OF_MEMORY if there 1.439 + * is not enough memory to perform the operation 1.440 + */ 1.441 + nsresult AddAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) { 1.442 + mAssignments.Add(nsAssignment(aVariable, aValue)); 1.443 + return NS_OK; } 1.444 + 1.445 + /** 1.446 + * Add a memory element to the set of memory elements that are 1.447 + * supporting the instantiation 1.448 + * @param aMemoryElement the memory element to add to the 1.449 + * instantiation's set of support 1.450 + * @return NS_OK if no errors occurred, NS_ERROR_OUT_OF_MEMORY 1.451 + * if there is not enough memory to perform the operation. 1.452 + */ 1.453 + nsresult AddSupportingElement(MemoryElement* aMemoryElement) { 1.454 + mSupport.Add(aMemoryElement); 1.455 + return NS_OK; } 1.456 + 1.457 + bool Equals(const Instantiation& aInstantiation) const { 1.458 + return mAssignments == aInstantiation.mAssignments; } 1.459 + 1.460 + bool operator==(const Instantiation& aInstantiation) const { 1.461 + return Equals(aInstantiation); } 1.462 + 1.463 + bool operator!=(const Instantiation& aInstantiation) const { 1.464 + return !Equals(aInstantiation); } 1.465 + 1.466 + static PLHashNumber Hash(const void* aKey); 1.467 + static int Compare(const void* aLeft, const void* aRight); 1.468 +}; 1.469 + 1.470 + 1.471 +//---------------------------------------------------------------------- 1.472 + 1.473 +/** 1.474 + * A collection of intantiations 1.475 + */ 1.476 +class InstantiationSet 1.477 +{ 1.478 +public: 1.479 + InstantiationSet(); 1.480 + InstantiationSet(const InstantiationSet& aInstantiationSet); 1.481 + InstantiationSet& operator=(const InstantiationSet& aInstantiationSet); 1.482 + 1.483 + ~InstantiationSet() { 1.484 + MOZ_COUNT_DTOR(InstantiationSet); 1.485 + Clear(); } 1.486 + 1.487 + class ConstIterator; 1.488 + friend class ConstIterator; 1.489 + 1.490 + class Iterator; 1.491 + friend class Iterator; 1.492 + 1.493 + friend class nsXULTemplateResultSetRDF; // so it can get to the List 1.494 + 1.495 +protected: 1.496 + class List { 1.497 + public: 1.498 + Instantiation mInstantiation; 1.499 + List* mNext; 1.500 + List* mPrev; 1.501 + 1.502 + List() { MOZ_COUNT_CTOR(InstantiationSet::List); } 1.503 + ~List() { MOZ_COUNT_DTOR(InstantiationSet::List); } 1.504 + }; 1.505 + 1.506 + List mHead; 1.507 + 1.508 +public: 1.509 + class ConstIterator { 1.510 + protected: 1.511 + friend class Iterator; // XXXwaterson so broken. 1.512 + List* mCurrent; 1.513 + 1.514 + public: 1.515 + ConstIterator(List* aList) : mCurrent(aList) {} 1.516 + 1.517 + ConstIterator(const ConstIterator& aConstIterator) 1.518 + : mCurrent(aConstIterator.mCurrent) {} 1.519 + 1.520 + ConstIterator& operator=(const ConstIterator& aConstIterator) { 1.521 + mCurrent = aConstIterator.mCurrent; 1.522 + return *this; } 1.523 + 1.524 + ConstIterator& operator++() { 1.525 + mCurrent = mCurrent->mNext; 1.526 + return *this; } 1.527 + 1.528 + ConstIterator operator++(int) { 1.529 + ConstIterator result(*this); 1.530 + mCurrent = mCurrent->mNext; 1.531 + return result; } 1.532 + 1.533 + ConstIterator& operator--() { 1.534 + mCurrent = mCurrent->mPrev; 1.535 + return *this; } 1.536 + 1.537 + ConstIterator operator--(int) { 1.538 + ConstIterator result(*this); 1.539 + mCurrent = mCurrent->mPrev; 1.540 + return result; } 1.541 + 1.542 + const Instantiation& operator*() const { 1.543 + return mCurrent->mInstantiation; } 1.544 + 1.545 + const Instantiation* operator->() const { 1.546 + return &mCurrent->mInstantiation; } 1.547 + 1.548 + bool operator==(const ConstIterator& aConstIterator) const { 1.549 + return mCurrent == aConstIterator.mCurrent; } 1.550 + 1.551 + bool operator!=(const ConstIterator& aConstIterator) const { 1.552 + return mCurrent != aConstIterator.mCurrent; } 1.553 + }; 1.554 + 1.555 + ConstIterator First() const { return ConstIterator(mHead.mNext); } 1.556 + ConstIterator Last() const { return ConstIterator(const_cast<List*>(&mHead)); } 1.557 + 1.558 + class Iterator : public ConstIterator { 1.559 + public: 1.560 + Iterator(List* aList) : ConstIterator(aList) {} 1.561 + 1.562 + Iterator& operator++() { 1.563 + mCurrent = mCurrent->mNext; 1.564 + return *this; } 1.565 + 1.566 + Iterator operator++(int) { 1.567 + Iterator result(*this); 1.568 + mCurrent = mCurrent->mNext; 1.569 + return result; } 1.570 + 1.571 + Iterator& operator--() { 1.572 + mCurrent = mCurrent->mPrev; 1.573 + return *this; } 1.574 + 1.575 + Iterator operator--(int) { 1.576 + Iterator result(*this); 1.577 + mCurrent = mCurrent->mPrev; 1.578 + return result; } 1.579 + 1.580 + Instantiation& operator*() const { 1.581 + return mCurrent->mInstantiation; } 1.582 + 1.583 + Instantiation* operator->() const { 1.584 + return &mCurrent->mInstantiation; } 1.585 + 1.586 + bool operator==(const ConstIterator& aConstIterator) const { 1.587 + return mCurrent == aConstIterator.mCurrent; } 1.588 + 1.589 + bool operator!=(const ConstIterator& aConstIterator) const { 1.590 + return mCurrent != aConstIterator.mCurrent; } 1.591 + 1.592 + friend class InstantiationSet; 1.593 + }; 1.594 + 1.595 + Iterator First() { return Iterator(mHead.mNext); } 1.596 + Iterator Last() { return Iterator(&mHead); } 1.597 + 1.598 + bool Empty() const { return First() == Last(); } 1.599 + 1.600 + Iterator Append(const Instantiation& aInstantiation) { 1.601 + return Insert(Last(), aInstantiation); } 1.602 + 1.603 + Iterator Insert(Iterator aBefore, const Instantiation& aInstantiation); 1.604 + 1.605 + Iterator Erase(Iterator aElement); 1.606 + 1.607 + void Clear(); 1.608 + 1.609 + bool HasAssignmentFor(nsIAtom* aVariable) const; 1.610 +}; 1.611 + 1.612 +//---------------------------------------------------------------------- 1.613 + 1.614 +/** 1.615 + * A abstract base class for all nodes in the rule network 1.616 + */ 1.617 +class ReteNode 1.618 +{ 1.619 +public: 1.620 + ReteNode() {} 1.621 + virtual ~ReteNode() {} 1.622 + 1.623 + /** 1.624 + * Propagate a set of instantiations "down" through the 1.625 + * network. Each instantiation is a partial set of 1.626 + * variable-to-value assignments, along with the memory elements 1.627 + * that support it. 1.628 + * 1.629 + * The node must evaluate each instantiation, and either 1) 1.630 + * extend it with additional assignments and memory-element 1.631 + * support, or 2) remove it from the set because it is 1.632 + * inconsistent with the constraints that this node applies. 1.633 + * 1.634 + * The node must then pass the resulting instantiation set along 1.635 + * to any of its children in the network. (In other words, the 1.636 + * node must recursively call Propagate() on its children. We 1.637 + * should fix this to make the algorithm interruptable.) 1.638 + * 1.639 + * See TestNode::Propagate for details about instantiation set ownership 1.640 + * 1.641 + * @param aInstantiations the set of instantiations to propagate 1.642 + * down through the network. 1.643 + * @param aIsUpdate true if updating, false for first generation 1.644 + * @param aTakenInstantiations true if the ownership over aInstantiations 1.645 + * has been taken from the caller. If false, 1.646 + * the caller owns it. 1.647 + * @return NS_OK if no errors occurred. 1.648 + */ 1.649 + virtual nsresult Propagate(InstantiationSet& aInstantiations, 1.650 + bool aIsUpdate, bool& aTakenInstantiations) = 0; 1.651 +}; 1.652 + 1.653 +//---------------------------------------------------------------------- 1.654 + 1.655 +/** 1.656 + * A collection of nodes in the rule network 1.657 + */ 1.658 +class ReteNodeSet 1.659 +{ 1.660 +public: 1.661 + ReteNodeSet(); 1.662 + ~ReteNodeSet(); 1.663 + 1.664 + nsresult Add(ReteNode* aNode); 1.665 + nsresult Clear(); 1.666 + 1.667 + class Iterator; 1.668 + 1.669 + class ConstIterator { 1.670 + public: 1.671 + ConstIterator(ReteNode** aNode) : mCurrent(aNode) {} 1.672 + 1.673 + ConstIterator(const ConstIterator& aConstIterator) 1.674 + : mCurrent(aConstIterator.mCurrent) {} 1.675 + 1.676 + ConstIterator& operator=(const ConstIterator& aConstIterator) { 1.677 + mCurrent = aConstIterator.mCurrent; 1.678 + return *this; } 1.679 + 1.680 + ConstIterator& operator++() { 1.681 + ++mCurrent; 1.682 + return *this; } 1.683 + 1.684 + ConstIterator operator++(int) { 1.685 + ConstIterator result(*this); 1.686 + ++mCurrent; 1.687 + return result; } 1.688 + 1.689 + const ReteNode* operator*() const { 1.690 + return *mCurrent; } 1.691 + 1.692 + const ReteNode* operator->() const { 1.693 + return *mCurrent; } 1.694 + 1.695 + bool operator==(const ConstIterator& aConstIterator) const { 1.696 + return mCurrent == aConstIterator.mCurrent; } 1.697 + 1.698 + bool operator!=(const ConstIterator& aConstIterator) const { 1.699 + return mCurrent != aConstIterator.mCurrent; } 1.700 + 1.701 + protected: 1.702 + friend class Iterator; // XXXwaterson this is so wrong! 1.703 + ReteNode** mCurrent; 1.704 + }; 1.705 + 1.706 + ConstIterator First() const { return ConstIterator(mNodes); } 1.707 + ConstIterator Last() const { return ConstIterator(mNodes + mCount); } 1.708 + 1.709 + class Iterator : public ConstIterator { 1.710 + public: 1.711 + Iterator(ReteNode** aNode) : ConstIterator(aNode) {} 1.712 + 1.713 + Iterator& operator++() { 1.714 + ++mCurrent; 1.715 + return *this; } 1.716 + 1.717 + Iterator operator++(int) { 1.718 + Iterator result(*this); 1.719 + ++mCurrent; 1.720 + return result; } 1.721 + 1.722 + ReteNode* operator*() const { 1.723 + return *mCurrent; } 1.724 + 1.725 + ReteNode* operator->() const { 1.726 + return *mCurrent; } 1.727 + 1.728 + bool operator==(const ConstIterator& aConstIterator) const { 1.729 + return mCurrent == aConstIterator.mCurrent; } 1.730 + 1.731 + bool operator!=(const ConstIterator& aConstIterator) const { 1.732 + return mCurrent != aConstIterator.mCurrent; } 1.733 + }; 1.734 + 1.735 + Iterator First() { return Iterator(mNodes); } 1.736 + Iterator Last() { return Iterator(mNodes + mCount); } 1.737 + 1.738 + int32_t Count() const { return mCount; } 1.739 + 1.740 +protected: 1.741 + ReteNode** mNodes; 1.742 + int32_t mCount; 1.743 + int32_t mCapacity; 1.744 +}; 1.745 + 1.746 +//---------------------------------------------------------------------- 1.747 + 1.748 +/** 1.749 + * A node that applies a test condition to a set of instantiations. 1.750 + * 1.751 + * This class provides implementations of Propagate() and Constrain() 1.752 + * in terms of one simple operation, FilterInstantiations(). A node 1.753 + * that is a "simple test node" in a rule network should derive from 1.754 + * this class, and need only implement FilterInstantiations(). 1.755 + */ 1.756 +class TestNode : public ReteNode 1.757 +{ 1.758 +public: 1.759 + TestNode(TestNode* aParent); 1.760 + 1.761 + /** 1.762 + * Retrieve the test node's parent 1.763 + * @return the test node's parent 1.764 + */ 1.765 + TestNode* GetParent() const { return mParent; } 1.766 + 1.767 + /** 1.768 + * Calls FilterInstantiations() on the instantiation set, and if 1.769 + * the resulting set isn't empty, propagates the new set down to 1.770 + * each of the test node's children. 1.771 + * 1.772 + * Note that the caller of Propagate is responsible for deleting 1.773 + * aInstantiations if necessary as described below. 1.774 + * 1.775 + * Propagate may be called in update or non-update mode as indicated 1.776 + * by the aIsUpdate argument. Non-update mode is used when initially 1.777 + * generating results, whereas update mode is used when the datasource 1.778 + * changes and new results might be available. 1.779 + * 1.780 + * The last node in a chain of TestNodes is always an nsInstantiationNode. 1.781 + * In non-update mode, this nsInstantiationNode will cache the results 1.782 + * in the query using the SetCachedResults method. The query processor 1.783 + * takes these cached results and creates a nsXULTemplateResultSetRDF 1.784 + * which is the enumeration returned to the template builder. This 1.785 + * nsXULTemplateResultSetRDF owns the instantiations and they will be 1.786 + * deleted when the nsXULTemplateResultSetRDF goes away. 1.787 + * 1.788 + * In update mode, the nsInstantiationNode node will iterate over the 1.789 + * instantiations itself and callback to the builder to update any matches 1.790 + * and generated content. If no instantiations match, then the builder 1.791 + * will never be called. 1.792 + * 1.793 + * Thus, the difference between update and non-update modes is that in 1.794 + * update mode, the results and instantiations have been already handled 1.795 + * whereas in non-update mode they are expected to be returned in an 1.796 + * nsXULTemplateResultSetRDF for further processing by the builder. 1.797 + * 1.798 + * Regardless, aTakenInstantiations will be set to true if the 1.799 + * ownership over aInstantiations has been transferred to a result set. 1.800 + * If set to false, the caller is still responsible for aInstantiations. 1.801 + * aTakenInstantiations will be set properly even if an error occurs. 1.802 + */ 1.803 + virtual nsresult Propagate(InstantiationSet& aInstantiations, 1.804 + bool aIsUpdate, bool& aTakenInstantiations) MOZ_OVERRIDE; 1.805 + 1.806 + /** 1.807 + * This is called by a child node on its parent to allow the 1.808 + * parent's constraints to apply to the set of instantiations. 1.809 + * 1.810 + * A node must iterate through the set of instantiations, and for 1.811 + * each instantiation, either 1) extend the instantiation by 1.812 + * adding variable-to-value assignments and memory element support 1.813 + * for those assignments, or 2) remove the instantiation because 1.814 + * it is inconsistent. 1.815 + * 1.816 + * The node must then pass the resulting set of instantiations up 1.817 + * to its parent (by recursive call; we should make this iterative 1.818 + * & interruptable at some point.) 1.819 + * 1.820 + * @param aInstantiations the set of instantiations that must 1.821 + * be constrained 1.822 + * @return NS_OK if no errors occurred 1.823 + */ 1.824 + virtual nsresult Constrain(InstantiationSet& aInstantiations); 1.825 + 1.826 + /** 1.827 + * Given a set of instantiations, filter out any that are 1.828 + * inconsistent with the test node's test, and append 1.829 + * variable-to-value assignments and memory element support for 1.830 + * those which do pass the test node's test. 1.831 + * 1.832 + * @param aInstantiations the set of instantiations to be 1.833 + * filtered 1.834 + * @param aCantHandleYet [out] true if the instantiations do not contain 1.835 + * enough information to constrain the data. May be null if this 1.836 + * isn't important to the caller. 1.837 + * @return NS_OK if no errors occurred. 1.838 + */ 1.839 + virtual nsresult FilterInstantiations(InstantiationSet& aInstantiations, 1.840 + bool* aCantHandleYet) const = 0; 1.841 + //XXX probably better named "ApplyConstraints" or "Discrminiate" or something 1.842 + 1.843 + /** 1.844 + * Add another node as a child of this node. 1.845 + * @param aNode the node to add. 1.846 + * @return NS_OK if no errors occur. 1.847 + */ 1.848 + nsresult AddChild(ReteNode* aNode) { return mKids.Add(aNode); } 1.849 + 1.850 + /** 1.851 + * Remove all the children of this node 1.852 + * @return NS_OK if no errors occur. 1.853 + */ 1.854 + nsresult RemoveAllChildren() { return mKids.Clear(); } 1.855 + 1.856 +protected: 1.857 + TestNode* mParent; 1.858 + ReteNodeSet mKids; 1.859 +}; 1.860 + 1.861 +#endif // nsRuleNetwork_h__