nsRuleNetwork.h 27 KB

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