LCOV - code coverage report
Current view: directory - content/xul/templates/src - nsRuleNetwork.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 188 2 1.1 %
Date: 2012-06-02 Functions: 27 2 7.4 %

       1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2000
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *   Chris Waterson <waterson@netscape.com>
      24                 :  *   Neil Deakin <enndeakin@sympatico.ca>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : /*
      41                 : 
      42                 :   Implementations for the rule network classes.
      43                 : 
      44                 :   To Do.
      45                 : 
      46                 :   - Constrain() & Propagate() still feel like they are poorly named.
      47                 :   - As do Instantiation and InstantiationSet.
      48                 :   - Make InstantiationSet share and do copy-on-write.
      49                 :   - Make things iterative, instead of recursive.
      50                 : 
      51                 :  */
      52                 : 
      53                 : #include "mozilla/Util.h"
      54                 : 
      55                 : #include "nscore.h"
      56                 : #include "nsCOMPtr.h"
      57                 : #include "nsCRT.h"
      58                 : #include "nsIComponentManager.h"
      59                 : #include "nsIContent.h"
      60                 : #include "plhash.h"
      61                 : #include "nsReadableUtils.h"
      62                 : 
      63                 : #include "prlog.h"
      64                 : #ifdef PR_LOGGING
      65                 : extern PRLogModuleInfo* gXULTemplateLog;
      66                 : 
      67                 : #include "nsString.h"
      68                 : #include "nsUnicharUtils.h"
      69                 : #include "nsXULContentUtils.h"
      70                 : 
      71                 : #endif
      72                 : 
      73                 : #include "nsRuleNetwork.h"
      74                 : #include "nsXULTemplateResultSetRDF.h"
      75                 : #include "nsRDFConMemberTestNode.h"
      76                 : #include "nsRDFPropertyTestNode.h"
      77                 : 
      78                 : using namespace mozilla;
      79                 : 
      80                 : bool MemoryElement::gPoolInited;
      81            1464 : nsFixedSizeAllocator MemoryElement::gPool;
      82                 : 
      83                 : // static
      84                 : bool
      85               0 : MemoryElement::Init()
      86                 : {
      87               0 :     if (!gPoolInited) {
      88                 :         const size_t bucketsizes[] = {
      89                 :             sizeof (nsRDFConMemberTestNode::Element),
      90                 :             sizeof (nsRDFPropertyTestNode::Element)
      91               0 :         };
      92                 : 
      93               0 :         if (NS_FAILED(gPool.Init("MemoryElement", bucketsizes,
      94                 :                                  ArrayLength(bucketsizes), 256)))
      95               0 :             return false;
      96                 : 
      97               0 :         gPoolInited = true;
      98                 :     }
      99                 : 
     100               0 :     return true;
     101                 : }
     102                 : 
     103                 : //----------------------------------------------------------------------
     104                 : //
     105                 : // nsRuleNetwork
     106                 : //
     107                 : 
     108                 : nsresult
     109               0 : MemoryElementSet::Add(MemoryElement* aElement)
     110                 : {
     111               0 :     for (ConstIterator element = First(); element != Last(); ++element) {
     112               0 :         if (*element == *aElement) {
     113                 :             // We've already got this element covered. Since Add()
     114                 :             // assumes ownership, and we aren't going to need this,
     115                 :             // just nuke it.
     116               0 :             aElement->Destroy();
     117               0 :             return NS_OK;
     118                 :         }
     119                 :     }
     120                 : 
     121               0 :     List* list = new List;
     122               0 :     if (! list)
     123               0 :         return NS_ERROR_OUT_OF_MEMORY;
     124                 : 
     125               0 :     list->mElement = aElement;
     126               0 :     list->mRefCnt  = 1;
     127               0 :     list->mNext    = mElements;
     128                 : 
     129               0 :     mElements = list;
     130                 : 
     131               0 :     return NS_OK;
     132                 : }
     133                 : 
     134                 : 
     135                 : //----------------------------------------------------------------------
     136                 : 
     137                 : nsresult
     138               0 : nsAssignmentSet::Add(const nsAssignment& aAssignment)
     139                 : {
     140               0 :     NS_PRECONDITION(! HasAssignmentFor(aAssignment.mVariable), "variable already bound");
     141                 : 
     142                 :     // XXXndeakin should this just silently fail?
     143               0 :     if (HasAssignmentFor(aAssignment.mVariable))
     144               0 :         return NS_ERROR_UNEXPECTED;
     145                 : 
     146               0 :     List* list = new List(aAssignment);
     147               0 :     if (! list)
     148               0 :         return NS_ERROR_OUT_OF_MEMORY;
     149                 : 
     150               0 :     list->mRefCnt     = 1;
     151               0 :     list->mNext       = mAssignments;
     152                 : 
     153               0 :     mAssignments = list;
     154                 : 
     155               0 :     return NS_OK;
     156                 : }
     157                 : 
     158                 : PRInt32
     159               0 : nsAssignmentSet::Count() const
     160                 : {
     161               0 :     PRInt32 count = 0;
     162               0 :     for (ConstIterator assignment = First(); assignment != Last(); ++assignment)
     163               0 :         ++count;
     164                 : 
     165               0 :     return count;
     166                 : }
     167                 : 
     168                 : bool
     169               0 : nsAssignmentSet::HasAssignment(nsIAtom* aVariable, nsIRDFNode* aValue) const
     170                 : {
     171               0 :     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
     172               0 :         if (assignment->mVariable == aVariable && assignment->mValue == aValue)
     173               0 :             return true;
     174                 :     }
     175                 : 
     176               0 :     return false;
     177                 : }
     178                 : 
     179                 : bool
     180               0 : nsAssignmentSet::HasAssignmentFor(nsIAtom* aVariable) const
     181                 : {
     182               0 :     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
     183               0 :         if (assignment->mVariable == aVariable)
     184               0 :             return true;
     185                 :     }
     186                 : 
     187               0 :     return false;
     188                 : }
     189                 : 
     190                 : bool
     191               0 : nsAssignmentSet::GetAssignmentFor(nsIAtom* aVariable, nsIRDFNode** aValue) const
     192                 : {
     193               0 :     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
     194               0 :         if (assignment->mVariable == aVariable) {
     195               0 :             *aValue = assignment->mValue;
     196               0 :             NS_IF_ADDREF(*aValue);
     197               0 :             return true;
     198                 :         }
     199                 :     }
     200                 : 
     201               0 :     *aValue = nsnull;
     202               0 :     return false;
     203                 : }
     204                 : 
     205                 : bool
     206               0 : nsAssignmentSet::Equals(const nsAssignmentSet& aSet) const
     207                 : {
     208               0 :     if (aSet.mAssignments == mAssignments)
     209               0 :         return true;
     210                 : 
     211                 :     // If they have a different number of assignments, then they're different.
     212               0 :     if (Count() != aSet.Count())
     213               0 :         return false;
     214                 : 
     215                 :     // XXX O(n^2)! Ugh!
     216               0 :     nsCOMPtr<nsIRDFNode> value;
     217               0 :     for (ConstIterator assignment = First(); assignment != Last(); ++assignment) {
     218               0 :         if (! aSet.GetAssignmentFor(assignment->mVariable, getter_AddRefs(value)))
     219               0 :             return false;
     220                 : 
     221               0 :         if (assignment->mValue != value)
     222               0 :             return false;
     223                 :     }
     224                 : 
     225               0 :     return true;
     226                 : }
     227                 : 
     228                 : //----------------------------------------------------------------------
     229                 : 
     230                 : PLHashNumber
     231               0 : Instantiation::Hash(const void* aKey)
     232                 : {
     233               0 :     const Instantiation* inst = static_cast<const Instantiation*>(aKey);
     234                 : 
     235               0 :     PLHashNumber result = 0;
     236                 : 
     237               0 :     nsAssignmentSet::ConstIterator last = inst->mAssignments.Last();
     238               0 :     for (nsAssignmentSet::ConstIterator assignment = inst->mAssignments.First();
     239                 :          assignment != last; ++assignment)
     240               0 :         result ^= assignment->Hash();
     241                 : 
     242               0 :     return result;
     243                 : }
     244                 : 
     245                 : 
     246                 : PRIntn
     247               0 : Instantiation::Compare(const void* aLeft, const void* aRight)
     248                 : {
     249               0 :     const Instantiation* left  = static_cast<const Instantiation*>(aLeft);
     250               0 :     const Instantiation* right = static_cast<const Instantiation*>(aRight);
     251                 : 
     252               0 :     return *left == *right;
     253                 : }
     254                 : 
     255                 : 
     256                 : //----------------------------------------------------------------------
     257                 : //
     258                 : // InstantiationSet
     259                 : //
     260                 : 
     261               0 : InstantiationSet::InstantiationSet()
     262                 : {
     263               0 :     mHead.mPrev = mHead.mNext = &mHead;
     264               0 :     MOZ_COUNT_CTOR(InstantiationSet);
     265               0 : }
     266                 : 
     267                 : 
     268               0 : InstantiationSet::InstantiationSet(const InstantiationSet& aInstantiationSet)
     269                 : {
     270               0 :     mHead.mPrev = mHead.mNext = &mHead;
     271                 : 
     272                 :     // XXX replace with copy-on-write foo
     273               0 :     ConstIterator last = aInstantiationSet.Last();
     274               0 :     for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
     275               0 :         Append(*inst);
     276                 : 
     277               0 :     MOZ_COUNT_CTOR(InstantiationSet);
     278               0 : }
     279                 : 
     280                 : InstantiationSet&
     281               0 : InstantiationSet::operator=(const InstantiationSet& aInstantiationSet)
     282                 : {
     283                 :     // XXX replace with copy-on-write foo
     284               0 :     Clear();
     285                 : 
     286               0 :     ConstIterator last = aInstantiationSet.Last();
     287               0 :     for (ConstIterator inst = aInstantiationSet.First(); inst != last; ++inst)
     288               0 :         Append(*inst);
     289                 : 
     290               0 :     return *this;
     291                 : }
     292                 : 
     293                 : 
     294                 : void
     295               0 : InstantiationSet::Clear()
     296                 : {
     297               0 :     Iterator inst = First();
     298               0 :     while (inst != Last())
     299               0 :         Erase(inst++);
     300               0 : }
     301                 : 
     302                 : 
     303                 : InstantiationSet::Iterator
     304               0 : InstantiationSet::Insert(Iterator aIterator, const Instantiation& aInstantiation)
     305                 : {
     306               0 :     List* newelement = new List();
     307               0 :     if (newelement) {
     308               0 :         newelement->mInstantiation = aInstantiation;
     309                 : 
     310               0 :         aIterator.mCurrent->mPrev->mNext = newelement;
     311                 : 
     312               0 :         newelement->mNext = aIterator.mCurrent;
     313               0 :         newelement->mPrev = aIterator.mCurrent->mPrev;
     314                 : 
     315               0 :         aIterator.mCurrent->mPrev = newelement;
     316                 :     }
     317               0 :     return aIterator;
     318                 : }
     319                 : 
     320                 : InstantiationSet::Iterator
     321               0 : InstantiationSet::Erase(Iterator aIterator)
     322                 : {
     323               0 :     Iterator result = aIterator;
     324               0 :     ++result;
     325               0 :     aIterator.mCurrent->mNext->mPrev = aIterator.mCurrent->mPrev;
     326               0 :     aIterator.mCurrent->mPrev->mNext = aIterator.mCurrent->mNext;
     327               0 :     delete aIterator.mCurrent;
     328                 :     return result;
     329                 : }
     330                 : 
     331                 : 
     332                 : bool
     333               0 : InstantiationSet::HasAssignmentFor(nsIAtom* aVariable) const
     334                 : {
     335               0 :     return !Empty() ? First()->mAssignments.HasAssignmentFor(aVariable) : false;
     336                 : }
     337                 : 
     338                 : //----------------------------------------------------------------------
     339                 : //
     340                 : // ReteNode
     341                 : //
     342                 : //   The basic node in the network.
     343                 : //
     344                 : 
     345                 : //----------------------------------------------------------------------
     346                 : //
     347                 : // TestNode
     348                 : //
     349                 : //   to do:
     350                 : //     - FilterInstantiations() is poorly named
     351                 : //
     352                 : 
     353                 : 
     354               0 : TestNode::TestNode(TestNode* aParent)
     355               0 :     : mParent(aParent)
     356                 : {
     357               0 : }
     358                 : 
     359                 : nsresult
     360               0 : TestNode::Propagate(InstantiationSet& aInstantiations,
     361                 :                     bool aIsUpdate, bool& aTakenInstantiations)
     362                 : {
     363               0 :     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     364                 :            ("TestNode[%p]: Propagate() begin", this));
     365                 : 
     366               0 :     aTakenInstantiations = false;
     367                 : 
     368               0 :     nsresult rv = FilterInstantiations(aInstantiations, nsnull);
     369               0 :     if (NS_FAILED(rv))
     370               0 :         return rv;
     371                 : 
     372                 :     // if there is more than one child, each will need to be supplied with the
     373                 :     // original set of instantiations from this node, so create a copy in this
     374                 :     // case. If there is only one child, optimize and just pass the
     375                 :     // instantiations along to the child without copying
     376               0 :     bool shouldCopy = (mKids.Count() > 1);
     377                 : 
     378                 :     // See the header file for details about how instantiation ownership works.
     379               0 :     if (! aInstantiations.Empty()) {
     380               0 :         ReteNodeSet::Iterator last = mKids.Last();
     381               0 :         for (ReteNodeSet::Iterator kid = mKids.First(); kid != last; ++kid) {
     382               0 :             PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     383                 :                    ("TestNode[%p]: Propagate() passing to child %p", this, kid.operator->()));
     384                 : 
     385                 :             // create a copy of the instantiations
     386               0 :             if (shouldCopy) {
     387               0 :                 bool owned = false;
     388                 :                 InstantiationSet* instantiations =
     389               0 :                     new InstantiationSet(aInstantiations);
     390               0 :                 if (!instantiations)
     391               0 :                     return NS_ERROR_OUT_OF_MEMORY;
     392               0 :                 rv = kid->Propagate(*instantiations, aIsUpdate, owned);
     393               0 :                 if (!owned)
     394               0 :                     delete instantiations;
     395               0 :                 if (NS_FAILED(rv))
     396               0 :                     return rv;
     397                 :             }
     398                 :             else {
     399               0 :                 rv = kid->Propagate(aInstantiations, aIsUpdate, aTakenInstantiations);
     400               0 :                 if (NS_FAILED(rv))
     401               0 :                     return rv;
     402                 :             }
     403                 :         }
     404                 :     }
     405                 : 
     406               0 :     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     407                 :            ("TestNode[%p]: Propagate() end", this));
     408                 : 
     409               0 :     return NS_OK;
     410                 : }
     411                 : 
     412                 : 
     413                 : nsresult
     414               0 : TestNode::Constrain(InstantiationSet& aInstantiations)
     415                 : {
     416                 :     nsresult rv;
     417                 : 
     418               0 :     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     419                 :            ("TestNode[%p]: Constrain() begin", this));
     420                 : 
     421                 :     // if the cantHandleYet flag is set by FilterInstantiations,
     422                 :     // there isn't enough information yet available to fill in.
     423                 :     // For this, continue the constrain all the way to the top
     424                 :     // and then call FilterInstantiations again afterwards. This
     425                 :     // should fill in any missing information.
     426               0 :     bool cantHandleYet = false;
     427               0 :     rv = FilterInstantiations(aInstantiations, &cantHandleYet);
     428               0 :     if (NS_FAILED(rv)) return rv;
     429                 : 
     430               0 :     if (mParent && (!aInstantiations.Empty() || cantHandleYet)) {
     431                 :         // if we still have instantiations, or if the instantiations
     432                 :         // could not be filled in yet, then ride 'em on up to the
     433                 :         // parent to narrow them.
     434                 : 
     435               0 :         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     436                 :                ("TestNode[%p]: Constrain() passing to parent %p", this, mParent));
     437                 : 
     438               0 :         rv = mParent->Constrain(aInstantiations);
     439                 : 
     440               0 :         if (NS_SUCCEEDED(rv) && cantHandleYet)
     441               0 :             rv = FilterInstantiations(aInstantiations, nsnull);
     442                 :     }
     443                 :     else {
     444               0 :         PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     445                 :                ("TestNode[%p]: Constrain() failed", this));
     446                 : 
     447               0 :         rv = NS_OK;
     448                 :     }
     449                 : 
     450               0 :     PR_LOG(gXULTemplateLog, PR_LOG_DEBUG,
     451                 :            ("TestNode[%p]: Constrain() end", this));
     452                 : 
     453               0 :     return rv;
     454                 : }
     455                 : 
     456                 : 
     457                 : //----------------------------------------------------------------------
     458                 : 
     459               0 : ReteNodeSet::ReteNodeSet()
     460               0 :     : mNodes(nsnull), mCount(0), mCapacity(0)
     461                 : {
     462               0 : }
     463                 : 
     464               0 : ReteNodeSet::~ReteNodeSet()
     465                 : {
     466               0 :     Clear();
     467               0 : }
     468                 : 
     469                 : nsresult
     470               0 : ReteNodeSet::Add(ReteNode* aNode)
     471                 : {
     472               0 :     NS_PRECONDITION(aNode != nsnull, "null ptr");
     473               0 :     if (! aNode)
     474               0 :         return NS_ERROR_NULL_POINTER;
     475                 : 
     476               0 :     if (mCount >= mCapacity) {
     477               0 :         PRInt32 capacity = mCapacity + 4;
     478               0 :         ReteNode** nodes = new ReteNode*[capacity];
     479               0 :         if (! nodes)
     480               0 :             return NS_ERROR_OUT_OF_MEMORY;
     481                 : 
     482               0 :         for (PRInt32 i = mCount - 1; i >= 0; --i)
     483               0 :             nodes[i] = mNodes[i];
     484                 : 
     485               0 :         delete[] mNodes;
     486                 : 
     487               0 :         mNodes = nodes;
     488               0 :         mCapacity = capacity;
     489                 :     }
     490                 : 
     491               0 :     mNodes[mCount++] = aNode;
     492               0 :     return NS_OK;
     493                 : }
     494                 : 
     495                 : nsresult
     496               0 : ReteNodeSet::Clear()
     497                 : {
     498               0 :     delete[] mNodes;
     499               0 :     mNodes = nsnull;
     500               0 :     mCount = mCapacity = 0;
     501               0 :     return NS_OK;
     502            4392 : }

Generated by: LCOV version 1.7