content/xul/templates/src/nsRuleNetwork.cpp

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

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

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

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     8   Implementations for the rule network classes.
    10   To Do.
    12   - Constrain() & Propagate() still feel like they are poorly named.
    13   - As do Instantiation and InstantiationSet.
    14   - Make InstantiationSet share and do copy-on-write.
    15   - Make things iterative, instead of recursive.
    17  */
    19 #include "nscore.h"
    20 #include "nsCOMPtr.h"
    21 #include "plhash.h"
    23 #include "prlog.h"
    24 #ifdef PR_LOGGING
    25 extern PRLogModuleInfo* gXULTemplateLog;
    27 #include "nsString.h"
    28 #include "nsUnicharUtils.h"
    29 #include "nsXULContentUtils.h"
    31 #endif
    33 #include "nsRuleNetwork.h"
    34 #include "nsXULTemplateResultSetRDF.h"
    35 #include "nsRDFConMemberTestNode.h"
    36 #include "nsRDFPropertyTestNode.h"
    38 using namespace mozilla;
    40 //----------------------------------------------------------------------
    41 //
    42 // nsRuleNetwork
    43 //
    45 nsresult
    46 MemoryElementSet::Add(MemoryElement* aElement)
    47 {
    48     for (ConstIterator element = First(); element != Last(); ++element) {
    49         if (*element == *aElement) {
    50             // We've already got this element covered. Since Add()
    51             // assumes ownership, and we aren't going to need this,
    52             // just nuke it.
    53             delete aElement;
    54             return NS_OK;
    55         }
    56     }
    58     List* list = new List;
    59     if (! list)
    60         return NS_ERROR_OUT_OF_MEMORY;
    62     list->mElement = aElement;
    63     list->mRefCnt  = 1;
    64     list->mNext    = mElements;
    66     mElements = list;
    68     return NS_OK;
    69 }
    72 //----------------------------------------------------------------------
    74 nsresult
    75 nsAssignmentSet::Add(const nsAssignment& aAssignment)
    76 {
    77     NS_PRECONDITION(! HasAssignmentFor(aAssignment.mVariable), "variable already bound");
    79     // XXXndeakin should this just silently fail?
    80     if (HasAssignmentFor(aAssignment.mVariable))
    81         return NS_ERROR_UNEXPECTED;
    83     List* list = new List(aAssignment);
    84     if (! list)
    85         return NS_ERROR_OUT_OF_MEMORY;
    87     list->mRefCnt     = 1;
    88     list->mNext       = mAssignments;
    90     mAssignments = list;
    92     return NS_OK;
    93 }
    95 int32_t
    96 nsAssignmentSet::Count() const
    97 {
    98     int32_t count = 0;
    99     for (ConstIterator assignment = First(); assignment != Last(); ++assignment)
   100         ++count;
   102     return count;
   103 }
   105 bool
   106 nsAssignmentSet::HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const
   107 {
   108     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
   109         if (assignment->mVariable == aVariable && assignment->mValue == aValue)
   110             return true;
   111     }
   113     return false;
   114 }
   116 bool
   117 nsAssignmentSet::HasAssignmentFor(nsIAtom* aVariable) const
   118 {
   119     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
   120         if (assignment->mVariable == aVariable)
   121             return true;
   122     }
   124     return false;
   125 }
   127 bool
   128 nsAssignmentSet::GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const
   129 {
   130     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
   131         if (assignment->mVariable == aVariable) {
   132             *aValue = assignment->mValue;
   133             NS_IF_ADDREF(*aValue);
   134             return true;
   135         }
   136     }
   138     *aValue = nullptr;
   139     return false;
   140 }
   142 bool
   143 nsAssignmentSet::Equals(const nsAssignmentSet& aSet) const
   144 {
   145     if (aSet.mAssignments == mAssignments)
   146         return true;
   148     // If they have a different number of assignments, then they're different.
   149     if (Count() != aSet.Count())
   150         return false;
   152     // XXX O(n^2)! Ugh!
   153     nsCOMPtr<nsIRDFNode> value;
   154     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
   155         if (! aSet.GetAssignmentFor(assignment->mVariable, getter_AddRefs(value)))
   156             return false;
   158         if (assignment->mValue != value)
   159             return false;
   160     }
   162     return true;
   163 }
   165 //----------------------------------------------------------------------
   167 PLHashNumber
   168 Instantiation::Hash(const void* aKey)
   169 {
   170     const Instantiation* inst = static_cast<const Instantiation*>(aKey);
   172     PLHashNumber result = 0;
   174     nsAssignmentSet::ConstIterator last = inst->mAssignments.Last();
   175     for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First();
   176          assignment != last; ++assignment)
   177         result ^= assignment->Hash();
   179     return result;
   180 }
   183 int
   184 Instantiation::Compare(const void* aLeft, const void* aRight)
   185 {
   186     const Instantiation* left  = static_cast<const Instantiation*>(aLeft);
   187     const Instantiation* right = static_cast<const Instantiation*>(aRight);
   189     return *left == *right;
   190 }
   193 //----------------------------------------------------------------------
   194 //
   195 // InstantiationSet
   196 //
   198 InstantiationSet::InstantiationSet()
   199 {
   200     mHead.mPrev = mHead.mNext = &mHead;
   201     MOZ_COUNT_CTOR(InstantiationSet);
   202 }
   205 InstantiationSet::InstantiationSet(const InstantiationSet& aInstantiationSet)
   206 {
   207     mHead.mPrev = mHead.mNext = &mHead;
   209     // XXX replace with copy-on-write foo
   210     ConstIterator last = aInstantiationSet.Last();
   211     for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
   212         Append(*inst);
   214     MOZ_COUNT_CTOR(InstantiationSet);
   215 }
   217 InstantiationSet&
   218 InstantiationSet::operator=(const InstantiationSet& aInstantiationSet)
   219 {
   220     // XXX replace with copy-on-write foo
   221     Clear();
   223     ConstIterator last = aInstantiationSet.Last();
   224     for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
   225         Append(*inst);
   227     return *this;
   228 }
   231 void
   232 InstantiationSet::Clear()
   233 {
   234     Iterator inst = First();
   235     while (inst != Last())
   236         Erase(inst++);
   237 }
   240 InstantiationSet::Iterator
   241 InstantiationSet::Insert(Iterator aIterator, const Instantiation& aInstantiation)
   242 {
   243     List* newelement = new List();
   244     if (newelement) {
   245         newelement->mInstantiation = aInstantiation;
   247         aIterator.mCurrent->mPrev->mNext = newelement;
   249         newelement->mNext = aIterator.mCurrent;
   250         newelement->mPrev = aIterator.mCurrent->mPrev;
   252         aIterator.mCurrent->mPrev = newelement;
   253     }
   254     return aIterator;
   255 }
   257 InstantiationSet::Iterator
   258 InstantiationSet::Erase(Iterator aIterator)
   259 {
   260     Iterator result = aIterator;
   261     ++result;
   262     aIterator.mCurrent->mNext->mPrev = aIterator.mCurrent->mPrev;
   263     aIterator.mCurrent->mPrev->mNext = aIterator.mCurrent->mNext;
   264     delete aIterator.mCurrent;
   265     return result;
   266 }
   269 bool
   270 InstantiationSet::HasAssignmentFor(nsIAtom* aVariable) const
   271 {
   272     return !Empty() ? First()->mAssignments.HasAssignmentFor(aVariable) : false;
   273 }
   275 //----------------------------------------------------------------------
   276 //
   277 // ReteNode
   278 //
   279 //   The basic node in the network.
   280 //
   282 //----------------------------------------------------------------------
   283 //
   284 // TestNode
   285 //
   286 //   to do:
   287 //     - FilterInstantiations() is poorly named
   288 //
   291 TestNode::TestNode(TestNode* aParent)
   292     : mParent(aParent)
   293 {
   294 }
   296 nsresult
   297 TestNode::Propagate(InstantiationSet& aInstantiations,
   298                     bool aIsUpdate, bool& aTakenInstantiations)
   299 {
   300     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   301            ("TestNode[%p]: Propagate() begin", this));
   303     aTakenInstantiations = false;
   305     nsresult rv = FilterInstantiations(aInstantiations, nullptr);
   306     if (NS_FAILED(rv))
   307         return rv;
   309     // if there is more than one child, each will need to be supplied with the
   310     // original set of instantiations from this node, so create a copy in this
   311     // case. If there is only one child, optimize and just pass the
   312     // instantiations along to the child without copying
   313     bool shouldCopy = (mKids.Count() > 1);
   315     // See the header file for details about how instantiation ownership works.
   316     if (! aInstantiations.Empty()) {
   317         ReteNodeSet::Iterator last = mKids.Last();
   318         for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid) {
   319             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   320                    ("TestNode[%p]: Propagate() passing to child %p", this, kid.operator->()));
   322             // create a copy of the instantiations
   323             if (shouldCopy) {
   324                 bool owned = false;
   325                 InstantiationSet* instantiations =
   326                     new InstantiationSet(aInstantiations);
   327                 if (!instantiations)
   328                     return NS_ERROR_OUT_OF_MEMORY;
   329                 rv = kid->Propagate(*instantiations, aIsUpdate, owned);
   330                 if (!owned)
   331                     delete instantiations;
   332                 if (NS_FAILED(rv))
   333                     return rv;
   334             }
   335             else {
   336                 rv = kid->Propagate(aInstantiations, aIsUpdate, aTakenInstantiations);
   337                 if (NS_FAILED(rv))
   338                     return rv;
   339             }
   340         }
   341     }
   343     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   344            ("TestNode[%p]: Propagate() end", this));
   346     return NS_OK;
   347 }
   350 nsresult
   351 TestNode::Constrain(InstantiationSet& aInstantiations)
   352 {
   353     nsresult rv;
   355     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   356            ("TestNode[%p]: Constrain() begin", this));
   358     // if the cantHandleYet flag is set by FilterInstantiations,
   359     // there isn't enough information yet available to fill in.
   360     // For this, continue the constrain all the way to the top
   361     // and then call FilterInstantiations again afterwards. This
   362     // should fill in any missing information.
   363     bool cantHandleYet = false;
   364     rv = FilterInstantiations(aInstantiations, &cantHandleYet);
   365     if (NS_FAILED(rv)) return rv;
   367     if (mParent && (!aInstantiations.Empty() || cantHandleYet)) {
   368         // if we still have instantiations, or if the instantiations
   369         // could not be filled in yet, then ride 'em on up to the
   370         // parent to narrow them.
   372         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   373                ("TestNode[%p]: Constrain() passing to parent %p", this, mParent));
   375         rv = mParent->Constrain(aInstantiations);
   377         if (NS_SUCCEEDED(rv) && cantHandleYet)
   378             rv = FilterInstantiations(aInstantiations, nullptr);
   379     }
   380     else {
   381         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   382                ("TestNode[%p]: Constrain() failed", this));
   384         rv = NS_OK;
   385     }
   387     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
   388            ("TestNode[%p]: Constrain() end", this));
   390     return rv;
   391 }
   394 //----------------------------------------------------------------------
   396 ReteNodeSet::ReteNodeSet()
   397     : mNodes(nullptr), mCount(0), mCapacity(0)
   398 {
   399 }
   401 ReteNodeSet::~ReteNodeSet()
   402 {
   403     Clear();
   404 }
   406 nsresult
   407 ReteNodeSet::Add(ReteNode* aNode)
   408 {
   409     NS_PRECONDITION(aNode != nullptr, "null ptr");
   410     if (! aNode)
   411         return NS_ERROR_NULL_POINTER;
   413     if (mCount >= mCapacity) {
   414         int32_t capacity = mCapacity + 4;
   415         ReteNode** nodes = new ReteNode*[capacity];
   416         if (! nodes)
   417             return NS_ERROR_OUT_OF_MEMORY;
   419         for (int32_t i = mCount - 1; i >= 0; --i)
   420             nodes[i] = mNodes[i];
   422         delete[] mNodes;
   424         mNodes = nodes;
   425         mCapacity = capacity;
   426     }
   428     mNodes[mCount++] = aNode;
   429     return NS_OK;
   430 }
   432 nsresult
   433 ReteNodeSet::Clear()
   434 {
   435     delete[] mNodes;
   436     mNodes = nullptr;
   437     mCount = mCapacity = 0;
   438     return NS_OK;
   439 }

mercurial