rdf/base/src/nsInMemoryDataSource.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  *
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  *
     7  *
     8  * This Original Code has been modified by IBM Corporation.
     9  * Modifications made by IBM described herein are
    10  * Copyright (c) International Business Machines
    11  * Corporation, 2000
    12  *
    13  * Modifications to Mozilla code or documentation
    14  * identified per MPL Section 3.3
    15  *
    16  * Date         Modified by     Description of modification
    17  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
    18  *                               use in OS2
    19  */
    21 /*
    23   Implementation for an in-memory RDF data store.
    25   TO DO
    27   1) Instrument this code to gather space and time performance
    28      characteristics.
    30   2) Optimize lookups for datasources which have a small number
    31      of properties + fanning out to a large number of targets.
    33   3) Complete implementation of thread-safety; specifically, make
    34      assertions be reference counted objects (so that a cursor can
    35      still refer to an assertion that gets removed from the graph).
    37  */
    39 #include "nsAgg.h"
    40 #include "nsCOMPtr.h"
    41 #include "nscore.h"
    42 #include "nsArrayEnumerator.h"
    43 #include "nsIOutputStream.h"
    44 #include "nsIRDFDataSource.h"
    45 #include "nsIRDFLiteral.h"
    46 #include "nsIRDFNode.h"
    47 #include "nsIRDFObserver.h"
    48 #include "nsIRDFInMemoryDataSource.h"
    49 #include "nsIRDFPropagatableDataSource.h"
    50 #include "nsIRDFPurgeableDataSource.h"
    51 #include "nsIRDFService.h"
    52 #include "nsIServiceManager.h"
    53 #include "nsISupportsArray.h"
    54 #include "nsCOMArray.h"
    55 #include "nsEnumeratorUtils.h"
    56 #include "nsTArray.h"
    57 #include "nsCRT.h"
    58 #include "nsRDFCID.h"
    59 #include "nsRDFBaseDataSources.h"
    60 #include "nsString.h"
    61 #include "nsReadableUtils.h"
    62 #include "nsXPIDLString.h"
    63 #include "rdfutil.h"
    64 #include "pldhash.h"
    65 #include "plstr.h"
    66 #include "prlog.h"
    67 #include "rdf.h"
    69 #include "rdfIDataSource.h"
    70 #include "rdfITripleVisitor.h"
    72 // This struct is used as the slot value in the forward and reverse
    73 // arcs hash tables.
    74 //
    75 // Assertion objects are reference counted, because each Assertion's
    76 // ownership is shared between the datasource and any enumerators that
    77 // are currently iterating over the datasource.
    78 //
    79 class Assertion
    80 {
    81 public:
    82     static PLDHashOperator
    83     DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
    84                            uint32_t aNumber, void* aArg);
    86     Assertion(nsIRDFResource* aSource,      // normal assertion
    87               nsIRDFResource* aProperty,
    88               nsIRDFNode* aTarget,
    89               bool aTruthValue);
    90     Assertion(nsIRDFResource* aSource);     // PLDHashTable assertion variant
    92     ~Assertion();
    94     void AddRef() {
    95         if (mRefCnt == UINT16_MAX) {
    96             NS_WARNING("refcount overflow, leaking Assertion");
    97             return;
    98         }
    99         ++mRefCnt;
   100     }
   102     void Release() {
   103         if (mRefCnt == UINT16_MAX) {
   104             NS_WARNING("refcount overflow, leaking Assertion");
   105             return;
   106         }
   107         if (--mRefCnt == 0)
   108             delete this;
   109     }
   111     // For nsIRDFPurgeableDataSource
   112     inline  void    Mark()      { u.as.mMarked = true; }
   113     inline  bool    IsMarked()  { return u.as.mMarked; }
   114     inline  void    Unmark()    { u.as.mMarked = false; }
   116     // public for now, because I'm too lazy to go thru and clean this up.
   118     // These are shared between hash/as (see the union below)
   119     nsIRDFResource*         mSource;
   120     Assertion*              mNext;
   122     union
   123     {
   124         struct hash
   125         {
   126             PLDHashTable*   mPropertyHash; 
   127         } hash;
   128         struct as
   129         {
   130             nsIRDFResource* mProperty;
   131             nsIRDFNode*     mTarget;
   132             Assertion*      mInvNext;
   133             // make sure bool are final elements
   134             bool            mTruthValue;
   135             bool            mMarked;
   136         } as;
   137     } u;
   139     // also shared between hash/as (see the union above)
   140     // but placed after union definition to ensure that
   141     // all 32-bit entries are long aligned
   142     uint16_t                    mRefCnt;
   143     bool                        mHashEntry;
   144 };
   147 struct Entry {
   148     PLDHashEntryHdr mHdr;
   149     nsIRDFNode*     mNode;
   150     Assertion*      mAssertions;
   151 };
   154 Assertion::Assertion(nsIRDFResource* aSource)
   155     : mSource(aSource),
   156       mNext(nullptr),
   157       mRefCnt(0),
   158       mHashEntry(true)
   159 {
   160     MOZ_COUNT_CTOR(RDF_Assertion);
   162     NS_ADDREF(mSource);
   164     u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(),
   165                       nullptr, sizeof(Entry), PL_DHASH_MIN_SIZE);
   166 }
   168 Assertion::Assertion(nsIRDFResource* aSource,
   169                      nsIRDFResource* aProperty,
   170                      nsIRDFNode* aTarget,
   171                      bool aTruthValue)
   172     : mSource(aSource),
   173       mNext(nullptr),
   174       mRefCnt(0),
   175       mHashEntry(false)
   176 {
   177     MOZ_COUNT_CTOR(RDF_Assertion);
   179     u.as.mProperty = aProperty;
   180     u.as.mTarget = aTarget;
   182     NS_ADDREF(mSource);
   183     NS_ADDREF(u.as.mProperty);
   184     NS_ADDREF(u.as.mTarget);
   186     u.as.mInvNext = nullptr;
   187     u.as.mTruthValue = aTruthValue;
   188     u.as.mMarked = false;
   189 }
   191 Assertion::~Assertion()
   192 {
   193     if (mHashEntry && u.hash.mPropertyHash) {
   194         PL_DHashTableEnumerate(u.hash.mPropertyHash, DeletePropertyHashEntry,
   195                                nullptr);
   196         PL_DHashTableDestroy(u.hash.mPropertyHash);
   197         u.hash.mPropertyHash = nullptr;
   198     }
   200     MOZ_COUNT_DTOR(RDF_Assertion);
   201 #ifdef DEBUG_REFS
   202     --gInstanceCount;
   203     fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
   204 #endif
   206     NS_RELEASE(mSource);
   207     if (!mHashEntry)
   208     {
   209         NS_RELEASE(u.as.mProperty);
   210         NS_RELEASE(u.as.mTarget);
   211     }
   212 }
   214 PLDHashOperator
   215 Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   216                                            uint32_t aNumber, void* aArg)
   217 {
   218     Entry* entry = reinterpret_cast<Entry*>(aHdr);
   220     Assertion* as = entry->mAssertions;
   221     while (as) {
   222         Assertion* doomed = as;
   223         as = as->mNext;
   225         // Unlink, and release the datasource's reference.
   226         doomed->mNext = doomed->u.as.mInvNext = nullptr;
   227         doomed->Release();
   228     }
   229     return PL_DHASH_NEXT;
   230 }
   234 ////////////////////////////////////////////////////////////////////////
   235 // InMemoryDataSource
   236 class InMemoryArcsEnumeratorImpl;
   237 class InMemoryAssertionEnumeratorImpl;
   238 class InMemoryResourceEnumeratorImpl;
   240 class InMemoryDataSource : public nsIRDFDataSource,
   241                            public nsIRDFInMemoryDataSource,
   242                            public nsIRDFPropagatableDataSource,
   243                            public nsIRDFPurgeableDataSource,
   244                            public rdfIDataSource
   245 {
   246 protected:
   247     // These hash tables are keyed on pointers to nsIRDFResource
   248     // objects (the nsIRDFService ensures that there is only ever one
   249     // nsIRDFResource object per unique URI). The value of an entry is
   250     // an Assertion struct, which is a linked list of (subject
   251     // predicate object) triples.
   252     PLDHashTable mForwardArcs; 
   253     PLDHashTable mReverseArcs; 
   255     nsCOMArray<nsIRDFObserver> mObservers;  
   256     uint32_t                   mNumObservers;
   258     // VisitFoo needs to block writes, [Un]Assert only allowed
   259     // during mReadCount == 0
   260     uint32_t mReadCount;
   262     static PLDHashOperator
   263     DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   264                            uint32_t aNumber, void* aArg);
   266     static PLDHashOperator
   267     ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   268                        uint32_t aNumber, void* aArg);
   270     friend class InMemoryArcsEnumeratorImpl;
   271     friend class InMemoryAssertionEnumeratorImpl;
   272     friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
   274     // Thread-safe writer implementation methods.
   275     nsresult
   276     LockedAssert(nsIRDFResource* source, 
   277                  nsIRDFResource* property, 
   278                  nsIRDFNode* target,
   279                  bool tv);
   281     nsresult
   282     LockedUnassert(nsIRDFResource* source,
   283                    nsIRDFResource* property,
   284                    nsIRDFNode* target);
   286     InMemoryDataSource(nsISupports* aOuter);
   287     virtual ~InMemoryDataSource();
   288     nsresult Init();
   290     friend nsresult
   291     NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
   293 public:
   294     NS_DECL_CYCLE_COLLECTING_AGGREGATED
   295     NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
   297     // nsIRDFDataSource methods
   298     NS_DECL_NSIRDFDATASOURCE
   300     // nsIRDFInMemoryDataSource methods
   301     NS_DECL_NSIRDFINMEMORYDATASOURCE
   303     // nsIRDFPropagatableDataSource methods
   304     NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
   306     // nsIRDFPurgeableDataSource methods
   307     NS_DECL_NSIRDFPURGEABLEDATASOURCE
   309     // rdfIDataSource methods
   310     NS_DECL_RDFIDATASOURCE
   312 protected:
   313     static PLDHashOperator
   314     SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   315                             uint32_t aNumber, void* aArg);
   317 public:
   318     // Implementation methods
   319     Assertion*
   320     GetForwardArcs(nsIRDFResource* u) {
   321         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, PL_DHASH_LOOKUP);
   322         return PL_DHASH_ENTRY_IS_BUSY(hdr)
   323             ? reinterpret_cast<Entry*>(hdr)->mAssertions
   324             : nullptr; }
   326     Assertion*
   327     GetReverseArcs(nsIRDFNode* v) {
   328         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, PL_DHASH_LOOKUP);
   329         return PL_DHASH_ENTRY_IS_BUSY(hdr)
   330             ? reinterpret_cast<Entry*>(hdr)->mAssertions
   331             : nullptr; }
   333     void
   334     SetForwardArcs(nsIRDFResource* u, Assertion* as) {
   335         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u,
   336                                                     as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
   337         if (as && hdr) {
   338             Entry* entry = reinterpret_cast<Entry*>(hdr);
   339             entry->mNode = u;
   340             entry->mAssertions = as;
   341         } }
   343     void
   344     SetReverseArcs(nsIRDFNode* v, Assertion* as) {
   345         PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v,
   346                                                     as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
   347         if (as && hdr) {
   348             Entry* entry = reinterpret_cast<Entry*>(hdr);
   349             entry->mNode = v;
   350             entry->mAssertions = as;
   351         } }
   353 #ifdef PR_LOGGING
   354     void
   355     LogOperation(const char* aOperation,
   356                  nsIRDFResource* asource,
   357                  nsIRDFResource* aProperty,
   358                  nsIRDFNode* aTarget,
   359                  bool aTruthValue = true);
   360 #endif
   362     bool    mPropagateChanges;
   364 private:
   365 #ifdef PR_LOGGING
   366     static PRLogModuleInfo* gLog;
   367 #endif
   368 };
   370 #ifdef PR_LOGGING
   371 PRLogModuleInfo* InMemoryDataSource::gLog;
   372 #endif
   374 //----------------------------------------------------------------------
   375 //
   376 // InMemoryAssertionEnumeratorImpl
   377 //
   379 /**
   380  * InMemoryAssertionEnumeratorImpl
   381  */
   382 class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
   383 {
   384 private:
   385     InMemoryDataSource* mDataSource;
   386     nsIRDFResource* mSource;
   387     nsIRDFResource* mProperty;
   388     nsIRDFNode*     mTarget;
   389     nsIRDFNode*     mValue;
   390     bool            mTruthValue;
   391     Assertion*      mNextAssertion;
   392     nsCOMPtr<nsISupportsArray> mHashArcs;
   394 public:
   395     InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
   396                                     nsIRDFResource* aSource,
   397                                     nsIRDFResource* aProperty,
   398                                     nsIRDFNode* aTarget,
   399                                     bool aTruthValue);
   401     virtual ~InMemoryAssertionEnumeratorImpl();
   403     // nsISupports interface
   404     NS_DECL_ISUPPORTS
   406     // nsISimpleEnumerator interface
   407     NS_DECL_NSISIMPLEENUMERATOR
   408 };
   410 ////////////////////////////////////////////////////////////////////////
   413 InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
   414                  InMemoryDataSource* aDataSource,
   415                  nsIRDFResource* aSource,
   416                  nsIRDFResource* aProperty,
   417                  nsIRDFNode* aTarget,
   418                  bool aTruthValue)
   419     : mDataSource(aDataSource),
   420       mSource(aSource),
   421       mProperty(aProperty),
   422       mTarget(aTarget),
   423       mValue(nullptr),
   424       mTruthValue(aTruthValue),
   425       mNextAssertion(nullptr)
   426 {
   427     NS_ADDREF(mDataSource);
   428     NS_IF_ADDREF(mSource);
   429     NS_ADDREF(mProperty);
   430     NS_IF_ADDREF(mTarget);
   432     if (mSource) {
   433         mNextAssertion = mDataSource->GetForwardArcs(mSource);
   435         if (mNextAssertion && mNextAssertion->mHashEntry) {
   436             // its our magical HASH_ENTRY forward hash for assertions
   437             PLDHashEntryHdr* hdr = PL_DHashTableOperate(mNextAssertion->u.hash.mPropertyHash,
   438                 aProperty, PL_DHASH_LOOKUP);
   439             mNextAssertion = PL_DHASH_ENTRY_IS_BUSY(hdr)
   440                 ? reinterpret_cast<Entry*>(hdr)->mAssertions
   441                 : nullptr;
   442         }
   443     }
   444     else {
   445         mNextAssertion = mDataSource->GetReverseArcs(mTarget);
   446     }
   448     // Add an owning reference from the enumerator
   449     if (mNextAssertion)
   450         mNextAssertion->AddRef();
   451 }
   453 InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
   454 {
   455 #ifdef DEBUG_REFS
   456     --gInstanceCount;
   457     fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
   458 #endif
   460     if (mNextAssertion)
   461         mNextAssertion->Release();
   463     NS_IF_RELEASE(mDataSource);
   464     NS_IF_RELEASE(mSource);
   465     NS_IF_RELEASE(mProperty);
   466     NS_IF_RELEASE(mTarget);
   467     NS_IF_RELEASE(mValue);
   468 }
   470 NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
   471 NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
   472 NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
   474 NS_IMETHODIMP
   475 InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
   476 {
   477     if (mValue) {
   478         *aResult = true;
   479         return NS_OK;
   480     }
   482     while (mNextAssertion) {
   483         bool foundIt = false;
   484         if ((mProperty == mNextAssertion->u.as.mProperty) &&
   485             (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
   486             if (mSource) {
   487                 mValue = mNextAssertion->u.as.mTarget;
   488                 NS_ADDREF(mValue);
   489             }
   490             else {
   491                 mValue = mNextAssertion->mSource;
   492                 NS_ADDREF(mValue);
   493             }
   494             foundIt = true;
   495         }
   497         // Remember the last assertion we were holding on to
   498         Assertion* as = mNextAssertion;
   500         // iterate
   501         mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
   503         // grab an owning reference from the enumerator to the next assertion
   504         if (mNextAssertion)
   505             mNextAssertion->AddRef();
   507         // ...and release the reference from the enumerator to the old one.
   508         as->Release();
   510         if (foundIt) {
   511             *aResult = true;
   512             return NS_OK;
   513         }
   514     }
   516     *aResult = false;
   517     return NS_OK;
   518 }
   521 NS_IMETHODIMP
   522 InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
   523 {
   524     nsresult rv;
   526     bool hasMore;
   527     rv = HasMoreElements(&hasMore);
   528     if (NS_FAILED(rv)) return rv;
   530     if (! hasMore)
   531         return NS_ERROR_UNEXPECTED;
   533     // Don't AddRef: we "transfer" ownership to the caller
   534     *aResult = mValue;
   535     mValue = nullptr;
   537     return NS_OK;
   538 }
   540 ////////////////////////////////////////////////////////////////////////
   541 //
   543 /**
   544  * This class is a little bit bizarre in that it implements both the
   545  * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
   546  * Because the structure of the in-memory graph is pretty flexible, it's
   547  * fairly easy to parameterize this class. The only funky thing to watch
   548  * out for is the multiple inheritance clashes.
   549  */
   551 class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
   552 {
   553 private:
   554     InMemoryDataSource* mDataSource;
   555     nsIRDFResource*     mSource;
   556     nsIRDFNode*         mTarget;
   557     nsAutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
   558     nsIRDFResource*     mCurrent;
   559     Assertion*          mAssertion;
   560     nsCOMPtr<nsISupportsArray> mHashArcs;
   562     static PLDHashOperator
   563     ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   564                        uint32_t aNumber, void* aArg);
   566 public:
   567     InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
   568                                nsIRDFResource* aSource,
   569                                nsIRDFNode* aTarget);
   571     virtual ~InMemoryArcsEnumeratorImpl();
   573     // nsISupports interface
   574     NS_DECL_ISUPPORTS
   576     // nsISimpleEnumerator interface
   577     NS_DECL_NSISIMPLEENUMERATOR
   578 };
   581 PLDHashOperator
   582 InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable* aTable,
   583                                        PLDHashEntryHdr* aHdr,
   584                                        uint32_t aNumber, void* aArg)
   585 {
   586     Entry* entry = reinterpret_cast<Entry*>(aHdr);
   587     nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg);
   589     resources->AppendElement(entry->mNode);
   590     return PL_DHASH_NEXT;
   591 }
   594 InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
   595                                                        nsIRDFResource* aSource,
   596                                                        nsIRDFNode* aTarget)
   597     : mDataSource(aDataSource),
   598       mSource(aSource),
   599       mTarget(aTarget),
   600       mCurrent(nullptr)
   601 {
   602     NS_ADDREF(mDataSource);
   603     NS_IF_ADDREF(mSource);
   604     NS_IF_ADDREF(mTarget);
   606     if (mSource) {
   607         // cast okay because it's a closed system
   608         mAssertion = mDataSource->GetForwardArcs(mSource);
   610         if (mAssertion && mAssertion->mHashEntry) {
   611             // its our magical HASH_ENTRY forward hash for assertions
   612             nsresult rv = NS_NewISupportsArray(getter_AddRefs(mHashArcs));
   613             if (NS_SUCCEEDED(rv)) {
   614                 PL_DHashTableEnumerate(mAssertion->u.hash.mPropertyHash,
   615                     ArcEnumerator, mHashArcs.get());
   616             }
   617             mAssertion = nullptr;
   618         }
   619     }
   620     else {
   621         mAssertion = mDataSource->GetReverseArcs(mTarget);
   622     }
   623 }
   625 InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
   626 {
   627 #ifdef DEBUG_REFS
   628     --gInstanceCount;
   629     fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
   630 #endif
   632     NS_RELEASE(mDataSource);
   633     NS_IF_RELEASE(mSource);
   634     NS_IF_RELEASE(mTarget);
   635     NS_IF_RELEASE(mCurrent);
   636 }
   638 NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
   639 NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
   640 NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
   642 NS_IMETHODIMP
   643 InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
   644 {
   645     NS_PRECONDITION(aResult != nullptr, "null ptr");
   646     if (! aResult)
   647         return NS_ERROR_NULL_POINTER;
   649     if (mCurrent) {
   650         *aResult = true;
   651         return NS_OK;
   652     }
   654     if (mHashArcs) {
   655         uint32_t    itemCount;
   656         nsresult    rv;
   657         if (NS_FAILED(rv = mHashArcs->Count(&itemCount)))   return(rv);
   658         if (itemCount > 0) {
   659             --itemCount;
   660             nsCOMPtr<nsIRDFResource> tmp = do_QueryElementAt(mHashArcs, itemCount);
   661             tmp.forget(&mCurrent);
   662             mHashArcs->RemoveElementAt(itemCount);
   663             *aResult = true;
   664             return NS_OK;
   665         }
   666     }
   667     else
   668         while (mAssertion) {
   669             nsIRDFResource* next = mAssertion->u.as.mProperty;
   671             // "next" is the property arc we are tentatively going to return
   672             // in a subsequent GetNext() call.  It is important to do two
   673             // things, however, before that can happen:
   674             //   1) Make sure it's not an arc we've already returned.
   675             //   2) Make sure that |mAssertion| is not left pointing to
   676             //      another assertion that has the same property as this one.
   677             // The first is a practical concern; the second a defense against
   678             // an obscure crash and other erratic behavior.  To ensure the
   679             // second condition, skip down the chain until we find the next 
   680             // assertion with a property that doesn't match the current one.
   681             // (All these assertions would be skipped via mAlreadyReturned
   682             // checks anyways; this is even a bit faster.)
   684             do {
   685                 mAssertion = (mSource ? mAssertion->mNext :
   686                         mAssertion->u.as.mInvNext);
   687             }
   688             while (mAssertion && (next == mAssertion->u.as.mProperty));
   690             bool alreadyReturned = false;
   691             for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
   692                 if (mAlreadyReturned[i] == next) {
   693                     alreadyReturned = true;
   694                     break;
   695                 }
   696             }
   698             if (! alreadyReturned) {
   699                 mCurrent = next;
   700                 NS_ADDREF(mCurrent);
   701                 *aResult = true;
   702                 return NS_OK;
   703             }
   704         }
   706     *aResult = false;
   707     return NS_OK;
   708 }
   711 NS_IMETHODIMP
   712 InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
   713 {
   714     nsresult rv;
   716     bool hasMore;
   717     rv = HasMoreElements(&hasMore);
   718     if (NS_FAILED(rv)) return rv;
   720     if (! hasMore)
   721         return NS_ERROR_UNEXPECTED;
   723     // Add this to the set of things we've already returned so that we
   724     // can ensure uniqueness
   725     mAlreadyReturned.AppendElement(mCurrent);
   727     // Don't AddRef: we "transfer" ownership to the caller
   728     *aResult = mCurrent;
   729     mCurrent = nullptr;
   731     return NS_OK;
   732 }
   735 ////////////////////////////////////////////////////////////////////////
   736 // InMemoryDataSource
   738 nsresult
   739 NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
   740 {
   741     NS_PRECONDITION(aResult != nullptr, "null ptr");
   742     if (! aResult)
   743         return NS_ERROR_NULL_POINTER;
   744     *aResult = nullptr;
   746     if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
   747         NS_ERROR("aggregation requires nsISupports");
   748         return NS_ERROR_ILLEGAL_VALUE;
   749     }
   751     InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
   752     if (! datasource)
   753         return NS_ERROR_OUT_OF_MEMORY;
   754     NS_ADDREF(datasource);
   756     nsresult rv = datasource->Init();
   757     if (NS_SUCCEEDED(rv)) {
   758         datasource->fAggregated.AddRef();
   759         rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
   760         datasource->fAggregated.Release();
   761     }
   763     NS_RELEASE(datasource);
   764     return rv;
   765 }
   768 InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
   769     : mNumObservers(0), mReadCount(0)
   770 {
   771     NS_INIT_AGGREGATED(aOuter);
   773     mForwardArcs.ops = nullptr;
   774     mReverseArcs.ops = nullptr;
   775     mPropagateChanges = true;
   776     MOZ_COUNT_CTOR(InMemoryDataSource);
   777 }
   780 nsresult
   781 InMemoryDataSource::Init()
   782 {
   783     PL_DHashTableInit(&mForwardArcs,
   784                       PL_DHashGetStubOps(),
   785                       nullptr,
   786                       sizeof(Entry),
   787                       PL_DHASH_MIN_SIZE);
   789     PL_DHashTableInit(&mReverseArcs,
   790                       PL_DHashGetStubOps(),
   791                       nullptr,
   792                       sizeof(Entry),
   793                       PL_DHASH_MIN_SIZE);
   795 #ifdef PR_LOGGING
   796     if (! gLog)
   797         gLog = PR_NewLogModule("InMemoryDataSource");
   798 #endif
   800     return NS_OK;
   801 }
   804 InMemoryDataSource::~InMemoryDataSource()
   805 {
   806 #ifdef DEBUG_REFS
   807     --gInstanceCount;
   808     fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
   809 #endif
   811     if (mForwardArcs.ops) {
   812         // This'll release all of the Assertion objects that are
   813         // associated with this data source. We only need to do this
   814         // for the forward arcs, because the reverse arcs table
   815         // indexes the exact same set of resources.
   816         PL_DHashTableEnumerate(&mForwardArcs, DeleteForwardArcsEntry, nullptr);
   817         PL_DHashTableFinish(&mForwardArcs);
   818     }
   819     if (mReverseArcs.ops)
   820         PL_DHashTableFinish(&mReverseArcs);
   822     PR_LOG(gLog, PR_LOG_NOTICE,
   823            ("InMemoryDataSource(%p): destroyed.", this));
   825     MOZ_COUNT_DTOR(InMemoryDataSource);
   826 }
   828 PLDHashOperator
   829 InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   830                                            uint32_t aNumber, void* aArg)
   831 {
   832     Entry* entry = reinterpret_cast<Entry*>(aHdr);
   834     Assertion* as = entry->mAssertions;
   835     while (as) {
   836         Assertion* doomed = as;
   837         as = as->mNext;
   839         // Unlink, and release the datasource's reference.
   840         doomed->mNext = doomed->u.as.mInvNext = nullptr;
   841         doomed->Release();
   842     }
   843     return PL_DHASH_NEXT;
   844 }
   847 ////////////////////////////////////////////////////////////////////////
   849 NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
   851 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
   852     NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
   853 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   854 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
   855     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
   856 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   858 NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
   859 NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
   860     NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
   861     NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
   862     NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
   863     NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
   864     NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
   865     NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
   866 NS_INTERFACE_MAP_END
   868 ////////////////////////////////////////////////////////////////////////
   871 #ifdef PR_LOGGING
   872 void
   873 InMemoryDataSource::LogOperation(const char* aOperation,
   874                                  nsIRDFResource* aSource,
   875                                  nsIRDFResource* aProperty,
   876                                  nsIRDFNode* aTarget,
   877                                  bool aTruthValue)
   878 {
   879     if (! PR_LOG_TEST(gLog, PR_LOG_NOTICE))
   880         return;
   882     nsXPIDLCString uri;
   883     aSource->GetValue(getter_Copies(uri));
   884     PR_LogPrint
   885            ("InMemoryDataSource(%p): %s", this, aOperation);
   887     PR_LogPrint
   888            ("  [(%p)%s]--", aSource, (const char*) uri);
   890     aProperty->GetValue(getter_Copies(uri));
   892     char tv = (aTruthValue ? '-' : '!');
   893     PR_LogPrint
   894            ("  --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
   896     nsCOMPtr<nsIRDFResource> resource;
   897     nsCOMPtr<nsIRDFLiteral> literal;
   899     if ((resource = do_QueryInterface(aTarget)) != nullptr) {
   900         resource->GetValue(getter_Copies(uri));
   901         PR_LogPrint
   902            ("  -->[(%p)%s]", aTarget, (const char*) uri);
   903     }
   904     else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
   905         nsXPIDLString value;
   906         literal->GetValue(getter_Copies(value));
   907         nsAutoString valueStr(value);
   908         char* valueCStr = ToNewCString(valueStr);
   910         PR_LogPrint
   911            ("  -->(\"%s\")\n", valueCStr);
   913         NS_Free(valueCStr);
   914     }
   915     else {
   916         PR_LogPrint
   917            ("  -->(unknown-type)\n");
   918     }
   919 }
   920 #endif
   923 NS_IMETHODIMP
   924 InMemoryDataSource::GetURI(char* *uri)
   925 {
   926     NS_PRECONDITION(uri != nullptr, "null ptr");
   927     if (! uri)
   928         return NS_ERROR_NULL_POINTER;
   930     *uri = nullptr;
   931     return NS_OK;
   932 }
   934 NS_IMETHODIMP
   935 InMemoryDataSource::GetSource(nsIRDFResource* property,
   936                               nsIRDFNode* target,
   937                               bool tv,
   938                               nsIRDFResource** source)
   939 {
   940     NS_PRECONDITION(source != nullptr, "null ptr");
   941     if (! source)
   942         return NS_ERROR_NULL_POINTER;
   944     NS_PRECONDITION(property != nullptr, "null ptr");
   945     if (! property)
   946         return NS_ERROR_NULL_POINTER;
   948     NS_PRECONDITION(target != nullptr, "null ptr");
   949     if (! target)
   950         return NS_ERROR_NULL_POINTER;
   952     for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
   953         if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
   954             *source = as->mSource;
   955             NS_ADDREF(*source);
   956             return NS_OK;
   957         }
   958     }
   959     *source = nullptr;
   960     return NS_RDF_NO_VALUE;
   961 }
   963 NS_IMETHODIMP
   964 InMemoryDataSource::GetTarget(nsIRDFResource* source,
   965                               nsIRDFResource* property,
   966                               bool tv,
   967                               nsIRDFNode** target)
   968 {
   969     NS_PRECONDITION(source != nullptr, "null ptr");
   970     if (! source)
   971         return NS_ERROR_NULL_POINTER;
   973     NS_PRECONDITION(property != nullptr, "null ptr");
   974     if (! property)
   975         return NS_ERROR_NULL_POINTER;
   977     NS_PRECONDITION(target != nullptr, "null ptr");
   978     if (! target)
   979         return NS_ERROR_NULL_POINTER;
   981     Assertion *as = GetForwardArcs(source);
   982     if (as && as->mHashEntry) {
   983         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
   984         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
   985             ? reinterpret_cast<Entry*>(hdr)->mAssertions
   986             : nullptr;
   987         while (val) {
   988             if (tv == val->u.as.mTruthValue) {
   989                 *target = val->u.as.mTarget;
   990                 NS_IF_ADDREF(*target);
   991                 return NS_OK;
   992             }
   993             val = val->mNext;
   994         }
   995     }
   996     else
   997     for (; as != nullptr; as = as->mNext) {
   998         if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
   999             *target = as->u.as.mTarget;
  1000             NS_ADDREF(*target);
  1001             return NS_OK;
  1005     // If we get here, then there was no target with for the specified
  1006     // property & truth value.
  1007     *target = nullptr;
  1008     return NS_RDF_NO_VALUE;
  1011 NS_IMETHODIMP
  1012 InMemoryDataSource::HasAssertion(nsIRDFResource* source,
  1013                                  nsIRDFResource* property,
  1014                                  nsIRDFNode* target,
  1015                                  bool tv,
  1016                                  bool* hasAssertion)
  1018     if (! source)
  1019         return NS_ERROR_NULL_POINTER;
  1021     if (! property)
  1022         return NS_ERROR_NULL_POINTER;
  1024     if (! target)
  1025         return NS_ERROR_NULL_POINTER;
  1027     Assertion *as = GetForwardArcs(source);
  1028     if (as && as->mHashEntry) {
  1029         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
  1030         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1031             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1032             : nullptr;
  1033         while (val) {
  1034             if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
  1035                 *hasAssertion = true;
  1036                 return NS_OK;
  1038             val = val->mNext;
  1041     else
  1042     for (; as != nullptr; as = as->mNext) {
  1043         // check target first as its most unique
  1044         if (target != as->u.as.mTarget)
  1045             continue;
  1047         if (property != as->u.as.mProperty)
  1048             continue;
  1050         if (tv != (as->u.as.mTruthValue))
  1051             continue;
  1053         // found it!
  1054         *hasAssertion = true;
  1055         return NS_OK;
  1058     // If we get here, we couldn't find the assertion
  1059     *hasAssertion = false;
  1060     return NS_OK;
  1063 NS_IMETHODIMP
  1064 InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
  1065                                nsIRDFNode* aTarget,
  1066                                bool aTruthValue,
  1067                                nsISimpleEnumerator** aResult)
  1069     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1070     if (! aProperty)
  1071         return NS_ERROR_NULL_POINTER;
  1073     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1074     if (! aTarget)
  1075         return NS_ERROR_NULL_POINTER;
  1077     NS_PRECONDITION(aResult != nullptr, "null ptr");
  1078     if (! aResult)
  1079         return NS_ERROR_NULL_POINTER;
  1081     InMemoryAssertionEnumeratorImpl* result =
  1082         new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
  1083                                             aTarget, aTruthValue);
  1085     if (! result)
  1086         return NS_ERROR_OUT_OF_MEMORY;
  1088     NS_ADDREF(result);
  1089     *aResult = result;
  1091     return NS_OK;
  1094 NS_IMETHODIMP
  1095 InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
  1096                                nsIRDFResource* aProperty,
  1097                                bool aTruthValue,
  1098                                nsISimpleEnumerator** aResult)
  1100     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1101     if (! aSource)
  1102         return NS_ERROR_NULL_POINTER;
  1104     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1105     if (! aProperty)
  1106         return NS_ERROR_NULL_POINTER;
  1108     NS_PRECONDITION(aResult != nullptr, "null ptr");
  1109     if (! aResult)
  1110         return NS_ERROR_NULL_POINTER;
  1112     InMemoryAssertionEnumeratorImpl* result =
  1113         new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
  1114                                             nullptr, aTruthValue);
  1116     if (! result)
  1117         return NS_ERROR_OUT_OF_MEMORY;
  1119     NS_ADDREF(result);
  1120     *aResult = result;
  1122     return NS_OK;
  1126 nsresult
  1127 InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
  1128                                  nsIRDFResource* aProperty,
  1129                                  nsIRDFNode* aTarget,
  1130                                  bool aTruthValue)
  1132 #ifdef PR_LOGGING
  1133     LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
  1134 #endif
  1136     Assertion* next = GetForwardArcs(aSource);
  1137     Assertion* prev = next;
  1138     Assertion* as = nullptr;
  1140     bool    haveHash = (next) ? next->mHashEntry : false;
  1141     if (haveHash) {
  1142         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, aProperty, PL_DHASH_LOOKUP);
  1143         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1144             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1145             : nullptr;
  1146         while (val) {
  1147             if (val->u.as.mTarget == aTarget) {
  1148                 // Wow, we already had the assertion. Make sure that the
  1149                 // truth values are correct and bail.
  1150                 val->u.as.mTruthValue = aTruthValue;
  1151                 return NS_OK;
  1153             val = val->mNext;
  1156     else
  1158         while (next) {
  1159             // check target first as its most unique
  1160             if (aTarget == next->u.as.mTarget) {
  1161                 if (aProperty == next->u.as.mProperty) {
  1162                     // Wow, we already had the assertion. Make sure that the
  1163                     // truth values are correct and bail.
  1164                     next->u.as.mTruthValue = aTruthValue;
  1165                     return NS_OK;
  1169             prev = next;
  1170             next = next->mNext;
  1174     as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
  1175     if (! as)
  1176         return NS_ERROR_OUT_OF_MEMORY;
  1178     // Add the datasource's owning reference.
  1179     as->AddRef();
  1181     if (haveHash)
  1183         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1184             aProperty, PL_DHASH_LOOKUP);
  1185         Assertion *asRef = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1186             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1187             : nullptr;
  1188         if (asRef)
  1190             as->mNext = asRef->mNext;
  1191             asRef->mNext = as;
  1193         else
  1195             hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1196                                             aProperty, PL_DHASH_ADD);
  1197             if (hdr)
  1199                 Entry* entry = reinterpret_cast<Entry*>(hdr);
  1200                 entry->mNode = aProperty;
  1201                 entry->mAssertions = as;
  1205     else
  1207         // Link it in to the "forward arcs" table
  1208         if (!prev) {
  1209             SetForwardArcs(aSource, as);
  1210         } else {
  1211             prev->mNext = as;
  1215     // Link it in to the "reverse arcs" table
  1217     next = GetReverseArcs(aTarget);
  1218     as->u.as.mInvNext = next;
  1219     next = as;
  1220     SetReverseArcs(aTarget, next);
  1222     return NS_OK;
  1225 NS_IMETHODIMP
  1226 InMemoryDataSource::Assert(nsIRDFResource* aSource,
  1227                            nsIRDFResource* aProperty, 
  1228                            nsIRDFNode* aTarget,
  1229                            bool aTruthValue) 
  1231     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1232     if (! aSource)
  1233         return NS_ERROR_NULL_POINTER;
  1235     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1236     if (! aProperty)
  1237         return NS_ERROR_NULL_POINTER;
  1239     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1240     if (! aTarget)
  1241         return NS_ERROR_NULL_POINTER;
  1243     if (mReadCount) {
  1244         NS_WARNING("Writing to InMemoryDataSource during read\n");
  1245         return NS_RDF_ASSERTION_REJECTED;
  1248     nsresult rv;
  1249     rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
  1250     if (NS_FAILED(rv)) return rv;
  1252     // notify observers
  1253     for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
  1254         nsIRDFObserver* obs = mObservers[i];
  1256         // XXX this should never happen, but it does, and we can't figure out why.
  1257         NS_ASSERTION(obs, "observer array corrupted!");
  1258         if (! obs)
  1259           continue;
  1261         obs->OnAssert(this, aSource, aProperty, aTarget);
  1262         // XXX ignore return value?
  1265     return NS_RDF_ASSERTION_ACCEPTED;
  1269 nsresult
  1270 InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
  1271                                    nsIRDFResource* aProperty,
  1272                                    nsIRDFNode* aTarget)
  1274 #ifdef PR_LOGGING
  1275     LogOperation("UNASSERT", aSource, aProperty, aTarget);
  1276 #endif
  1278     Assertion* next = GetForwardArcs(aSource);
  1279     Assertion* prev = next;
  1280     Assertion* root = next;
  1281     Assertion* as = nullptr;
  1283     bool    haveHash = (next) ? next->mHashEntry : false;
  1284     if (haveHash) {
  1285         PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1286             aProperty, PL_DHASH_LOOKUP);
  1287         prev = next = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1288             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1289             : nullptr;
  1290         bool first = true;
  1291         while (next) {
  1292             if (aTarget == next->u.as.mTarget) {
  1293                 break;
  1295             first = false;
  1296             prev = next;
  1297             next = next->mNext;
  1299         // We don't even have the assertion, so just bail.
  1300         if (!next)
  1301             return NS_OK;
  1303         as = next;
  1305         if (first) {
  1306             PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
  1308             if (next && next->mNext) {
  1309                 PLDHashEntryHdr* hdr = PL_DHashTableOperate(root->u.hash.mPropertyHash,
  1310                                      aProperty, PL_DHASH_ADD);
  1311                 if (hdr) {
  1312                     Entry* entry = reinterpret_cast<Entry*>(hdr);
  1313                     entry->mNode = aProperty;
  1314                     entry->mAssertions = next->mNext;
  1317             else {
  1318                 // If this second-level hash empties out, clean it up.
  1319                 if (!root->u.hash.mPropertyHash->entryCount) {
  1320                     delete root;
  1321                     SetForwardArcs(aSource, nullptr);
  1325         else {
  1326             prev->mNext = next->mNext;
  1329     else
  1331         while (next) {
  1332             // check target first as its most unique
  1333             if (aTarget == next->u.as.mTarget) {
  1334                 if (aProperty == next->u.as.mProperty) {
  1335                     if (prev == next) {
  1336                         SetForwardArcs(aSource, next->mNext);
  1337                     } else {
  1338                         prev->mNext = next->mNext;
  1340                     as = next;
  1341                     break;
  1345             prev = next;
  1346             next = next->mNext;
  1349     // We don't even have the assertion, so just bail.
  1350     if (!as)
  1351         return NS_OK;
  1353 #ifdef DEBUG
  1354     bool foundReverseArc = false;
  1355 #endif
  1357     next = prev = GetReverseArcs(aTarget);
  1358     while (next) {
  1359         if (next == as) {
  1360             if (prev == next) {
  1361                 SetReverseArcs(aTarget, next->u.as.mInvNext);
  1362             } else {
  1363                 prev->u.as.mInvNext = next->u.as.mInvNext;
  1365 #ifdef DEBUG
  1366             foundReverseArc = true;
  1367 #endif
  1368             break;
  1370         prev = next;
  1371         next = next->u.as.mInvNext;
  1374 #ifdef DEBUG
  1375     NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
  1376 #endif
  1378     // Unlink, and release the datasource's reference
  1379     as->mNext = as->u.as.mInvNext = nullptr;
  1380     as->Release();
  1382     return NS_OK;
  1385 NS_IMETHODIMP
  1386 InMemoryDataSource::Unassert(nsIRDFResource* aSource,
  1387                              nsIRDFResource* aProperty,
  1388                              nsIRDFNode* aTarget)
  1390     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1391     if (! aSource)
  1392         return NS_ERROR_NULL_POINTER;
  1394     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1395     if (! aProperty)
  1396         return NS_ERROR_NULL_POINTER;
  1398     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1399     if (! aTarget)
  1400         return NS_ERROR_NULL_POINTER;
  1402     if (mReadCount) {
  1403         NS_WARNING("Writing to InMemoryDataSource during read\n");
  1404         return NS_RDF_ASSERTION_REJECTED;
  1407     nsresult rv;
  1409     rv = LockedUnassert(aSource, aProperty, aTarget);
  1410     if (NS_FAILED(rv)) return rv;
  1412     // Notify the world
  1413     for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1414         nsIRDFObserver* obs = mObservers[i];
  1416         // XXX this should never happen, but it does, and we can't figure out why.
  1417         NS_ASSERTION(obs, "observer array corrupted!");
  1418         if (! obs)
  1419           continue;
  1421         obs->OnUnassert(this, aSource, aProperty, aTarget);
  1422         // XXX ignore return value?
  1425     return NS_RDF_ASSERTION_ACCEPTED;
  1429 NS_IMETHODIMP
  1430 InMemoryDataSource::Change(nsIRDFResource* aSource,
  1431                            nsIRDFResource* aProperty,
  1432                            nsIRDFNode* aOldTarget,
  1433                            nsIRDFNode* aNewTarget)
  1435     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1436     if (! aSource)
  1437         return NS_ERROR_NULL_POINTER;
  1439     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1440     if (! aProperty)
  1441         return NS_ERROR_NULL_POINTER;
  1443     NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
  1444     if (! aOldTarget)
  1445         return NS_ERROR_NULL_POINTER;
  1447     NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
  1448     if (! aNewTarget)
  1449         return NS_ERROR_NULL_POINTER;
  1451     if (mReadCount) {
  1452         NS_WARNING("Writing to InMemoryDataSource during read\n");
  1453         return NS_RDF_ASSERTION_REJECTED;
  1456     nsresult rv;
  1458     // XXX We can implement LockedChange() if we decide that this
  1459     // is a performance bottleneck.
  1461     rv = LockedUnassert(aSource, aProperty, aOldTarget);
  1462     if (NS_FAILED(rv)) return rv;
  1464     rv = LockedAssert(aSource, aProperty, aNewTarget, true);
  1465     if (NS_FAILED(rv)) return rv;
  1467     // Notify the world
  1468     for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1469         nsIRDFObserver* obs = mObservers[i];
  1471         // XXX this should never happen, but it does, and we can't figure out why.
  1472         NS_ASSERTION(obs, "observer array corrupted!");
  1473         if (! obs)
  1474           continue;
  1476         obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
  1477         // XXX ignore return value?
  1480     return NS_RDF_ASSERTION_ACCEPTED;
  1484 NS_IMETHODIMP
  1485 InMemoryDataSource::Move(nsIRDFResource* aOldSource,
  1486                          nsIRDFResource* aNewSource,
  1487                          nsIRDFResource* aProperty,
  1488                          nsIRDFNode* aTarget)
  1490     NS_PRECONDITION(aOldSource != nullptr, "null ptr");
  1491     if (! aOldSource)
  1492         return NS_ERROR_NULL_POINTER;
  1494     NS_PRECONDITION(aNewSource != nullptr, "null ptr");
  1495     if (! aNewSource)
  1496         return NS_ERROR_NULL_POINTER;
  1498     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1499     if (! aProperty)
  1500         return NS_ERROR_NULL_POINTER;
  1502     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1503     if (! aTarget)
  1504         return NS_ERROR_NULL_POINTER;
  1506     if (mReadCount) {
  1507         NS_WARNING("Writing to InMemoryDataSource during read\n");
  1508         return NS_RDF_ASSERTION_REJECTED;
  1511     nsresult rv;
  1513     // XXX We can implement LockedMove() if we decide that this
  1514     // is a performance bottleneck.
  1516     rv = LockedUnassert(aOldSource, aProperty, aTarget);
  1517     if (NS_FAILED(rv)) return rv;
  1519     rv = LockedAssert(aNewSource, aProperty, aTarget, true);
  1520     if (NS_FAILED(rv)) return rv;
  1522     // Notify the world
  1523     for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1524         nsIRDFObserver* obs = mObservers[i];
  1526         // XXX this should never happen, but it does, and we can't figure out why.
  1527         NS_ASSERTION(obs, "observer array corrupted!");
  1528         if (! obs)
  1529           continue;
  1531         obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
  1532         // XXX ignore return value?
  1535     return NS_RDF_ASSERTION_ACCEPTED;
  1539 NS_IMETHODIMP
  1540 InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
  1542     NS_PRECONDITION(aObserver != nullptr, "null ptr");
  1543     if (! aObserver)
  1544         return NS_ERROR_NULL_POINTER;
  1546     mObservers.AppendObject(aObserver);
  1547     mNumObservers = mObservers.Count();
  1549     return NS_OK;
  1552 NS_IMETHODIMP
  1553 InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
  1555     NS_PRECONDITION(aObserver != nullptr, "null ptr");
  1556     if (! aObserver)
  1557         return NS_ERROR_NULL_POINTER;
  1559     mObservers.RemoveObject(aObserver);
  1560     // note: use Count() instead of just decrementing
  1561     // in case aObserver wasn't in list, for example
  1562     mNumObservers = mObservers.Count();
  1564     return NS_OK;
  1567 NS_IMETHODIMP 
  1568 InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
  1570     Assertion* ass = GetReverseArcs(aNode);
  1571     while (ass) {
  1572         nsIRDFResource* elbow = ass->u.as.mProperty;
  1573         if (elbow == aArc) {
  1574             *result = true;
  1575             return NS_OK;
  1577         ass = ass->u.as.mInvNext;
  1579     *result = false;
  1580     return NS_OK;
  1583 NS_IMETHODIMP 
  1584 InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
  1586     Assertion* ass = GetForwardArcs(aSource);
  1587     if (ass && ass->mHashEntry) {
  1588         PLDHashEntryHdr* hdr = PL_DHashTableOperate(ass->u.hash.mPropertyHash,
  1589             aArc, PL_DHASH_LOOKUP);
  1590         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1591             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1592             : nullptr;
  1593         if (val) {
  1594             *result = true;
  1595             return NS_OK;
  1597         ass = ass->mNext;
  1599     while (ass) {
  1600         nsIRDFResource* elbow = ass->u.as.mProperty;
  1601         if (elbow == aArc) {
  1602             *result = true;
  1603             return NS_OK;
  1605         ass = ass->mNext;
  1607     *result = false;
  1608     return NS_OK;
  1611 NS_IMETHODIMP
  1612 InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
  1614     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1615     if (! aTarget)
  1616         return NS_ERROR_NULL_POINTER;
  1618     InMemoryArcsEnumeratorImpl* result =
  1619         new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
  1621     if (! result)
  1622         return NS_ERROR_OUT_OF_MEMORY;
  1624     NS_ADDREF(result);
  1625     *aResult = result;
  1627     return NS_OK;
  1630 NS_IMETHODIMP
  1631 InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
  1633     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1634     if (! aSource)
  1635         return NS_ERROR_NULL_POINTER;
  1637     InMemoryArcsEnumeratorImpl* result =
  1638         new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
  1640     if (! result)
  1641         return NS_ERROR_OUT_OF_MEMORY;
  1643     NS_ADDREF(result);
  1644     *aResult = result;
  1646     return NS_OK;
  1649 PLDHashOperator
  1650 InMemoryDataSource::ResourceEnumerator(PLDHashTable* aTable,
  1651                                        PLDHashEntryHdr* aHdr,
  1652                                        uint32_t aNumber, void* aArg)
  1654     Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1655     static_cast<nsCOMArray<nsIRDFNode>*>(aArg)->AppendObject(entry->mNode);
  1656     return PL_DHASH_NEXT;
  1660 NS_IMETHODIMP
  1661 InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
  1663     nsCOMArray<nsIRDFNode> nodes;
  1664     nodes.SetCapacity(mForwardArcs.entryCount);
  1666     // Enumerate all of our entries into an nsCOMArray
  1667     PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes);
  1669     return NS_NewArrayEnumerator(aResult, nodes);
  1672 NS_IMETHODIMP
  1673 InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
  1674                                nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
  1676     return(NS_NewEmptyEnumerator(commands));
  1679 NS_IMETHODIMP
  1680 InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1681                                      nsIRDFResource*   aCommand,
  1682                                      nsISupportsArray/*<nsIRDFResource>*/* aArguments,
  1683                                      bool* aResult)
  1685     *aResult = false;
  1686     return NS_OK;
  1689 NS_IMETHODIMP
  1690 InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1691                               nsIRDFResource*   aCommand,
  1692                               nsISupportsArray/*<nsIRDFResource>*/* aArguments)
  1694     return NS_OK;
  1697 NS_IMETHODIMP
  1698 InMemoryDataSource::BeginUpdateBatch()
  1700     for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1701         nsIRDFObserver* obs = mObservers[i];
  1702         obs->OnBeginUpdateBatch(this);
  1704     return NS_OK;
  1707 NS_IMETHODIMP
  1708 InMemoryDataSource::EndUpdateBatch()
  1710     for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1711         nsIRDFObserver* obs = mObservers[i];
  1712         obs->OnEndUpdateBatch(this);
  1714     return NS_OK;
  1719 ////////////////////////////////////////////////////////////////////////
  1720 // nsIRDFInMemoryDataSource methods
  1722 NS_IMETHODIMP
  1723 InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
  1725     Assertion *as = GetForwardArcs(aSource);
  1726     bool    haveHash = (as) ? as->mHashEntry : false;
  1728     // if its already a hash, then nothing to do
  1729     if (haveHash)   return(NS_OK);
  1731     // convert aSource in forward hash into a hash
  1732     Assertion *hashAssertion = new Assertion(aSource);
  1733     NS_ASSERTION(hashAssertion, "unable to create Assertion");
  1734     if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
  1736     // Add the datasource's owning reference.
  1737     hashAssertion->AddRef();
  1739     Assertion *first = GetForwardArcs(aSource);
  1740     SetForwardArcs(aSource, hashAssertion);
  1742     // mutate references of existing forward assertions into this hash
  1743     PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
  1744     Assertion *nextRef;
  1745     while(first) {
  1746         nextRef = first->mNext;
  1747         nsIRDFResource *prop = first->u.as.mProperty;
  1749         PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
  1750             prop, PL_DHASH_LOOKUP);
  1751         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1752             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1753             : nullptr;
  1754         if (val) {
  1755             first->mNext = val->mNext;
  1756             val->mNext = first;
  1758         else {
  1759             PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
  1760                                             prop, PL_DHASH_ADD);
  1761             if (hdr) {
  1762                 Entry* entry = reinterpret_cast<Entry*>(hdr);
  1763                 entry->mNode = prop;
  1764                 entry->mAssertions = first;
  1765                 first->mNext = nullptr;
  1768         first = nextRef;
  1770     return(NS_OK);
  1774 ////////////////////////////////////////////////////////////////////////
  1775 // nsIRDFPropagatableDataSource methods
  1776 NS_IMETHODIMP
  1777 InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
  1779     *aPropagateChanges = mPropagateChanges;
  1780     return NS_OK;
  1783 NS_IMETHODIMP
  1784 InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
  1786     mPropagateChanges = aPropagateChanges;
  1787     return NS_OK;
  1791 ////////////////////////////////////////////////////////////////////////
  1792 // nsIRDFPurgeableDataSource methods
  1794 NS_IMETHODIMP
  1795 InMemoryDataSource::Mark(nsIRDFResource* aSource,
  1796                          nsIRDFResource* aProperty,
  1797                          nsIRDFNode* aTarget,
  1798                          bool aTruthValue,
  1799                          bool* aDidMark)
  1801     NS_PRECONDITION(aSource != nullptr, "null ptr");
  1802     if (! aSource)
  1803         return NS_ERROR_NULL_POINTER;
  1805     NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1806     if (! aProperty)
  1807         return NS_ERROR_NULL_POINTER;
  1809     NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1810     if (! aTarget)
  1811         return NS_ERROR_NULL_POINTER;
  1813     Assertion *as = GetForwardArcs(aSource);
  1814     if (as && as->mHashEntry) {
  1815         PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash,
  1816             aProperty, PL_DHASH_LOOKUP);
  1817         Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1818             ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1819             : nullptr;
  1820         while (val) {
  1821             if ((val->u.as.mTarget == aTarget) &&
  1822                 (aTruthValue == (val->u.as.mTruthValue))) {
  1824                 // found it! so mark it.
  1825                 as->Mark();
  1826                 *aDidMark = true;
  1828 #ifdef PR_LOGGING
  1829                 LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
  1830 #endif
  1832                 return NS_OK;
  1834             val = val->mNext;
  1837     else for (; as != nullptr; as = as->mNext) {
  1838         // check target first as its most unique
  1839         if (aTarget != as->u.as.mTarget)
  1840             continue;
  1842         if (aProperty != as->u.as.mProperty)
  1843             continue;
  1845         if (aTruthValue != (as->u.as.mTruthValue))
  1846             continue;
  1848         // found it! so mark it.
  1849         as->Mark();
  1850         *aDidMark = true;
  1852 #ifdef PR_LOGGING
  1853         LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
  1854 #endif
  1856         return NS_OK;
  1859     // If we get here, we couldn't find the assertion
  1860     *aDidMark = false;
  1861     return NS_OK;
  1865 struct SweepInfo {
  1866     Assertion* mUnassertList;
  1867     PLDHashTable* mReverseArcs;
  1868 };
  1870 NS_IMETHODIMP
  1871 InMemoryDataSource::Sweep()
  1873     SweepInfo info = { nullptr, &mReverseArcs };
  1875     // Remove all the assertions, but don't notify anyone.
  1876     PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info);
  1878     // Now do the notification.
  1879     Assertion* as = info.mUnassertList;
  1880     while (as) {
  1881 #ifdef PR_LOGGING
  1882         LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
  1883 #endif
  1884         if (!(as->mHashEntry))
  1886             for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1887                 nsIRDFObserver* obs = mObservers[i];
  1888                 // XXXbz other loops over mObservers null-check |obs| here!
  1889                 obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
  1890                 // XXX ignore return value?
  1894         Assertion* doomed = as;
  1895         as = as->mNext;
  1897         // Unlink, and release the datasource's reference
  1898         doomed->mNext = doomed->u.as.mInvNext = nullptr;
  1899         doomed->Release();
  1902     return NS_OK;
  1906 PLDHashOperator
  1907 InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
  1908                                             PLDHashEntryHdr* aHdr,
  1909                                             uint32_t aNumber, void* aArg)
  1911     PLDHashOperator result = PL_DHASH_NEXT;
  1912     Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1913     SweepInfo* info = static_cast<SweepInfo*>(aArg);
  1915     Assertion* as = entry->mAssertions;
  1916     if (as && (as->mHashEntry))
  1918         // Stuff in sub-hashes must be swept recursively (max depth: 1)
  1919         PL_DHashTableEnumerate(as->u.hash.mPropertyHash,
  1920                                SweepForwardArcsEntries, info);
  1922         // If the sub-hash is now empty, clean it up.
  1923         if (!as->u.hash.mPropertyHash->entryCount) {
  1924             delete as;
  1925             result = PL_DHASH_REMOVE;
  1928         return result;
  1931     Assertion* prev = nullptr;
  1932     while (as) {
  1933         if (as->IsMarked()) {
  1934             prev = as;
  1935             as->Unmark();
  1936             as = as->mNext;
  1938         else {
  1939             // remove from the list of assertions in the datasource
  1940             Assertion* next = as->mNext;
  1941             if (prev) {
  1942                 prev->mNext = next;
  1944             else {
  1945                 // it's the first one. update the hashtable entry.
  1946                 entry->mAssertions = next;
  1949             // remove from the reverse arcs
  1950             PLDHashEntryHdr* hdr =
  1951                 PL_DHashTableOperate(info->mReverseArcs, as->u.as.mTarget, PL_DHASH_LOOKUP);
  1952             NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "no assertion in reverse arcs");
  1954             Entry* rentry = reinterpret_cast<Entry*>(hdr);
  1955             Assertion* ras = rentry->mAssertions;
  1956             Assertion* rprev = nullptr;
  1957             while (ras) {
  1958                 if (ras == as) {
  1959                     if (rprev) {
  1960                         rprev->u.as.mInvNext = ras->u.as.mInvNext;
  1962                     else {
  1963                         // it's the first one. update the hashtable entry.
  1964                         rentry->mAssertions = ras->u.as.mInvNext;
  1966                     as->u.as.mInvNext = nullptr; // for my sanity.
  1967                     break;
  1969                 rprev = ras;
  1970                 ras = ras->u.as.mInvNext;
  1973             // Wow, it was the _only_ one. Unhash it.
  1974             if (! rentry->mAssertions)
  1976                 PL_DHashTableRawRemove(info->mReverseArcs, hdr);
  1979             // add to the list of assertions to unassert
  1980             as->mNext = info->mUnassertList;
  1981             info->mUnassertList = as;
  1983             // Advance to the next assertion
  1984             as = next;
  1988     // if no more assertions exist for this resource, then unhash it.
  1989     if (! entry->mAssertions)
  1990         result = PL_DHASH_REMOVE;
  1992     return result;
  1995 ////////////////////////////////////////////////////////////////////////
  1996 // rdfIDataSource methods
  1998 class VisitorClosure
  2000 public:
  2001     VisitorClosure(rdfITripleVisitor* aVisitor) :
  2002         mVisitor(aVisitor),
  2003         mRv(NS_OK)
  2004     {}
  2005     rdfITripleVisitor* mVisitor;
  2006     nsresult mRv;
  2007 };
  2009 PLDHashOperator
  2010 SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  2011                   uint32_t aNumber, void* aArg) {
  2012     Entry* entry = reinterpret_cast<Entry*>(aHdr);
  2013     VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
  2015     nsresult rv;
  2016     nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
  2017     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
  2019     closure->mRv = closure->mVisitor->Visit(subject, nullptr, nullptr, true);
  2020     if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT)
  2021         return PL_DHASH_STOP;
  2023     return PL_DHASH_NEXT;
  2026 NS_IMETHODIMP
  2027 InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
  2029     // Lock datasource against writes
  2030     ++mReadCount;
  2032     // Enumerate all of our entries into an nsISupportsArray.
  2033     VisitorClosure cls(aVisitor);
  2034     PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls);
  2036     // Unlock datasource
  2037     --mReadCount;
  2039     return cls.mRv;
  2042 class TriplesInnerClosure
  2044 public:
  2045     TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) :
  2046         mSubject(aSubject), mOuter(aClosure) {}
  2047     nsIRDFNode* mSubject;
  2048     VisitorClosure* mOuter;
  2049 };
  2051 PLDHashOperator
  2052 TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  2053                   uint32_t aNumber, void* aArg) {
  2054     Entry* entry = reinterpret_cast<Entry*>(aHdr);
  2055     Assertion* assertion = entry->mAssertions;
  2056     TriplesInnerClosure* closure = 
  2057         static_cast<TriplesInnerClosure*>(aArg);
  2058     while (assertion) {
  2059         NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
  2060         VisitorClosure* cls = closure->mOuter;
  2061         cls->mRv = cls->mVisitor->Visit(closure->mSubject,
  2062                                         assertion->u.as.mProperty,
  2063                                         assertion->u.as.mTarget,
  2064                                         assertion->u.as.mTruthValue);
  2065         if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) {
  2066             return PL_DHASH_STOP;
  2068         assertion = assertion->mNext;
  2070     return PL_DHASH_NEXT;
  2072 PLDHashOperator
  2073 TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  2074                   uint32_t aNumber, void* aArg) {
  2075     Entry* entry = reinterpret_cast<Entry*>(aHdr);
  2076     VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
  2078     nsresult rv;
  2079     nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
  2080     NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
  2082     if (entry->mAssertions->mHashEntry) {
  2083         TriplesInnerClosure cls(subject, closure);
  2084         PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash,
  2085                                TriplesInnerEnumerator, &cls);
  2086         if (NS_FAILED(closure->mRv)) {
  2087             return PL_DHASH_STOP;
  2089         return PL_DHASH_NEXT;
  2091     Assertion* assertion = entry->mAssertions;
  2092     while (assertion) {
  2093         NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
  2094         closure->mRv = closure->mVisitor->Visit(subject,
  2095                                                 assertion->u.as.mProperty,
  2096                                                 assertion->u.as.mTarget,
  2097                                                 assertion->u.as.mTruthValue);
  2098         if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) {
  2099             return PL_DHASH_STOP;
  2101         assertion = assertion->mNext;
  2103     return PL_DHASH_NEXT;
  2105 NS_IMETHODIMP
  2106 InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
  2108     // Lock datasource against writes
  2109     ++mReadCount;
  2111     // Enumerate all of our entries into an nsISupportsArray.
  2112     VisitorClosure cls(aVisitor);
  2113     PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls);
  2115     // Unlock datasource
  2116     --mReadCount;
  2118     return cls.mRv;
  2121 ////////////////////////////////////////////////////////////////////////

mercurial