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.

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

mercurial