rdf/base/src/nsInMemoryDataSource.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rdf/base/src/nsInMemoryDataSource.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,2122 @@
     1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + *
     1.6 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/.
     1.9 + *
    1.10 + *
    1.11 + * This Original Code has been modified by IBM Corporation.
    1.12 + * Modifications made by IBM described herein are
    1.13 + * Copyright (c) International Business Machines
    1.14 + * Corporation, 2000
    1.15 + *
    1.16 + * Modifications to Mozilla code or documentation
    1.17 + * identified per MPL Section 3.3
    1.18 + *
    1.19 + * Date         Modified by     Description of modification
    1.20 + * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
    1.21 + *                               use in OS2
    1.22 + */
    1.23 +
    1.24 +/*
    1.25 +
    1.26 +  Implementation for an in-memory RDF data store.
    1.27 +
    1.28 +  TO DO
    1.29 +
    1.30 +  1) Instrument this code to gather space and time performance
    1.31 +     characteristics.
    1.32 +
    1.33 +  2) Optimize lookups for datasources which have a small number
    1.34 +     of properties + fanning out to a large number of targets.
    1.35 +
    1.36 +  3) Complete implementation of thread-safety; specifically, make
    1.37 +     assertions be reference counted objects (so that a cursor can
    1.38 +     still refer to an assertion that gets removed from the graph).
    1.39 +
    1.40 + */
    1.41 +
    1.42 +#include "nsAgg.h"
    1.43 +#include "nsCOMPtr.h"
    1.44 +#include "nscore.h"
    1.45 +#include "nsArrayEnumerator.h"
    1.46 +#include "nsIOutputStream.h"
    1.47 +#include "nsIRDFDataSource.h"
    1.48 +#include "nsIRDFLiteral.h"
    1.49 +#include "nsIRDFNode.h"
    1.50 +#include "nsIRDFObserver.h"
    1.51 +#include "nsIRDFInMemoryDataSource.h"
    1.52 +#include "nsIRDFPropagatableDataSource.h"
    1.53 +#include "nsIRDFPurgeableDataSource.h"
    1.54 +#include "nsIRDFService.h"
    1.55 +#include "nsIServiceManager.h"
    1.56 +#include "nsISupportsArray.h"
    1.57 +#include "nsCOMArray.h"
    1.58 +#include "nsEnumeratorUtils.h"
    1.59 +#include "nsTArray.h"
    1.60 +#include "nsCRT.h"
    1.61 +#include "nsRDFCID.h"
    1.62 +#include "nsRDFBaseDataSources.h"
    1.63 +#include "nsString.h"
    1.64 +#include "nsReadableUtils.h"
    1.65 +#include "nsXPIDLString.h"
    1.66 +#include "rdfutil.h"
    1.67 +#include "pldhash.h"
    1.68 +#include "plstr.h"
    1.69 +#include "prlog.h"
    1.70 +#include "rdf.h"
    1.71 +
    1.72 +#include "rdfIDataSource.h"
    1.73 +#include "rdfITripleVisitor.h"
    1.74 +
    1.75 +// This struct is used as the slot value in the forward and reverse
    1.76 +// arcs hash tables.
    1.77 +//
    1.78 +// Assertion objects are reference counted, because each Assertion's
    1.79 +// ownership is shared between the datasource and any enumerators that
    1.80 +// are currently iterating over the datasource.
    1.81 +//
    1.82 +class Assertion
    1.83 +{
    1.84 +public:
    1.85 +    static PLDHashOperator
    1.86 +    DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
    1.87 +                           uint32_t aNumber, void* aArg);
    1.88 +
    1.89 +    Assertion(nsIRDFResource* aSource,      // normal assertion
    1.90 +              nsIRDFResource* aProperty,
    1.91 +              nsIRDFNode* aTarget,
    1.92 +              bool aTruthValue);
    1.93 +    Assertion(nsIRDFResource* aSource);     // PLDHashTable assertion variant
    1.94 +
    1.95 +    ~Assertion();
    1.96 +
    1.97 +    void AddRef() {
    1.98 +        if (mRefCnt == UINT16_MAX) {
    1.99 +            NS_WARNING("refcount overflow, leaking Assertion");
   1.100 +            return;
   1.101 +        }
   1.102 +        ++mRefCnt;
   1.103 +    }
   1.104 +
   1.105 +    void Release() {
   1.106 +        if (mRefCnt == UINT16_MAX) {
   1.107 +            NS_WARNING("refcount overflow, leaking Assertion");
   1.108 +            return;
   1.109 +        }
   1.110 +        if (--mRefCnt == 0)
   1.111 +            delete this;
   1.112 +    }
   1.113 +
   1.114 +    // For nsIRDFPurgeableDataSource
   1.115 +    inline  void    Mark()      { u.as.mMarked = true; }
   1.116 +    inline  bool    IsMarked()  { return u.as.mMarked; }
   1.117 +    inline  void    Unmark()    { u.as.mMarked = false; }
   1.118 +
   1.119 +    // public for now, because I'm too lazy to go thru and clean this up.
   1.120 +
   1.121 +    // These are shared between hash/as (see the union below)
   1.122 +    nsIRDFResource*         mSource;
   1.123 +    Assertion*              mNext;
   1.124 +
   1.125 +    union
   1.126 +    {
   1.127 +        struct hash
   1.128 +        {
   1.129 +            PLDHashTable*   mPropertyHash; 
   1.130 +        } hash;
   1.131 +        struct as
   1.132 +        {
   1.133 +            nsIRDFResource* mProperty;
   1.134 +            nsIRDFNode*     mTarget;
   1.135 +            Assertion*      mInvNext;
   1.136 +            // make sure bool are final elements
   1.137 +            bool            mTruthValue;
   1.138 +            bool            mMarked;
   1.139 +        } as;
   1.140 +    } u;
   1.141 +
   1.142 +    // also shared between hash/as (see the union above)
   1.143 +    // but placed after union definition to ensure that
   1.144 +    // all 32-bit entries are long aligned
   1.145 +    uint16_t                    mRefCnt;
   1.146 +    bool                        mHashEntry;
   1.147 +};
   1.148 +
   1.149 +
   1.150 +struct Entry {
   1.151 +    PLDHashEntryHdr mHdr;
   1.152 +    nsIRDFNode*     mNode;
   1.153 +    Assertion*      mAssertions;
   1.154 +};
   1.155 +
   1.156 +
   1.157 +Assertion::Assertion(nsIRDFResource* aSource)
   1.158 +    : mSource(aSource),
   1.159 +      mNext(nullptr),
   1.160 +      mRefCnt(0),
   1.161 +      mHashEntry(true)
   1.162 +{
   1.163 +    MOZ_COUNT_CTOR(RDF_Assertion);
   1.164 +
   1.165 +    NS_ADDREF(mSource);
   1.166 +
   1.167 +    u.hash.mPropertyHash = PL_NewDHashTable(PL_DHashGetStubOps(),
   1.168 +                      nullptr, sizeof(Entry), PL_DHASH_MIN_SIZE);
   1.169 +}
   1.170 +
   1.171 +Assertion::Assertion(nsIRDFResource* aSource,
   1.172 +                     nsIRDFResource* aProperty,
   1.173 +                     nsIRDFNode* aTarget,
   1.174 +                     bool aTruthValue)
   1.175 +    : mSource(aSource),
   1.176 +      mNext(nullptr),
   1.177 +      mRefCnt(0),
   1.178 +      mHashEntry(false)
   1.179 +{
   1.180 +    MOZ_COUNT_CTOR(RDF_Assertion);
   1.181 +
   1.182 +    u.as.mProperty = aProperty;
   1.183 +    u.as.mTarget = aTarget;
   1.184 +
   1.185 +    NS_ADDREF(mSource);
   1.186 +    NS_ADDREF(u.as.mProperty);
   1.187 +    NS_ADDREF(u.as.mTarget);
   1.188 +
   1.189 +    u.as.mInvNext = nullptr;
   1.190 +    u.as.mTruthValue = aTruthValue;
   1.191 +    u.as.mMarked = false;
   1.192 +}
   1.193 +
   1.194 +Assertion::~Assertion()
   1.195 +{
   1.196 +    if (mHashEntry && u.hash.mPropertyHash) {
   1.197 +        PL_DHashTableEnumerate(u.hash.mPropertyHash, DeletePropertyHashEntry,
   1.198 +                               nullptr);
   1.199 +        PL_DHashTableDestroy(u.hash.mPropertyHash);
   1.200 +        u.hash.mPropertyHash = nullptr;
   1.201 +    }
   1.202 +
   1.203 +    MOZ_COUNT_DTOR(RDF_Assertion);
   1.204 +#ifdef DEBUG_REFS
   1.205 +    --gInstanceCount;
   1.206 +    fprintf(stdout, "%d - RDF: Assertion\n", gInstanceCount);
   1.207 +#endif
   1.208 +
   1.209 +    NS_RELEASE(mSource);
   1.210 +    if (!mHashEntry)
   1.211 +    {
   1.212 +        NS_RELEASE(u.as.mProperty);
   1.213 +        NS_RELEASE(u.as.mTarget);
   1.214 +    }
   1.215 +}
   1.216 +
   1.217 +PLDHashOperator
   1.218 +Assertion::DeletePropertyHashEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.219 +                                           uint32_t aNumber, void* aArg)
   1.220 +{
   1.221 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
   1.222 +
   1.223 +    Assertion* as = entry->mAssertions;
   1.224 +    while (as) {
   1.225 +        Assertion* doomed = as;
   1.226 +        as = as->mNext;
   1.227 +
   1.228 +        // Unlink, and release the datasource's reference.
   1.229 +        doomed->mNext = doomed->u.as.mInvNext = nullptr;
   1.230 +        doomed->Release();
   1.231 +    }
   1.232 +    return PL_DHASH_NEXT;
   1.233 +}
   1.234 +
   1.235 +
   1.236 +
   1.237 +////////////////////////////////////////////////////////////////////////
   1.238 +// InMemoryDataSource
   1.239 +class InMemoryArcsEnumeratorImpl;
   1.240 +class InMemoryAssertionEnumeratorImpl;
   1.241 +class InMemoryResourceEnumeratorImpl;
   1.242 +
   1.243 +class InMemoryDataSource : public nsIRDFDataSource,
   1.244 +                           public nsIRDFInMemoryDataSource,
   1.245 +                           public nsIRDFPropagatableDataSource,
   1.246 +                           public nsIRDFPurgeableDataSource,
   1.247 +                           public rdfIDataSource
   1.248 +{
   1.249 +protected:
   1.250 +    // These hash tables are keyed on pointers to nsIRDFResource
   1.251 +    // objects (the nsIRDFService ensures that there is only ever one
   1.252 +    // nsIRDFResource object per unique URI). The value of an entry is
   1.253 +    // an Assertion struct, which is a linked list of (subject
   1.254 +    // predicate object) triples.
   1.255 +    PLDHashTable mForwardArcs; 
   1.256 +    PLDHashTable mReverseArcs; 
   1.257 +
   1.258 +    nsCOMArray<nsIRDFObserver> mObservers;  
   1.259 +    uint32_t                   mNumObservers;
   1.260 +
   1.261 +    // VisitFoo needs to block writes, [Un]Assert only allowed
   1.262 +    // during mReadCount == 0
   1.263 +    uint32_t mReadCount;
   1.264 +
   1.265 +    static PLDHashOperator
   1.266 +    DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.267 +                           uint32_t aNumber, void* aArg);
   1.268 +
   1.269 +    static PLDHashOperator
   1.270 +    ResourceEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.271 +                       uint32_t aNumber, void* aArg);
   1.272 +
   1.273 +    friend class InMemoryArcsEnumeratorImpl;
   1.274 +    friend class InMemoryAssertionEnumeratorImpl;
   1.275 +    friend class InMemoryResourceEnumeratorImpl; // b/c it needs to enumerate mForwardArcs
   1.276 +
   1.277 +    // Thread-safe writer implementation methods.
   1.278 +    nsresult
   1.279 +    LockedAssert(nsIRDFResource* source, 
   1.280 +                 nsIRDFResource* property, 
   1.281 +                 nsIRDFNode* target,
   1.282 +                 bool tv);
   1.283 +
   1.284 +    nsresult
   1.285 +    LockedUnassert(nsIRDFResource* source,
   1.286 +                   nsIRDFResource* property,
   1.287 +                   nsIRDFNode* target);
   1.288 +
   1.289 +    InMemoryDataSource(nsISupports* aOuter);
   1.290 +    virtual ~InMemoryDataSource();
   1.291 +    nsresult Init();
   1.292 +
   1.293 +    friend nsresult
   1.294 +    NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult);
   1.295 +
   1.296 +public:
   1.297 +    NS_DECL_CYCLE_COLLECTING_AGGREGATED
   1.298 +    NS_DECL_AGGREGATED_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
   1.299 +
   1.300 +    // nsIRDFDataSource methods
   1.301 +    NS_DECL_NSIRDFDATASOURCE
   1.302 +
   1.303 +    // nsIRDFInMemoryDataSource methods
   1.304 +    NS_DECL_NSIRDFINMEMORYDATASOURCE
   1.305 +
   1.306 +    // nsIRDFPropagatableDataSource methods
   1.307 +    NS_DECL_NSIRDFPROPAGATABLEDATASOURCE
   1.308 +
   1.309 +    // nsIRDFPurgeableDataSource methods
   1.310 +    NS_DECL_NSIRDFPURGEABLEDATASOURCE
   1.311 +
   1.312 +    // rdfIDataSource methods
   1.313 +    NS_DECL_RDFIDATASOURCE
   1.314 +
   1.315 +protected:
   1.316 +    static PLDHashOperator
   1.317 +    SweepForwardArcsEntries(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.318 +                            uint32_t aNumber, void* aArg);
   1.319 +
   1.320 +public:
   1.321 +    // Implementation methods
   1.322 +    Assertion*
   1.323 +    GetForwardArcs(nsIRDFResource* u) {
   1.324 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u, PL_DHASH_LOOKUP);
   1.325 +        return PL_DHASH_ENTRY_IS_BUSY(hdr)
   1.326 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
   1.327 +            : nullptr; }
   1.328 +
   1.329 +    Assertion*
   1.330 +    GetReverseArcs(nsIRDFNode* v) {
   1.331 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v, PL_DHASH_LOOKUP);
   1.332 +        return PL_DHASH_ENTRY_IS_BUSY(hdr)
   1.333 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
   1.334 +            : nullptr; }
   1.335 +
   1.336 +    void
   1.337 +    SetForwardArcs(nsIRDFResource* u, Assertion* as) {
   1.338 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mForwardArcs, u,
   1.339 +                                                    as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
   1.340 +        if (as && hdr) {
   1.341 +            Entry* entry = reinterpret_cast<Entry*>(hdr);
   1.342 +            entry->mNode = u;
   1.343 +            entry->mAssertions = as;
   1.344 +        } }
   1.345 +
   1.346 +    void
   1.347 +    SetReverseArcs(nsIRDFNode* v, Assertion* as) {
   1.348 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(&mReverseArcs, v,
   1.349 +                                                    as ? PL_DHASH_ADD : PL_DHASH_REMOVE);
   1.350 +        if (as && hdr) {
   1.351 +            Entry* entry = reinterpret_cast<Entry*>(hdr);
   1.352 +            entry->mNode = v;
   1.353 +            entry->mAssertions = as;
   1.354 +        } }
   1.355 +
   1.356 +#ifdef PR_LOGGING
   1.357 +    void
   1.358 +    LogOperation(const char* aOperation,
   1.359 +                 nsIRDFResource* asource,
   1.360 +                 nsIRDFResource* aProperty,
   1.361 +                 nsIRDFNode* aTarget,
   1.362 +                 bool aTruthValue = true);
   1.363 +#endif
   1.364 +
   1.365 +    bool    mPropagateChanges;
   1.366 +
   1.367 +private:
   1.368 +#ifdef PR_LOGGING
   1.369 +    static PRLogModuleInfo* gLog;
   1.370 +#endif
   1.371 +};
   1.372 +
   1.373 +#ifdef PR_LOGGING
   1.374 +PRLogModuleInfo* InMemoryDataSource::gLog;
   1.375 +#endif
   1.376 +
   1.377 +//----------------------------------------------------------------------
   1.378 +//
   1.379 +// InMemoryAssertionEnumeratorImpl
   1.380 +//
   1.381 +
   1.382 +/**
   1.383 + * InMemoryAssertionEnumeratorImpl
   1.384 + */
   1.385 +class InMemoryAssertionEnumeratorImpl : public nsISimpleEnumerator
   1.386 +{
   1.387 +private:
   1.388 +    InMemoryDataSource* mDataSource;
   1.389 +    nsIRDFResource* mSource;
   1.390 +    nsIRDFResource* mProperty;
   1.391 +    nsIRDFNode*     mTarget;
   1.392 +    nsIRDFNode*     mValue;
   1.393 +    bool            mTruthValue;
   1.394 +    Assertion*      mNextAssertion;
   1.395 +    nsCOMPtr<nsISupportsArray> mHashArcs;
   1.396 +
   1.397 +public:
   1.398 +    InMemoryAssertionEnumeratorImpl(InMemoryDataSource* aDataSource,
   1.399 +                                    nsIRDFResource* aSource,
   1.400 +                                    nsIRDFResource* aProperty,
   1.401 +                                    nsIRDFNode* aTarget,
   1.402 +                                    bool aTruthValue);
   1.403 +
   1.404 +    virtual ~InMemoryAssertionEnumeratorImpl();
   1.405 +
   1.406 +    // nsISupports interface
   1.407 +    NS_DECL_ISUPPORTS
   1.408 +
   1.409 +    // nsISimpleEnumerator interface
   1.410 +    NS_DECL_NSISIMPLEENUMERATOR
   1.411 +};
   1.412 +
   1.413 +////////////////////////////////////////////////////////////////////////
   1.414 +
   1.415 +
   1.416 +InMemoryAssertionEnumeratorImpl::InMemoryAssertionEnumeratorImpl(
   1.417 +                 InMemoryDataSource* aDataSource,
   1.418 +                 nsIRDFResource* aSource,
   1.419 +                 nsIRDFResource* aProperty,
   1.420 +                 nsIRDFNode* aTarget,
   1.421 +                 bool aTruthValue)
   1.422 +    : mDataSource(aDataSource),
   1.423 +      mSource(aSource),
   1.424 +      mProperty(aProperty),
   1.425 +      mTarget(aTarget),
   1.426 +      mValue(nullptr),
   1.427 +      mTruthValue(aTruthValue),
   1.428 +      mNextAssertion(nullptr)
   1.429 +{
   1.430 +    NS_ADDREF(mDataSource);
   1.431 +    NS_IF_ADDREF(mSource);
   1.432 +    NS_ADDREF(mProperty);
   1.433 +    NS_IF_ADDREF(mTarget);
   1.434 +
   1.435 +    if (mSource) {
   1.436 +        mNextAssertion = mDataSource->GetForwardArcs(mSource);
   1.437 +
   1.438 +        if (mNextAssertion && mNextAssertion->mHashEntry) {
   1.439 +            // its our magical HASH_ENTRY forward hash for assertions
   1.440 +            PLDHashEntryHdr* hdr = PL_DHashTableOperate(mNextAssertion->u.hash.mPropertyHash,
   1.441 +                aProperty, PL_DHASH_LOOKUP);
   1.442 +            mNextAssertion = PL_DHASH_ENTRY_IS_BUSY(hdr)
   1.443 +                ? reinterpret_cast<Entry*>(hdr)->mAssertions
   1.444 +                : nullptr;
   1.445 +        }
   1.446 +    }
   1.447 +    else {
   1.448 +        mNextAssertion = mDataSource->GetReverseArcs(mTarget);
   1.449 +    }
   1.450 +
   1.451 +    // Add an owning reference from the enumerator
   1.452 +    if (mNextAssertion)
   1.453 +        mNextAssertion->AddRef();
   1.454 +}
   1.455 +
   1.456 +InMemoryAssertionEnumeratorImpl::~InMemoryAssertionEnumeratorImpl()
   1.457 +{
   1.458 +#ifdef DEBUG_REFS
   1.459 +    --gInstanceCount;
   1.460 +    fprintf(stdout, "%d - RDF: InMemoryAssertionEnumeratorImpl\n", gInstanceCount);
   1.461 +#endif
   1.462 +
   1.463 +    if (mNextAssertion)
   1.464 +        mNextAssertion->Release();
   1.465 +
   1.466 +    NS_IF_RELEASE(mDataSource);
   1.467 +    NS_IF_RELEASE(mSource);
   1.468 +    NS_IF_RELEASE(mProperty);
   1.469 +    NS_IF_RELEASE(mTarget);
   1.470 +    NS_IF_RELEASE(mValue);
   1.471 +}
   1.472 +
   1.473 +NS_IMPL_ADDREF(InMemoryAssertionEnumeratorImpl)
   1.474 +NS_IMPL_RELEASE(InMemoryAssertionEnumeratorImpl)
   1.475 +NS_IMPL_QUERY_INTERFACE(InMemoryAssertionEnumeratorImpl, nsISimpleEnumerator)
   1.476 +
   1.477 +NS_IMETHODIMP
   1.478 +InMemoryAssertionEnumeratorImpl::HasMoreElements(bool* aResult)
   1.479 +{
   1.480 +    if (mValue) {
   1.481 +        *aResult = true;
   1.482 +        return NS_OK;
   1.483 +    }
   1.484 +
   1.485 +    while (mNextAssertion) {
   1.486 +        bool foundIt = false;
   1.487 +        if ((mProperty == mNextAssertion->u.as.mProperty) &&
   1.488 +            (mTruthValue == mNextAssertion->u.as.mTruthValue)) {
   1.489 +            if (mSource) {
   1.490 +                mValue = mNextAssertion->u.as.mTarget;
   1.491 +                NS_ADDREF(mValue);
   1.492 +            }
   1.493 +            else {
   1.494 +                mValue = mNextAssertion->mSource;
   1.495 +                NS_ADDREF(mValue);
   1.496 +            }
   1.497 +            foundIt = true;
   1.498 +        }
   1.499 +
   1.500 +        // Remember the last assertion we were holding on to
   1.501 +        Assertion* as = mNextAssertion;
   1.502 +
   1.503 +        // iterate
   1.504 +        mNextAssertion = (mSource) ? mNextAssertion->mNext : mNextAssertion->u.as.mInvNext;
   1.505 +
   1.506 +        // grab an owning reference from the enumerator to the next assertion
   1.507 +        if (mNextAssertion)
   1.508 +            mNextAssertion->AddRef();
   1.509 +
   1.510 +        // ...and release the reference from the enumerator to the old one.
   1.511 +        as->Release();
   1.512 +
   1.513 +        if (foundIt) {
   1.514 +            *aResult = true;
   1.515 +            return NS_OK;
   1.516 +        }
   1.517 +    }
   1.518 +
   1.519 +    *aResult = false;
   1.520 +    return NS_OK;
   1.521 +}
   1.522 +
   1.523 +
   1.524 +NS_IMETHODIMP
   1.525 +InMemoryAssertionEnumeratorImpl::GetNext(nsISupports** aResult)
   1.526 +{
   1.527 +    nsresult rv;
   1.528 +
   1.529 +    bool hasMore;
   1.530 +    rv = HasMoreElements(&hasMore);
   1.531 +    if (NS_FAILED(rv)) return rv;
   1.532 +
   1.533 +    if (! hasMore)
   1.534 +        return NS_ERROR_UNEXPECTED;
   1.535 +
   1.536 +    // Don't AddRef: we "transfer" ownership to the caller
   1.537 +    *aResult = mValue;
   1.538 +    mValue = nullptr;
   1.539 +
   1.540 +    return NS_OK;
   1.541 +}
   1.542 +
   1.543 +////////////////////////////////////////////////////////////////////////
   1.544 +//
   1.545 +
   1.546 +/**
   1.547 + * This class is a little bit bizarre in that it implements both the
   1.548 + * <tt>nsIRDFArcsOutCursor</tt> and <tt>nsIRDFArcsInCursor</tt> interfaces.
   1.549 + * Because the structure of the in-memory graph is pretty flexible, it's
   1.550 + * fairly easy to parameterize this class. The only funky thing to watch
   1.551 + * out for is the multiple inheritance clashes.
   1.552 + */
   1.553 +
   1.554 +class InMemoryArcsEnumeratorImpl : public nsISimpleEnumerator
   1.555 +{
   1.556 +private:
   1.557 +    InMemoryDataSource* mDataSource;
   1.558 +    nsIRDFResource*     mSource;
   1.559 +    nsIRDFNode*         mTarget;
   1.560 +    nsAutoTArray<nsCOMPtr<nsIRDFResource>, 8> mAlreadyReturned;
   1.561 +    nsIRDFResource*     mCurrent;
   1.562 +    Assertion*          mAssertion;
   1.563 +    nsCOMPtr<nsISupportsArray> mHashArcs;
   1.564 +
   1.565 +    static PLDHashOperator
   1.566 +    ArcEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.567 +                       uint32_t aNumber, void* aArg);
   1.568 +
   1.569 +public:
   1.570 +    InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
   1.571 +                               nsIRDFResource* aSource,
   1.572 +                               nsIRDFNode* aTarget);
   1.573 +
   1.574 +    virtual ~InMemoryArcsEnumeratorImpl();
   1.575 +
   1.576 +    // nsISupports interface
   1.577 +    NS_DECL_ISUPPORTS
   1.578 +
   1.579 +    // nsISimpleEnumerator interface
   1.580 +    NS_DECL_NSISIMPLEENUMERATOR
   1.581 +};
   1.582 +
   1.583 +
   1.584 +PLDHashOperator
   1.585 +InMemoryArcsEnumeratorImpl::ArcEnumerator(PLDHashTable* aTable,
   1.586 +                                       PLDHashEntryHdr* aHdr,
   1.587 +                                       uint32_t aNumber, void* aArg)
   1.588 +{
   1.589 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
   1.590 +    nsISupportsArray* resources = static_cast<nsISupportsArray*>(aArg);
   1.591 +
   1.592 +    resources->AppendElement(entry->mNode);
   1.593 +    return PL_DHASH_NEXT;
   1.594 +}
   1.595 +
   1.596 +
   1.597 +InMemoryArcsEnumeratorImpl::InMemoryArcsEnumeratorImpl(InMemoryDataSource* aDataSource,
   1.598 +                                                       nsIRDFResource* aSource,
   1.599 +                                                       nsIRDFNode* aTarget)
   1.600 +    : mDataSource(aDataSource),
   1.601 +      mSource(aSource),
   1.602 +      mTarget(aTarget),
   1.603 +      mCurrent(nullptr)
   1.604 +{
   1.605 +    NS_ADDREF(mDataSource);
   1.606 +    NS_IF_ADDREF(mSource);
   1.607 +    NS_IF_ADDREF(mTarget);
   1.608 +
   1.609 +    if (mSource) {
   1.610 +        // cast okay because it's a closed system
   1.611 +        mAssertion = mDataSource->GetForwardArcs(mSource);
   1.612 +
   1.613 +        if (mAssertion && mAssertion->mHashEntry) {
   1.614 +            // its our magical HASH_ENTRY forward hash for assertions
   1.615 +            nsresult rv = NS_NewISupportsArray(getter_AddRefs(mHashArcs));
   1.616 +            if (NS_SUCCEEDED(rv)) {
   1.617 +                PL_DHashTableEnumerate(mAssertion->u.hash.mPropertyHash,
   1.618 +                    ArcEnumerator, mHashArcs.get());
   1.619 +            }
   1.620 +            mAssertion = nullptr;
   1.621 +        }
   1.622 +    }
   1.623 +    else {
   1.624 +        mAssertion = mDataSource->GetReverseArcs(mTarget);
   1.625 +    }
   1.626 +}
   1.627 +
   1.628 +InMemoryArcsEnumeratorImpl::~InMemoryArcsEnumeratorImpl()
   1.629 +{
   1.630 +#ifdef DEBUG_REFS
   1.631 +    --gInstanceCount;
   1.632 +    fprintf(stdout, "%d - RDF: InMemoryArcsEnumeratorImpl\n", gInstanceCount);
   1.633 +#endif
   1.634 +
   1.635 +    NS_RELEASE(mDataSource);
   1.636 +    NS_IF_RELEASE(mSource);
   1.637 +    NS_IF_RELEASE(mTarget);
   1.638 +    NS_IF_RELEASE(mCurrent);
   1.639 +}
   1.640 +
   1.641 +NS_IMPL_ADDREF(InMemoryArcsEnumeratorImpl)
   1.642 +NS_IMPL_RELEASE(InMemoryArcsEnumeratorImpl)
   1.643 +NS_IMPL_QUERY_INTERFACE(InMemoryArcsEnumeratorImpl, nsISimpleEnumerator)
   1.644 +
   1.645 +NS_IMETHODIMP
   1.646 +InMemoryArcsEnumeratorImpl::HasMoreElements(bool* aResult)
   1.647 +{
   1.648 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.649 +    if (! aResult)
   1.650 +        return NS_ERROR_NULL_POINTER;
   1.651 +
   1.652 +    if (mCurrent) {
   1.653 +        *aResult = true;
   1.654 +        return NS_OK;
   1.655 +    }
   1.656 +
   1.657 +    if (mHashArcs) {
   1.658 +        uint32_t    itemCount;
   1.659 +        nsresult    rv;
   1.660 +        if (NS_FAILED(rv = mHashArcs->Count(&itemCount)))   return(rv);
   1.661 +        if (itemCount > 0) {
   1.662 +            --itemCount;
   1.663 +            nsCOMPtr<nsIRDFResource> tmp = do_QueryElementAt(mHashArcs, itemCount);
   1.664 +            tmp.forget(&mCurrent);
   1.665 +            mHashArcs->RemoveElementAt(itemCount);
   1.666 +            *aResult = true;
   1.667 +            return NS_OK;
   1.668 +        }
   1.669 +    }
   1.670 +    else
   1.671 +        while (mAssertion) {
   1.672 +            nsIRDFResource* next = mAssertion->u.as.mProperty;
   1.673 +
   1.674 +            // "next" is the property arc we are tentatively going to return
   1.675 +            // in a subsequent GetNext() call.  It is important to do two
   1.676 +            // things, however, before that can happen:
   1.677 +            //   1) Make sure it's not an arc we've already returned.
   1.678 +            //   2) Make sure that |mAssertion| is not left pointing to
   1.679 +            //      another assertion that has the same property as this one.
   1.680 +            // The first is a practical concern; the second a defense against
   1.681 +            // an obscure crash and other erratic behavior.  To ensure the
   1.682 +            // second condition, skip down the chain until we find the next 
   1.683 +            // assertion with a property that doesn't match the current one.
   1.684 +            // (All these assertions would be skipped via mAlreadyReturned
   1.685 +            // checks anyways; this is even a bit faster.)
   1.686 +
   1.687 +            do {
   1.688 +                mAssertion = (mSource ? mAssertion->mNext :
   1.689 +                        mAssertion->u.as.mInvNext);
   1.690 +            }
   1.691 +            while (mAssertion && (next == mAssertion->u.as.mProperty));
   1.692 +
   1.693 +            bool alreadyReturned = false;
   1.694 +            for (int32_t i = mAlreadyReturned.Length() - 1; i >= 0; --i) {
   1.695 +                if (mAlreadyReturned[i] == next) {
   1.696 +                    alreadyReturned = true;
   1.697 +                    break;
   1.698 +                }
   1.699 +            }
   1.700 +
   1.701 +            if (! alreadyReturned) {
   1.702 +                mCurrent = next;
   1.703 +                NS_ADDREF(mCurrent);
   1.704 +                *aResult = true;
   1.705 +                return NS_OK;
   1.706 +            }
   1.707 +        }
   1.708 +
   1.709 +    *aResult = false;
   1.710 +    return NS_OK;
   1.711 +}
   1.712 +
   1.713 +
   1.714 +NS_IMETHODIMP
   1.715 +InMemoryArcsEnumeratorImpl::GetNext(nsISupports** aResult)
   1.716 +{
   1.717 +    nsresult rv;
   1.718 +
   1.719 +    bool hasMore;
   1.720 +    rv = HasMoreElements(&hasMore);
   1.721 +    if (NS_FAILED(rv)) return rv;
   1.722 +
   1.723 +    if (! hasMore)
   1.724 +        return NS_ERROR_UNEXPECTED;
   1.725 +
   1.726 +    // Add this to the set of things we've already returned so that we
   1.727 +    // can ensure uniqueness
   1.728 +    mAlreadyReturned.AppendElement(mCurrent);
   1.729 +
   1.730 +    // Don't AddRef: we "transfer" ownership to the caller
   1.731 +    *aResult = mCurrent;
   1.732 +    mCurrent = nullptr;
   1.733 +
   1.734 +    return NS_OK;
   1.735 +}
   1.736 +
   1.737 +
   1.738 +////////////////////////////////////////////////////////////////////////
   1.739 +// InMemoryDataSource
   1.740 +
   1.741 +nsresult
   1.742 +NS_NewRDFInMemoryDataSource(nsISupports* aOuter, const nsIID& aIID, void** aResult)
   1.743 +{
   1.744 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
   1.745 +    if (! aResult)
   1.746 +        return NS_ERROR_NULL_POINTER;
   1.747 +    *aResult = nullptr;
   1.748 +
   1.749 +    if (aOuter && !aIID.Equals(NS_GET_IID(nsISupports))) {
   1.750 +        NS_ERROR("aggregation requires nsISupports");
   1.751 +        return NS_ERROR_ILLEGAL_VALUE;
   1.752 +    }
   1.753 +
   1.754 +    InMemoryDataSource* datasource = new InMemoryDataSource(aOuter);
   1.755 +    if (! datasource)
   1.756 +        return NS_ERROR_OUT_OF_MEMORY;
   1.757 +    NS_ADDREF(datasource);
   1.758 +
   1.759 +    nsresult rv = datasource->Init();
   1.760 +    if (NS_SUCCEEDED(rv)) {
   1.761 +        datasource->fAggregated.AddRef();
   1.762 +        rv = datasource->AggregatedQueryInterface(aIID, aResult); // This'll AddRef()
   1.763 +        datasource->fAggregated.Release();
   1.764 +    }
   1.765 +
   1.766 +    NS_RELEASE(datasource);
   1.767 +    return rv;
   1.768 +}
   1.769 +
   1.770 +
   1.771 +InMemoryDataSource::InMemoryDataSource(nsISupports* aOuter)
   1.772 +    : mNumObservers(0), mReadCount(0)
   1.773 +{
   1.774 +    NS_INIT_AGGREGATED(aOuter);
   1.775 +
   1.776 +    mForwardArcs.ops = nullptr;
   1.777 +    mReverseArcs.ops = nullptr;
   1.778 +    mPropagateChanges = true;
   1.779 +    MOZ_COUNT_CTOR(InMemoryDataSource);
   1.780 +}
   1.781 +
   1.782 +
   1.783 +nsresult
   1.784 +InMemoryDataSource::Init()
   1.785 +{
   1.786 +    PL_DHashTableInit(&mForwardArcs,
   1.787 +                      PL_DHashGetStubOps(),
   1.788 +                      nullptr,
   1.789 +                      sizeof(Entry),
   1.790 +                      PL_DHASH_MIN_SIZE);
   1.791 +
   1.792 +    PL_DHashTableInit(&mReverseArcs,
   1.793 +                      PL_DHashGetStubOps(),
   1.794 +                      nullptr,
   1.795 +                      sizeof(Entry),
   1.796 +                      PL_DHASH_MIN_SIZE);
   1.797 +
   1.798 +#ifdef PR_LOGGING
   1.799 +    if (! gLog)
   1.800 +        gLog = PR_NewLogModule("InMemoryDataSource");
   1.801 +#endif
   1.802 +
   1.803 +    return NS_OK;
   1.804 +}
   1.805 +
   1.806 +
   1.807 +InMemoryDataSource::~InMemoryDataSource()
   1.808 +{
   1.809 +#ifdef DEBUG_REFS
   1.810 +    --gInstanceCount;
   1.811 +    fprintf(stdout, "%d - RDF: InMemoryDataSource\n", gInstanceCount);
   1.812 +#endif
   1.813 +
   1.814 +    if (mForwardArcs.ops) {
   1.815 +        // This'll release all of the Assertion objects that are
   1.816 +        // associated with this data source. We only need to do this
   1.817 +        // for the forward arcs, because the reverse arcs table
   1.818 +        // indexes the exact same set of resources.
   1.819 +        PL_DHashTableEnumerate(&mForwardArcs, DeleteForwardArcsEntry, nullptr);
   1.820 +        PL_DHashTableFinish(&mForwardArcs);
   1.821 +    }
   1.822 +    if (mReverseArcs.ops)
   1.823 +        PL_DHashTableFinish(&mReverseArcs);
   1.824 +
   1.825 +    PR_LOG(gLog, PR_LOG_NOTICE,
   1.826 +           ("InMemoryDataSource(%p): destroyed.", this));
   1.827 +
   1.828 +    MOZ_COUNT_DTOR(InMemoryDataSource);
   1.829 +}
   1.830 +
   1.831 +PLDHashOperator
   1.832 +InMemoryDataSource::DeleteForwardArcsEntry(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
   1.833 +                                           uint32_t aNumber, void* aArg)
   1.834 +{
   1.835 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
   1.836 +
   1.837 +    Assertion* as = entry->mAssertions;
   1.838 +    while (as) {
   1.839 +        Assertion* doomed = as;
   1.840 +        as = as->mNext;
   1.841 +
   1.842 +        // Unlink, and release the datasource's reference.
   1.843 +        doomed->mNext = doomed->u.as.mInvNext = nullptr;
   1.844 +        doomed->Release();
   1.845 +    }
   1.846 +    return PL_DHASH_NEXT;
   1.847 +}
   1.848 +
   1.849 +
   1.850 +////////////////////////////////////////////////////////////////////////
   1.851 +
   1.852 +NS_IMPL_CYCLE_COLLECTION_CLASS(InMemoryDataSource)
   1.853 +
   1.854 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(InMemoryDataSource)
   1.855 +    NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers)
   1.856 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.857 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_AGGREGATED(InMemoryDataSource)
   1.858 +    NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
   1.859 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.860 +
   1.861 +NS_IMPL_CYCLE_COLLECTING_AGGREGATED(InMemoryDataSource)
   1.862 +NS_INTERFACE_MAP_BEGIN_AGGREGATED(InMemoryDataSource)
   1.863 +    NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION_AGGREGATED(InMemoryDataSource)
   1.864 +    NS_INTERFACE_MAP_ENTRY(nsIRDFDataSource)
   1.865 +    NS_INTERFACE_MAP_ENTRY(nsIRDFInMemoryDataSource)
   1.866 +    NS_INTERFACE_MAP_ENTRY(nsIRDFPropagatableDataSource)
   1.867 +    NS_INTERFACE_MAP_ENTRY(nsIRDFPurgeableDataSource)
   1.868 +    NS_INTERFACE_MAP_ENTRY(rdfIDataSource)
   1.869 +NS_INTERFACE_MAP_END
   1.870 +
   1.871 +////////////////////////////////////////////////////////////////////////
   1.872 +
   1.873 +
   1.874 +#ifdef PR_LOGGING
   1.875 +void
   1.876 +InMemoryDataSource::LogOperation(const char* aOperation,
   1.877 +                                 nsIRDFResource* aSource,
   1.878 +                                 nsIRDFResource* aProperty,
   1.879 +                                 nsIRDFNode* aTarget,
   1.880 +                                 bool aTruthValue)
   1.881 +{
   1.882 +    if (! PR_LOG_TEST(gLog, PR_LOG_NOTICE))
   1.883 +        return;
   1.884 +
   1.885 +    nsXPIDLCString uri;
   1.886 +    aSource->GetValue(getter_Copies(uri));
   1.887 +    PR_LogPrint
   1.888 +           ("InMemoryDataSource(%p): %s", this, aOperation);
   1.889 +
   1.890 +    PR_LogPrint
   1.891 +           ("  [(%p)%s]--", aSource, (const char*) uri);
   1.892 +
   1.893 +    aProperty->GetValue(getter_Copies(uri));
   1.894 +
   1.895 +    char tv = (aTruthValue ? '-' : '!');
   1.896 +    PR_LogPrint
   1.897 +           ("  --%c[(%p)%s]--", tv, aProperty, (const char*) uri);
   1.898 +
   1.899 +    nsCOMPtr<nsIRDFResource> resource;
   1.900 +    nsCOMPtr<nsIRDFLiteral> literal;
   1.901 +
   1.902 +    if ((resource = do_QueryInterface(aTarget)) != nullptr) {
   1.903 +        resource->GetValue(getter_Copies(uri));
   1.904 +        PR_LogPrint
   1.905 +           ("  -->[(%p)%s]", aTarget, (const char*) uri);
   1.906 +    }
   1.907 +    else if ((literal = do_QueryInterface(aTarget)) != nullptr) {
   1.908 +        nsXPIDLString value;
   1.909 +        literal->GetValue(getter_Copies(value));
   1.910 +        nsAutoString valueStr(value);
   1.911 +        char* valueCStr = ToNewCString(valueStr);
   1.912 +
   1.913 +        PR_LogPrint
   1.914 +           ("  -->(\"%s\")\n", valueCStr);
   1.915 +
   1.916 +        NS_Free(valueCStr);
   1.917 +    }
   1.918 +    else {
   1.919 +        PR_LogPrint
   1.920 +           ("  -->(unknown-type)\n");
   1.921 +    }
   1.922 +}
   1.923 +#endif
   1.924 +
   1.925 +
   1.926 +NS_IMETHODIMP
   1.927 +InMemoryDataSource::GetURI(char* *uri)
   1.928 +{
   1.929 +    NS_PRECONDITION(uri != nullptr, "null ptr");
   1.930 +    if (! uri)
   1.931 +        return NS_ERROR_NULL_POINTER;
   1.932 +
   1.933 +    *uri = nullptr;
   1.934 +    return NS_OK;
   1.935 +}
   1.936 +
   1.937 +NS_IMETHODIMP
   1.938 +InMemoryDataSource::GetSource(nsIRDFResource* property,
   1.939 +                              nsIRDFNode* target,
   1.940 +                              bool tv,
   1.941 +                              nsIRDFResource** source)
   1.942 +{
   1.943 +    NS_PRECONDITION(source != nullptr, "null ptr");
   1.944 +    if (! source)
   1.945 +        return NS_ERROR_NULL_POINTER;
   1.946 +
   1.947 +    NS_PRECONDITION(property != nullptr, "null ptr");
   1.948 +    if (! property)
   1.949 +        return NS_ERROR_NULL_POINTER;
   1.950 +
   1.951 +    NS_PRECONDITION(target != nullptr, "null ptr");
   1.952 +    if (! target)
   1.953 +        return NS_ERROR_NULL_POINTER;
   1.954 +
   1.955 +    for (Assertion* as = GetReverseArcs(target); as; as = as->u.as.mInvNext) {
   1.956 +        if ((property == as->u.as.mProperty) && (tv == as->u.as.mTruthValue)) {
   1.957 +            *source = as->mSource;
   1.958 +            NS_ADDREF(*source);
   1.959 +            return NS_OK;
   1.960 +        }
   1.961 +    }
   1.962 +    *source = nullptr;
   1.963 +    return NS_RDF_NO_VALUE;
   1.964 +}
   1.965 +
   1.966 +NS_IMETHODIMP
   1.967 +InMemoryDataSource::GetTarget(nsIRDFResource* source,
   1.968 +                              nsIRDFResource* property,
   1.969 +                              bool tv,
   1.970 +                              nsIRDFNode** target)
   1.971 +{
   1.972 +    NS_PRECONDITION(source != nullptr, "null ptr");
   1.973 +    if (! source)
   1.974 +        return NS_ERROR_NULL_POINTER;
   1.975 +
   1.976 +    NS_PRECONDITION(property != nullptr, "null ptr");
   1.977 +    if (! property)
   1.978 +        return NS_ERROR_NULL_POINTER;
   1.979 +
   1.980 +    NS_PRECONDITION(target != nullptr, "null ptr");
   1.981 +    if (! target)
   1.982 +        return NS_ERROR_NULL_POINTER;
   1.983 +
   1.984 +    Assertion *as = GetForwardArcs(source);
   1.985 +    if (as && as->mHashEntry) {
   1.986 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
   1.987 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
   1.988 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
   1.989 +            : nullptr;
   1.990 +        while (val) {
   1.991 +            if (tv == val->u.as.mTruthValue) {
   1.992 +                *target = val->u.as.mTarget;
   1.993 +                NS_IF_ADDREF(*target);
   1.994 +                return NS_OK;
   1.995 +            }
   1.996 +            val = val->mNext;
   1.997 +        }
   1.998 +    }
   1.999 +    else
  1.1000 +    for (; as != nullptr; as = as->mNext) {
  1.1001 +        if ((property == as->u.as.mProperty) && (tv == (as->u.as.mTruthValue))) {
  1.1002 +            *target = as->u.as.mTarget;
  1.1003 +            NS_ADDREF(*target);
  1.1004 +            return NS_OK;
  1.1005 +        }
  1.1006 +    }
  1.1007 +
  1.1008 +    // If we get here, then there was no target with for the specified
  1.1009 +    // property & truth value.
  1.1010 +    *target = nullptr;
  1.1011 +    return NS_RDF_NO_VALUE;
  1.1012 +}
  1.1013 +
  1.1014 +NS_IMETHODIMP
  1.1015 +InMemoryDataSource::HasAssertion(nsIRDFResource* source,
  1.1016 +                                 nsIRDFResource* property,
  1.1017 +                                 nsIRDFNode* target,
  1.1018 +                                 bool tv,
  1.1019 +                                 bool* hasAssertion)
  1.1020 +{
  1.1021 +    if (! source)
  1.1022 +        return NS_ERROR_NULL_POINTER;
  1.1023 +
  1.1024 +    if (! property)
  1.1025 +        return NS_ERROR_NULL_POINTER;
  1.1026 +
  1.1027 +    if (! target)
  1.1028 +        return NS_ERROR_NULL_POINTER;
  1.1029 +
  1.1030 +    Assertion *as = GetForwardArcs(source);
  1.1031 +    if (as && as->mHashEntry) {
  1.1032 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash, property, PL_DHASH_LOOKUP);
  1.1033 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1034 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1035 +            : nullptr;
  1.1036 +        while (val) {
  1.1037 +            if ((val->u.as.mTarget == target) && (tv == (val->u.as.mTruthValue))) {
  1.1038 +                *hasAssertion = true;
  1.1039 +                return NS_OK;
  1.1040 +            }
  1.1041 +            val = val->mNext;
  1.1042 +        }
  1.1043 +    }
  1.1044 +    else
  1.1045 +    for (; as != nullptr; as = as->mNext) {
  1.1046 +        // check target first as its most unique
  1.1047 +        if (target != as->u.as.mTarget)
  1.1048 +            continue;
  1.1049 +
  1.1050 +        if (property != as->u.as.mProperty)
  1.1051 +            continue;
  1.1052 +
  1.1053 +        if (tv != (as->u.as.mTruthValue))
  1.1054 +            continue;
  1.1055 +
  1.1056 +        // found it!
  1.1057 +        *hasAssertion = true;
  1.1058 +        return NS_OK;
  1.1059 +    }
  1.1060 +
  1.1061 +    // If we get here, we couldn't find the assertion
  1.1062 +    *hasAssertion = false;
  1.1063 +    return NS_OK;
  1.1064 +}
  1.1065 +
  1.1066 +NS_IMETHODIMP
  1.1067 +InMemoryDataSource::GetSources(nsIRDFResource* aProperty,
  1.1068 +                               nsIRDFNode* aTarget,
  1.1069 +                               bool aTruthValue,
  1.1070 +                               nsISimpleEnumerator** aResult)
  1.1071 +{
  1.1072 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1073 +    if (! aProperty)
  1.1074 +        return NS_ERROR_NULL_POINTER;
  1.1075 +
  1.1076 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1077 +    if (! aTarget)
  1.1078 +        return NS_ERROR_NULL_POINTER;
  1.1079 +
  1.1080 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
  1.1081 +    if (! aResult)
  1.1082 +        return NS_ERROR_NULL_POINTER;
  1.1083 +
  1.1084 +    InMemoryAssertionEnumeratorImpl* result =
  1.1085 +        new InMemoryAssertionEnumeratorImpl(this, nullptr, aProperty,
  1.1086 +                                            aTarget, aTruthValue);
  1.1087 +
  1.1088 +    if (! result)
  1.1089 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1090 +
  1.1091 +    NS_ADDREF(result);
  1.1092 +    *aResult = result;
  1.1093 +
  1.1094 +    return NS_OK;
  1.1095 +}
  1.1096 +
  1.1097 +NS_IMETHODIMP
  1.1098 +InMemoryDataSource::GetTargets(nsIRDFResource* aSource,
  1.1099 +                               nsIRDFResource* aProperty,
  1.1100 +                               bool aTruthValue,
  1.1101 +                               nsISimpleEnumerator** aResult)
  1.1102 +{
  1.1103 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1104 +    if (! aSource)
  1.1105 +        return NS_ERROR_NULL_POINTER;
  1.1106 +
  1.1107 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1108 +    if (! aProperty)
  1.1109 +        return NS_ERROR_NULL_POINTER;
  1.1110 +
  1.1111 +    NS_PRECONDITION(aResult != nullptr, "null ptr");
  1.1112 +    if (! aResult)
  1.1113 +        return NS_ERROR_NULL_POINTER;
  1.1114 +
  1.1115 +    InMemoryAssertionEnumeratorImpl* result =
  1.1116 +        new InMemoryAssertionEnumeratorImpl(this, aSource, aProperty,
  1.1117 +                                            nullptr, aTruthValue);
  1.1118 +
  1.1119 +    if (! result)
  1.1120 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1121 +
  1.1122 +    NS_ADDREF(result);
  1.1123 +    *aResult = result;
  1.1124 +
  1.1125 +    return NS_OK;
  1.1126 +}
  1.1127 +
  1.1128 +
  1.1129 +nsresult
  1.1130 +InMemoryDataSource::LockedAssert(nsIRDFResource* aSource,
  1.1131 +                                 nsIRDFResource* aProperty,
  1.1132 +                                 nsIRDFNode* aTarget,
  1.1133 +                                 bool aTruthValue)
  1.1134 +{
  1.1135 +#ifdef PR_LOGGING
  1.1136 +    LogOperation("ASSERT", aSource, aProperty, aTarget, aTruthValue);
  1.1137 +#endif
  1.1138 +
  1.1139 +    Assertion* next = GetForwardArcs(aSource);
  1.1140 +    Assertion* prev = next;
  1.1141 +    Assertion* as = nullptr;
  1.1142 +
  1.1143 +    bool    haveHash = (next) ? next->mHashEntry : false;
  1.1144 +    if (haveHash) {
  1.1145 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash, aProperty, PL_DHASH_LOOKUP);
  1.1146 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1147 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1148 +            : nullptr;
  1.1149 +        while (val) {
  1.1150 +            if (val->u.as.mTarget == aTarget) {
  1.1151 +                // Wow, we already had the assertion. Make sure that the
  1.1152 +                // truth values are correct and bail.
  1.1153 +                val->u.as.mTruthValue = aTruthValue;
  1.1154 +                return NS_OK;
  1.1155 +            }
  1.1156 +            val = val->mNext;
  1.1157 +        }
  1.1158 +    }
  1.1159 +    else
  1.1160 +    {
  1.1161 +        while (next) {
  1.1162 +            // check target first as its most unique
  1.1163 +            if (aTarget == next->u.as.mTarget) {
  1.1164 +                if (aProperty == next->u.as.mProperty) {
  1.1165 +                    // Wow, we already had the assertion. Make sure that the
  1.1166 +                    // truth values are correct and bail.
  1.1167 +                    next->u.as.mTruthValue = aTruthValue;
  1.1168 +                    return NS_OK;
  1.1169 +                }
  1.1170 +            }
  1.1171 +
  1.1172 +            prev = next;
  1.1173 +            next = next->mNext;
  1.1174 +        }
  1.1175 +    }
  1.1176 +
  1.1177 +    as = new Assertion(aSource, aProperty, aTarget, aTruthValue);
  1.1178 +    if (! as)
  1.1179 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1180 +
  1.1181 +    // Add the datasource's owning reference.
  1.1182 +    as->AddRef();
  1.1183 +
  1.1184 +    if (haveHash)
  1.1185 +    {
  1.1186 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1.1187 +            aProperty, PL_DHASH_LOOKUP);
  1.1188 +        Assertion *asRef = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1189 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1190 +            : nullptr;
  1.1191 +        if (asRef)
  1.1192 +        {
  1.1193 +            as->mNext = asRef->mNext;
  1.1194 +            asRef->mNext = as;
  1.1195 +        }
  1.1196 +        else
  1.1197 +        {
  1.1198 +            hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1.1199 +                                            aProperty, PL_DHASH_ADD);
  1.1200 +            if (hdr)
  1.1201 +            {
  1.1202 +                Entry* entry = reinterpret_cast<Entry*>(hdr);
  1.1203 +                entry->mNode = aProperty;
  1.1204 +                entry->mAssertions = as;
  1.1205 +            }
  1.1206 +        }
  1.1207 +    }
  1.1208 +    else
  1.1209 +    {
  1.1210 +        // Link it in to the "forward arcs" table
  1.1211 +        if (!prev) {
  1.1212 +            SetForwardArcs(aSource, as);
  1.1213 +        } else {
  1.1214 +            prev->mNext = as;
  1.1215 +        }
  1.1216 +    }
  1.1217 +
  1.1218 +    // Link it in to the "reverse arcs" table
  1.1219 +
  1.1220 +    next = GetReverseArcs(aTarget);
  1.1221 +    as->u.as.mInvNext = next;
  1.1222 +    next = as;
  1.1223 +    SetReverseArcs(aTarget, next);
  1.1224 +
  1.1225 +    return NS_OK;
  1.1226 +}
  1.1227 +
  1.1228 +NS_IMETHODIMP
  1.1229 +InMemoryDataSource::Assert(nsIRDFResource* aSource,
  1.1230 +                           nsIRDFResource* aProperty, 
  1.1231 +                           nsIRDFNode* aTarget,
  1.1232 +                           bool aTruthValue) 
  1.1233 +{
  1.1234 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1235 +    if (! aSource)
  1.1236 +        return NS_ERROR_NULL_POINTER;
  1.1237 +
  1.1238 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1239 +    if (! aProperty)
  1.1240 +        return NS_ERROR_NULL_POINTER;
  1.1241 +
  1.1242 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1243 +    if (! aTarget)
  1.1244 +        return NS_ERROR_NULL_POINTER;
  1.1245 +
  1.1246 +    if (mReadCount) {
  1.1247 +        NS_WARNING("Writing to InMemoryDataSource during read\n");
  1.1248 +        return NS_RDF_ASSERTION_REJECTED;
  1.1249 +    }
  1.1250 +
  1.1251 +    nsresult rv;
  1.1252 +    rv = LockedAssert(aSource, aProperty, aTarget, aTruthValue);
  1.1253 +    if (NS_FAILED(rv)) return rv;
  1.1254 +
  1.1255 +    // notify observers
  1.1256 +    for (int32_t i = (int32_t)mNumObservers - 1; mPropagateChanges && i >= 0; --i) {
  1.1257 +        nsIRDFObserver* obs = mObservers[i];
  1.1258 +
  1.1259 +        // XXX this should never happen, but it does, and we can't figure out why.
  1.1260 +        NS_ASSERTION(obs, "observer array corrupted!");
  1.1261 +        if (! obs)
  1.1262 +          continue;
  1.1263 +
  1.1264 +        obs->OnAssert(this, aSource, aProperty, aTarget);
  1.1265 +        // XXX ignore return value?
  1.1266 +    }
  1.1267 +
  1.1268 +    return NS_RDF_ASSERTION_ACCEPTED;
  1.1269 +}
  1.1270 +
  1.1271 +
  1.1272 +nsresult
  1.1273 +InMemoryDataSource::LockedUnassert(nsIRDFResource* aSource,
  1.1274 +                                   nsIRDFResource* aProperty,
  1.1275 +                                   nsIRDFNode* aTarget)
  1.1276 +{
  1.1277 +#ifdef PR_LOGGING
  1.1278 +    LogOperation("UNASSERT", aSource, aProperty, aTarget);
  1.1279 +#endif
  1.1280 +
  1.1281 +    Assertion* next = GetForwardArcs(aSource);
  1.1282 +    Assertion* prev = next;
  1.1283 +    Assertion* root = next;
  1.1284 +    Assertion* as = nullptr;
  1.1285 +    
  1.1286 +    bool    haveHash = (next) ? next->mHashEntry : false;
  1.1287 +    if (haveHash) {
  1.1288 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(next->u.hash.mPropertyHash,
  1.1289 +            aProperty, PL_DHASH_LOOKUP);
  1.1290 +        prev = next = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1291 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1292 +            : nullptr;
  1.1293 +        bool first = true;
  1.1294 +        while (next) {
  1.1295 +            if (aTarget == next->u.as.mTarget) {
  1.1296 +                break;
  1.1297 +            }
  1.1298 +            first = false;
  1.1299 +            prev = next;
  1.1300 +            next = next->mNext;
  1.1301 +        }
  1.1302 +        // We don't even have the assertion, so just bail.
  1.1303 +        if (!next)
  1.1304 +            return NS_OK;
  1.1305 +
  1.1306 +        as = next;
  1.1307 +
  1.1308 +        if (first) {
  1.1309 +            PL_DHashTableRawRemove(root->u.hash.mPropertyHash, hdr);
  1.1310 +
  1.1311 +            if (next && next->mNext) {
  1.1312 +                PLDHashEntryHdr* hdr = PL_DHashTableOperate(root->u.hash.mPropertyHash,
  1.1313 +                                     aProperty, PL_DHASH_ADD);
  1.1314 +                if (hdr) {
  1.1315 +                    Entry* entry = reinterpret_cast<Entry*>(hdr);
  1.1316 +                    entry->mNode = aProperty;
  1.1317 +                    entry->mAssertions = next->mNext;
  1.1318 +                }
  1.1319 +            }
  1.1320 +            else {
  1.1321 +                // If this second-level hash empties out, clean it up.
  1.1322 +                if (!root->u.hash.mPropertyHash->entryCount) {
  1.1323 +                    delete root;
  1.1324 +                    SetForwardArcs(aSource, nullptr);
  1.1325 +                }
  1.1326 +            }
  1.1327 +        }
  1.1328 +        else {
  1.1329 +            prev->mNext = next->mNext;
  1.1330 +        }
  1.1331 +    }
  1.1332 +    else
  1.1333 +    {
  1.1334 +        while (next) {
  1.1335 +            // check target first as its most unique
  1.1336 +            if (aTarget == next->u.as.mTarget) {
  1.1337 +                if (aProperty == next->u.as.mProperty) {
  1.1338 +                    if (prev == next) {
  1.1339 +                        SetForwardArcs(aSource, next->mNext);
  1.1340 +                    } else {
  1.1341 +                        prev->mNext = next->mNext;
  1.1342 +                    }
  1.1343 +                    as = next;
  1.1344 +                    break;
  1.1345 +                }
  1.1346 +            }
  1.1347 +
  1.1348 +            prev = next;
  1.1349 +            next = next->mNext;
  1.1350 +        }
  1.1351 +    }
  1.1352 +    // We don't even have the assertion, so just bail.
  1.1353 +    if (!as)
  1.1354 +        return NS_OK;
  1.1355 +
  1.1356 +#ifdef DEBUG
  1.1357 +    bool foundReverseArc = false;
  1.1358 +#endif
  1.1359 +
  1.1360 +    next = prev = GetReverseArcs(aTarget);
  1.1361 +    while (next) {
  1.1362 +        if (next == as) {
  1.1363 +            if (prev == next) {
  1.1364 +                SetReverseArcs(aTarget, next->u.as.mInvNext);
  1.1365 +            } else {
  1.1366 +                prev->u.as.mInvNext = next->u.as.mInvNext;
  1.1367 +            }
  1.1368 +#ifdef DEBUG
  1.1369 +            foundReverseArc = true;
  1.1370 +#endif
  1.1371 +            break;
  1.1372 +        }
  1.1373 +        prev = next;
  1.1374 +        next = next->u.as.mInvNext;
  1.1375 +    }
  1.1376 +
  1.1377 +#ifdef DEBUG
  1.1378 +    NS_ASSERTION(foundReverseArc, "in-memory db corrupted: unable to find reverse arc");
  1.1379 +#endif
  1.1380 +
  1.1381 +    // Unlink, and release the datasource's reference
  1.1382 +    as->mNext = as->u.as.mInvNext = nullptr;
  1.1383 +    as->Release();
  1.1384 +
  1.1385 +    return NS_OK;
  1.1386 +}
  1.1387 +
  1.1388 +NS_IMETHODIMP
  1.1389 +InMemoryDataSource::Unassert(nsIRDFResource* aSource,
  1.1390 +                             nsIRDFResource* aProperty,
  1.1391 +                             nsIRDFNode* aTarget)
  1.1392 +{
  1.1393 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1394 +    if (! aSource)
  1.1395 +        return NS_ERROR_NULL_POINTER;
  1.1396 +
  1.1397 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1398 +    if (! aProperty)
  1.1399 +        return NS_ERROR_NULL_POINTER;
  1.1400 +
  1.1401 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1402 +    if (! aTarget)
  1.1403 +        return NS_ERROR_NULL_POINTER;
  1.1404 +
  1.1405 +    if (mReadCount) {
  1.1406 +        NS_WARNING("Writing to InMemoryDataSource during read\n");
  1.1407 +        return NS_RDF_ASSERTION_REJECTED;
  1.1408 +    }
  1.1409 +
  1.1410 +    nsresult rv;
  1.1411 +
  1.1412 +    rv = LockedUnassert(aSource, aProperty, aTarget);
  1.1413 +    if (NS_FAILED(rv)) return rv;
  1.1414 +
  1.1415 +    // Notify the world
  1.1416 +    for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1417 +        nsIRDFObserver* obs = mObservers[i];
  1.1418 +
  1.1419 +        // XXX this should never happen, but it does, and we can't figure out why.
  1.1420 +        NS_ASSERTION(obs, "observer array corrupted!");
  1.1421 +        if (! obs)
  1.1422 +          continue;
  1.1423 +
  1.1424 +        obs->OnUnassert(this, aSource, aProperty, aTarget);
  1.1425 +        // XXX ignore return value?
  1.1426 +    }
  1.1427 +
  1.1428 +    return NS_RDF_ASSERTION_ACCEPTED;
  1.1429 +}
  1.1430 +
  1.1431 +
  1.1432 +NS_IMETHODIMP
  1.1433 +InMemoryDataSource::Change(nsIRDFResource* aSource,
  1.1434 +                           nsIRDFResource* aProperty,
  1.1435 +                           nsIRDFNode* aOldTarget,
  1.1436 +                           nsIRDFNode* aNewTarget)
  1.1437 +{
  1.1438 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1439 +    if (! aSource)
  1.1440 +        return NS_ERROR_NULL_POINTER;
  1.1441 +
  1.1442 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1443 +    if (! aProperty)
  1.1444 +        return NS_ERROR_NULL_POINTER;
  1.1445 +
  1.1446 +    NS_PRECONDITION(aOldTarget != nullptr, "null ptr");
  1.1447 +    if (! aOldTarget)
  1.1448 +        return NS_ERROR_NULL_POINTER;
  1.1449 +
  1.1450 +    NS_PRECONDITION(aNewTarget != nullptr, "null ptr");
  1.1451 +    if (! aNewTarget)
  1.1452 +        return NS_ERROR_NULL_POINTER;
  1.1453 +
  1.1454 +    if (mReadCount) {
  1.1455 +        NS_WARNING("Writing to InMemoryDataSource during read\n");
  1.1456 +        return NS_RDF_ASSERTION_REJECTED;
  1.1457 +    }
  1.1458 +
  1.1459 +    nsresult rv;
  1.1460 +
  1.1461 +    // XXX We can implement LockedChange() if we decide that this
  1.1462 +    // is a performance bottleneck.
  1.1463 +
  1.1464 +    rv = LockedUnassert(aSource, aProperty, aOldTarget);
  1.1465 +    if (NS_FAILED(rv)) return rv;
  1.1466 +
  1.1467 +    rv = LockedAssert(aSource, aProperty, aNewTarget, true);
  1.1468 +    if (NS_FAILED(rv)) return rv;
  1.1469 +
  1.1470 +    // Notify the world
  1.1471 +    for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1472 +        nsIRDFObserver* obs = mObservers[i];
  1.1473 +
  1.1474 +        // XXX this should never happen, but it does, and we can't figure out why.
  1.1475 +        NS_ASSERTION(obs, "observer array corrupted!");
  1.1476 +        if (! obs)
  1.1477 +          continue;
  1.1478 +
  1.1479 +        obs->OnChange(this, aSource, aProperty, aOldTarget, aNewTarget);
  1.1480 +        // XXX ignore return value?
  1.1481 +    }
  1.1482 +
  1.1483 +    return NS_RDF_ASSERTION_ACCEPTED;
  1.1484 +}
  1.1485 +
  1.1486 +
  1.1487 +NS_IMETHODIMP
  1.1488 +InMemoryDataSource::Move(nsIRDFResource* aOldSource,
  1.1489 +                         nsIRDFResource* aNewSource,
  1.1490 +                         nsIRDFResource* aProperty,
  1.1491 +                         nsIRDFNode* aTarget)
  1.1492 +{
  1.1493 +    NS_PRECONDITION(aOldSource != nullptr, "null ptr");
  1.1494 +    if (! aOldSource)
  1.1495 +        return NS_ERROR_NULL_POINTER;
  1.1496 +
  1.1497 +    NS_PRECONDITION(aNewSource != nullptr, "null ptr");
  1.1498 +    if (! aNewSource)
  1.1499 +        return NS_ERROR_NULL_POINTER;
  1.1500 +
  1.1501 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1502 +    if (! aProperty)
  1.1503 +        return NS_ERROR_NULL_POINTER;
  1.1504 +
  1.1505 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1506 +    if (! aTarget)
  1.1507 +        return NS_ERROR_NULL_POINTER;
  1.1508 +
  1.1509 +    if (mReadCount) {
  1.1510 +        NS_WARNING("Writing to InMemoryDataSource during read\n");
  1.1511 +        return NS_RDF_ASSERTION_REJECTED;
  1.1512 +    }
  1.1513 +
  1.1514 +    nsresult rv;
  1.1515 +
  1.1516 +    // XXX We can implement LockedMove() if we decide that this
  1.1517 +    // is a performance bottleneck.
  1.1518 +
  1.1519 +    rv = LockedUnassert(aOldSource, aProperty, aTarget);
  1.1520 +    if (NS_FAILED(rv)) return rv;
  1.1521 +
  1.1522 +    rv = LockedAssert(aNewSource, aProperty, aTarget, true);
  1.1523 +    if (NS_FAILED(rv)) return rv;
  1.1524 +
  1.1525 +    // Notify the world
  1.1526 +    for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1527 +        nsIRDFObserver* obs = mObservers[i];
  1.1528 +
  1.1529 +        // XXX this should never happen, but it does, and we can't figure out why.
  1.1530 +        NS_ASSERTION(obs, "observer array corrupted!");
  1.1531 +        if (! obs)
  1.1532 +          continue;
  1.1533 +
  1.1534 +        obs->OnMove(this, aOldSource, aNewSource, aProperty, aTarget);
  1.1535 +        // XXX ignore return value?
  1.1536 +    }
  1.1537 +
  1.1538 +    return NS_RDF_ASSERTION_ACCEPTED;
  1.1539 +}
  1.1540 +
  1.1541 +
  1.1542 +NS_IMETHODIMP
  1.1543 +InMemoryDataSource::AddObserver(nsIRDFObserver* aObserver)
  1.1544 +{
  1.1545 +    NS_PRECONDITION(aObserver != nullptr, "null ptr");
  1.1546 +    if (! aObserver)
  1.1547 +        return NS_ERROR_NULL_POINTER;
  1.1548 +
  1.1549 +    mObservers.AppendObject(aObserver);
  1.1550 +    mNumObservers = mObservers.Count();
  1.1551 +
  1.1552 +    return NS_OK;
  1.1553 +}
  1.1554 +
  1.1555 +NS_IMETHODIMP
  1.1556 +InMemoryDataSource::RemoveObserver(nsIRDFObserver* aObserver)
  1.1557 +{
  1.1558 +    NS_PRECONDITION(aObserver != nullptr, "null ptr");
  1.1559 +    if (! aObserver)
  1.1560 +        return NS_ERROR_NULL_POINTER;
  1.1561 +
  1.1562 +    mObservers.RemoveObject(aObserver);
  1.1563 +    // note: use Count() instead of just decrementing
  1.1564 +    // in case aObserver wasn't in list, for example
  1.1565 +    mNumObservers = mObservers.Count();
  1.1566 +
  1.1567 +    return NS_OK;
  1.1568 +}
  1.1569 +
  1.1570 +NS_IMETHODIMP 
  1.1571 +InMemoryDataSource::HasArcIn(nsIRDFNode *aNode, nsIRDFResource *aArc, bool *result)
  1.1572 +{
  1.1573 +    Assertion* ass = GetReverseArcs(aNode);
  1.1574 +    while (ass) {
  1.1575 +        nsIRDFResource* elbow = ass->u.as.mProperty;
  1.1576 +        if (elbow == aArc) {
  1.1577 +            *result = true;
  1.1578 +            return NS_OK;
  1.1579 +        }
  1.1580 +        ass = ass->u.as.mInvNext;
  1.1581 +    }
  1.1582 +    *result = false;
  1.1583 +    return NS_OK;
  1.1584 +}
  1.1585 +
  1.1586 +NS_IMETHODIMP 
  1.1587 +InMemoryDataSource::HasArcOut(nsIRDFResource *aSource, nsIRDFResource *aArc, bool *result)
  1.1588 +{
  1.1589 +    Assertion* ass = GetForwardArcs(aSource);
  1.1590 +    if (ass && ass->mHashEntry) {
  1.1591 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(ass->u.hash.mPropertyHash,
  1.1592 +            aArc, PL_DHASH_LOOKUP);
  1.1593 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1594 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1595 +            : nullptr;
  1.1596 +        if (val) {
  1.1597 +            *result = true;
  1.1598 +            return NS_OK;
  1.1599 +        }
  1.1600 +        ass = ass->mNext;
  1.1601 +    }
  1.1602 +    while (ass) {
  1.1603 +        nsIRDFResource* elbow = ass->u.as.mProperty;
  1.1604 +        if (elbow == aArc) {
  1.1605 +            *result = true;
  1.1606 +            return NS_OK;
  1.1607 +        }
  1.1608 +        ass = ass->mNext;
  1.1609 +    }
  1.1610 +    *result = false;
  1.1611 +    return NS_OK;
  1.1612 +}
  1.1613 +
  1.1614 +NS_IMETHODIMP
  1.1615 +InMemoryDataSource::ArcLabelsIn(nsIRDFNode* aTarget, nsISimpleEnumerator** aResult)
  1.1616 +{
  1.1617 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1618 +    if (! aTarget)
  1.1619 +        return NS_ERROR_NULL_POINTER;
  1.1620 +
  1.1621 +    InMemoryArcsEnumeratorImpl* result =
  1.1622 +        new InMemoryArcsEnumeratorImpl(this, nullptr, aTarget);
  1.1623 +
  1.1624 +    if (! result)
  1.1625 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1626 +
  1.1627 +    NS_ADDREF(result);
  1.1628 +    *aResult = result;
  1.1629 +
  1.1630 +    return NS_OK;
  1.1631 +}
  1.1632 +
  1.1633 +NS_IMETHODIMP
  1.1634 +InMemoryDataSource::ArcLabelsOut(nsIRDFResource* aSource, nsISimpleEnumerator** aResult)
  1.1635 +{
  1.1636 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1637 +    if (! aSource)
  1.1638 +        return NS_ERROR_NULL_POINTER;
  1.1639 +
  1.1640 +    InMemoryArcsEnumeratorImpl* result =
  1.1641 +        new InMemoryArcsEnumeratorImpl(this, aSource, nullptr);
  1.1642 +
  1.1643 +    if (! result)
  1.1644 +        return NS_ERROR_OUT_OF_MEMORY;
  1.1645 +
  1.1646 +    NS_ADDREF(result);
  1.1647 +    *aResult = result;
  1.1648 +
  1.1649 +    return NS_OK;
  1.1650 +}
  1.1651 +
  1.1652 +PLDHashOperator
  1.1653 +InMemoryDataSource::ResourceEnumerator(PLDHashTable* aTable,
  1.1654 +                                       PLDHashEntryHdr* aHdr,
  1.1655 +                                       uint32_t aNumber, void* aArg)
  1.1656 +{
  1.1657 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1.1658 +    static_cast<nsCOMArray<nsIRDFNode>*>(aArg)->AppendObject(entry->mNode);
  1.1659 +    return PL_DHASH_NEXT;
  1.1660 +}
  1.1661 +
  1.1662 +
  1.1663 +NS_IMETHODIMP
  1.1664 +InMemoryDataSource::GetAllResources(nsISimpleEnumerator** aResult)
  1.1665 +{
  1.1666 +    nsCOMArray<nsIRDFNode> nodes;
  1.1667 +    nodes.SetCapacity(mForwardArcs.entryCount);
  1.1668 +
  1.1669 +    // Enumerate all of our entries into an nsCOMArray
  1.1670 +    PL_DHashTableEnumerate(&mForwardArcs, ResourceEnumerator, &nodes);
  1.1671 +
  1.1672 +    return NS_NewArrayEnumerator(aResult, nodes);
  1.1673 +}
  1.1674 +
  1.1675 +NS_IMETHODIMP
  1.1676 +InMemoryDataSource::GetAllCmds(nsIRDFResource* source,
  1.1677 +                               nsISimpleEnumerator/*<nsIRDFResource>*/** commands)
  1.1678 +{
  1.1679 +    return(NS_NewEmptyEnumerator(commands));
  1.1680 +}
  1.1681 +
  1.1682 +NS_IMETHODIMP
  1.1683 +InMemoryDataSource::IsCommandEnabled(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1.1684 +                                     nsIRDFResource*   aCommand,
  1.1685 +                                     nsISupportsArray/*<nsIRDFResource>*/* aArguments,
  1.1686 +                                     bool* aResult)
  1.1687 +{
  1.1688 +    *aResult = false;
  1.1689 +    return NS_OK;
  1.1690 +}
  1.1691 +
  1.1692 +NS_IMETHODIMP
  1.1693 +InMemoryDataSource::DoCommand(nsISupportsArray/*<nsIRDFResource>*/* aSources,
  1.1694 +                              nsIRDFResource*   aCommand,
  1.1695 +                              nsISupportsArray/*<nsIRDFResource>*/* aArguments)
  1.1696 +{
  1.1697 +    return NS_OK;
  1.1698 +}
  1.1699 +
  1.1700 +NS_IMETHODIMP
  1.1701 +InMemoryDataSource::BeginUpdateBatch()
  1.1702 +{
  1.1703 +    for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1704 +        nsIRDFObserver* obs = mObservers[i];
  1.1705 +        obs->OnBeginUpdateBatch(this);
  1.1706 +    }
  1.1707 +    return NS_OK;
  1.1708 +}
  1.1709 +
  1.1710 +NS_IMETHODIMP
  1.1711 +InMemoryDataSource::EndUpdateBatch()
  1.1712 +{
  1.1713 +    for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1714 +        nsIRDFObserver* obs = mObservers[i];
  1.1715 +        obs->OnEndUpdateBatch(this);
  1.1716 +    }
  1.1717 +    return NS_OK;
  1.1718 +}
  1.1719 +
  1.1720 +
  1.1721 +
  1.1722 +////////////////////////////////////////////////////////////////////////
  1.1723 +// nsIRDFInMemoryDataSource methods
  1.1724 +
  1.1725 +NS_IMETHODIMP
  1.1726 +InMemoryDataSource::EnsureFastContainment(nsIRDFResource* aSource)
  1.1727 +{
  1.1728 +    Assertion *as = GetForwardArcs(aSource);
  1.1729 +    bool    haveHash = (as) ? as->mHashEntry : false;
  1.1730 +
  1.1731 +    // if its already a hash, then nothing to do
  1.1732 +    if (haveHash)   return(NS_OK);
  1.1733 +
  1.1734 +    // convert aSource in forward hash into a hash
  1.1735 +    Assertion *hashAssertion = new Assertion(aSource);
  1.1736 +    NS_ASSERTION(hashAssertion, "unable to create Assertion");
  1.1737 +    if (!hashAssertion) return(NS_ERROR_OUT_OF_MEMORY);
  1.1738 +
  1.1739 +    // Add the datasource's owning reference.
  1.1740 +    hashAssertion->AddRef();
  1.1741 +
  1.1742 +    Assertion *first = GetForwardArcs(aSource);
  1.1743 +    SetForwardArcs(aSource, hashAssertion);
  1.1744 +
  1.1745 +    // mutate references of existing forward assertions into this hash
  1.1746 +    PLDHashTable *table = hashAssertion->u.hash.mPropertyHash;
  1.1747 +    Assertion *nextRef;
  1.1748 +    while(first) {
  1.1749 +        nextRef = first->mNext;
  1.1750 +        nsIRDFResource *prop = first->u.as.mProperty;
  1.1751 +
  1.1752 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
  1.1753 +            prop, PL_DHASH_LOOKUP);
  1.1754 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1755 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1756 +            : nullptr;
  1.1757 +        if (val) {
  1.1758 +            first->mNext = val->mNext;
  1.1759 +            val->mNext = first;
  1.1760 +        }
  1.1761 +        else {
  1.1762 +            PLDHashEntryHdr* hdr = PL_DHashTableOperate(table,
  1.1763 +                                            prop, PL_DHASH_ADD);
  1.1764 +            if (hdr) {
  1.1765 +                Entry* entry = reinterpret_cast<Entry*>(hdr);
  1.1766 +                entry->mNode = prop;
  1.1767 +                entry->mAssertions = first;
  1.1768 +                first->mNext = nullptr;
  1.1769 +            }
  1.1770 +        }
  1.1771 +        first = nextRef;
  1.1772 +    }
  1.1773 +    return(NS_OK);
  1.1774 +}
  1.1775 +
  1.1776 +
  1.1777 +////////////////////////////////////////////////////////////////////////
  1.1778 +// nsIRDFPropagatableDataSource methods
  1.1779 +NS_IMETHODIMP
  1.1780 +InMemoryDataSource::GetPropagateChanges(bool* aPropagateChanges)
  1.1781 +{
  1.1782 +    *aPropagateChanges = mPropagateChanges;
  1.1783 +    return NS_OK;
  1.1784 +}
  1.1785 +
  1.1786 +NS_IMETHODIMP
  1.1787 +InMemoryDataSource::SetPropagateChanges(bool aPropagateChanges)
  1.1788 +{
  1.1789 +    mPropagateChanges = aPropagateChanges;
  1.1790 +    return NS_OK;
  1.1791 +}
  1.1792 +
  1.1793 +
  1.1794 +////////////////////////////////////////////////////////////////////////
  1.1795 +// nsIRDFPurgeableDataSource methods
  1.1796 +
  1.1797 +NS_IMETHODIMP
  1.1798 +InMemoryDataSource::Mark(nsIRDFResource* aSource,
  1.1799 +                         nsIRDFResource* aProperty,
  1.1800 +                         nsIRDFNode* aTarget,
  1.1801 +                         bool aTruthValue,
  1.1802 +                         bool* aDidMark)
  1.1803 +{
  1.1804 +    NS_PRECONDITION(aSource != nullptr, "null ptr");
  1.1805 +    if (! aSource)
  1.1806 +        return NS_ERROR_NULL_POINTER;
  1.1807 +
  1.1808 +    NS_PRECONDITION(aProperty != nullptr, "null ptr");
  1.1809 +    if (! aProperty)
  1.1810 +        return NS_ERROR_NULL_POINTER;
  1.1811 +
  1.1812 +    NS_PRECONDITION(aTarget != nullptr, "null ptr");
  1.1813 +    if (! aTarget)
  1.1814 +        return NS_ERROR_NULL_POINTER;
  1.1815 +
  1.1816 +    Assertion *as = GetForwardArcs(aSource);
  1.1817 +    if (as && as->mHashEntry) {
  1.1818 +        PLDHashEntryHdr* hdr = PL_DHashTableOperate(as->u.hash.mPropertyHash,
  1.1819 +            aProperty, PL_DHASH_LOOKUP);
  1.1820 +        Assertion* val = PL_DHASH_ENTRY_IS_BUSY(hdr)
  1.1821 +            ? reinterpret_cast<Entry*>(hdr)->mAssertions
  1.1822 +            : nullptr;
  1.1823 +        while (val) {
  1.1824 +            if ((val->u.as.mTarget == aTarget) &&
  1.1825 +                (aTruthValue == (val->u.as.mTruthValue))) {
  1.1826 +
  1.1827 +                // found it! so mark it.
  1.1828 +                as->Mark();
  1.1829 +                *aDidMark = true;
  1.1830 +
  1.1831 +#ifdef PR_LOGGING
  1.1832 +                LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
  1.1833 +#endif
  1.1834 +
  1.1835 +                return NS_OK;
  1.1836 +            }
  1.1837 +            val = val->mNext;
  1.1838 +        }
  1.1839 +    }
  1.1840 +    else for (; as != nullptr; as = as->mNext) {
  1.1841 +        // check target first as its most unique
  1.1842 +        if (aTarget != as->u.as.mTarget)
  1.1843 +            continue;
  1.1844 +
  1.1845 +        if (aProperty != as->u.as.mProperty)
  1.1846 +            continue;
  1.1847 +
  1.1848 +        if (aTruthValue != (as->u.as.mTruthValue))
  1.1849 +            continue;
  1.1850 +
  1.1851 +        // found it! so mark it.
  1.1852 +        as->Mark();
  1.1853 +        *aDidMark = true;
  1.1854 +
  1.1855 +#ifdef PR_LOGGING
  1.1856 +        LogOperation("MARK", aSource, aProperty, aTarget, aTruthValue);
  1.1857 +#endif
  1.1858 +
  1.1859 +        return NS_OK;
  1.1860 +    }
  1.1861 +
  1.1862 +    // If we get here, we couldn't find the assertion
  1.1863 +    *aDidMark = false;
  1.1864 +    return NS_OK;
  1.1865 +}
  1.1866 +
  1.1867 +
  1.1868 +struct SweepInfo {
  1.1869 +    Assertion* mUnassertList;
  1.1870 +    PLDHashTable* mReverseArcs;
  1.1871 +};
  1.1872 +
  1.1873 +NS_IMETHODIMP
  1.1874 +InMemoryDataSource::Sweep()
  1.1875 +{
  1.1876 +    SweepInfo info = { nullptr, &mReverseArcs };
  1.1877 +
  1.1878 +    // Remove all the assertions, but don't notify anyone.
  1.1879 +    PL_DHashTableEnumerate(&mForwardArcs, SweepForwardArcsEntries, &info);
  1.1880 +
  1.1881 +    // Now do the notification.
  1.1882 +    Assertion* as = info.mUnassertList;
  1.1883 +    while (as) {
  1.1884 +#ifdef PR_LOGGING
  1.1885 +        LogOperation("SWEEP", as->mSource, as->u.as.mProperty, as->u.as.mTarget, as->u.as.mTruthValue);
  1.1886 +#endif
  1.1887 +        if (!(as->mHashEntry))
  1.1888 +        {
  1.1889 +            for (int32_t i = int32_t(mNumObservers) - 1; mPropagateChanges && i >= 0; --i) {
  1.1890 +                nsIRDFObserver* obs = mObservers[i];
  1.1891 +                // XXXbz other loops over mObservers null-check |obs| here!
  1.1892 +                obs->OnUnassert(this, as->mSource, as->u.as.mProperty, as->u.as.mTarget);
  1.1893 +                // XXX ignore return value?
  1.1894 +            }
  1.1895 +        }
  1.1896 +
  1.1897 +        Assertion* doomed = as;
  1.1898 +        as = as->mNext;
  1.1899 +
  1.1900 +        // Unlink, and release the datasource's reference
  1.1901 +        doomed->mNext = doomed->u.as.mInvNext = nullptr;
  1.1902 +        doomed->Release();
  1.1903 +    }
  1.1904 +
  1.1905 +    return NS_OK;
  1.1906 +}
  1.1907 +
  1.1908 +
  1.1909 +PLDHashOperator
  1.1910 +InMemoryDataSource::SweepForwardArcsEntries(PLDHashTable* aTable,
  1.1911 +                                            PLDHashEntryHdr* aHdr,
  1.1912 +                                            uint32_t aNumber, void* aArg)
  1.1913 +{
  1.1914 +    PLDHashOperator result = PL_DHASH_NEXT;
  1.1915 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1.1916 +    SweepInfo* info = static_cast<SweepInfo*>(aArg);
  1.1917 +
  1.1918 +    Assertion* as = entry->mAssertions;
  1.1919 +    if (as && (as->mHashEntry))
  1.1920 +    {
  1.1921 +        // Stuff in sub-hashes must be swept recursively (max depth: 1)
  1.1922 +        PL_DHashTableEnumerate(as->u.hash.mPropertyHash,
  1.1923 +                               SweepForwardArcsEntries, info);
  1.1924 +
  1.1925 +        // If the sub-hash is now empty, clean it up.
  1.1926 +        if (!as->u.hash.mPropertyHash->entryCount) {
  1.1927 +            delete as;
  1.1928 +            result = PL_DHASH_REMOVE;
  1.1929 +        }
  1.1930 +
  1.1931 +        return result;
  1.1932 +    }
  1.1933 +
  1.1934 +    Assertion* prev = nullptr;
  1.1935 +    while (as) {
  1.1936 +        if (as->IsMarked()) {
  1.1937 +            prev = as;
  1.1938 +            as->Unmark();
  1.1939 +            as = as->mNext;
  1.1940 +        }
  1.1941 +        else {
  1.1942 +            // remove from the list of assertions in the datasource
  1.1943 +            Assertion* next = as->mNext;
  1.1944 +            if (prev) {
  1.1945 +                prev->mNext = next;
  1.1946 +            }
  1.1947 +            else {
  1.1948 +                // it's the first one. update the hashtable entry.
  1.1949 +                entry->mAssertions = next;
  1.1950 +            }
  1.1951 +
  1.1952 +            // remove from the reverse arcs
  1.1953 +            PLDHashEntryHdr* hdr =
  1.1954 +                PL_DHashTableOperate(info->mReverseArcs, as->u.as.mTarget, PL_DHASH_LOOKUP);
  1.1955 +            NS_ASSERTION(PL_DHASH_ENTRY_IS_BUSY(hdr), "no assertion in reverse arcs");
  1.1956 +
  1.1957 +            Entry* rentry = reinterpret_cast<Entry*>(hdr);
  1.1958 +            Assertion* ras = rentry->mAssertions;
  1.1959 +            Assertion* rprev = nullptr;
  1.1960 +            while (ras) {
  1.1961 +                if (ras == as) {
  1.1962 +                    if (rprev) {
  1.1963 +                        rprev->u.as.mInvNext = ras->u.as.mInvNext;
  1.1964 +                    }
  1.1965 +                    else {
  1.1966 +                        // it's the first one. update the hashtable entry.
  1.1967 +                        rentry->mAssertions = ras->u.as.mInvNext;
  1.1968 +                    }
  1.1969 +                    as->u.as.mInvNext = nullptr; // for my sanity.
  1.1970 +                    break;
  1.1971 +                }
  1.1972 +                rprev = ras;
  1.1973 +                ras = ras->u.as.mInvNext;
  1.1974 +            }
  1.1975 +
  1.1976 +            // Wow, it was the _only_ one. Unhash it.
  1.1977 +            if (! rentry->mAssertions)
  1.1978 +            {
  1.1979 +                PL_DHashTableRawRemove(info->mReverseArcs, hdr);
  1.1980 +            }
  1.1981 +
  1.1982 +            // add to the list of assertions to unassert
  1.1983 +            as->mNext = info->mUnassertList;
  1.1984 +            info->mUnassertList = as;
  1.1985 +
  1.1986 +            // Advance to the next assertion
  1.1987 +            as = next;
  1.1988 +        }
  1.1989 +    }
  1.1990 +
  1.1991 +    // if no more assertions exist for this resource, then unhash it.
  1.1992 +    if (! entry->mAssertions)
  1.1993 +        result = PL_DHASH_REMOVE;
  1.1994 +
  1.1995 +    return result;
  1.1996 +}
  1.1997 +
  1.1998 +////////////////////////////////////////////////////////////////////////
  1.1999 +// rdfIDataSource methods
  1.2000 +
  1.2001 +class VisitorClosure
  1.2002 +{
  1.2003 +public:
  1.2004 +    VisitorClosure(rdfITripleVisitor* aVisitor) :
  1.2005 +        mVisitor(aVisitor),
  1.2006 +        mRv(NS_OK)
  1.2007 +    {}
  1.2008 +    rdfITripleVisitor* mVisitor;
  1.2009 +    nsresult mRv;
  1.2010 +};
  1.2011 +
  1.2012 +PLDHashOperator
  1.2013 +SubjectEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  1.2014 +                  uint32_t aNumber, void* aArg) {
  1.2015 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1.2016 +    VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
  1.2017 +
  1.2018 +    nsresult rv;
  1.2019 +    nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
  1.2020 +    NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
  1.2021 +
  1.2022 +    closure->mRv = closure->mVisitor->Visit(subject, nullptr, nullptr, true);
  1.2023 +    if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT)
  1.2024 +        return PL_DHASH_STOP;
  1.2025 +
  1.2026 +    return PL_DHASH_NEXT;
  1.2027 +}
  1.2028 +
  1.2029 +NS_IMETHODIMP
  1.2030 +InMemoryDataSource::VisitAllSubjects(rdfITripleVisitor *aVisitor)
  1.2031 +{
  1.2032 +    // Lock datasource against writes
  1.2033 +    ++mReadCount;
  1.2034 +
  1.2035 +    // Enumerate all of our entries into an nsISupportsArray.
  1.2036 +    VisitorClosure cls(aVisitor);
  1.2037 +    PL_DHashTableEnumerate(&mForwardArcs, SubjectEnumerator, &cls);
  1.2038 +
  1.2039 +    // Unlock datasource
  1.2040 +    --mReadCount;
  1.2041 +
  1.2042 +    return cls.mRv;
  1.2043 +} 
  1.2044 +
  1.2045 +class TriplesInnerClosure
  1.2046 +{
  1.2047 +public:
  1.2048 +    TriplesInnerClosure(nsIRDFNode* aSubject, VisitorClosure* aClosure) :
  1.2049 +        mSubject(aSubject), mOuter(aClosure) {}
  1.2050 +    nsIRDFNode* mSubject;
  1.2051 +    VisitorClosure* mOuter;
  1.2052 +};
  1.2053 +
  1.2054 +PLDHashOperator
  1.2055 +TriplesInnerEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  1.2056 +                  uint32_t aNumber, void* aArg) {
  1.2057 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1.2058 +    Assertion* assertion = entry->mAssertions;
  1.2059 +    TriplesInnerClosure* closure = 
  1.2060 +        static_cast<TriplesInnerClosure*>(aArg);
  1.2061 +    while (assertion) {
  1.2062 +        NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
  1.2063 +        VisitorClosure* cls = closure->mOuter;
  1.2064 +        cls->mRv = cls->mVisitor->Visit(closure->mSubject,
  1.2065 +                                        assertion->u.as.mProperty,
  1.2066 +                                        assertion->u.as.mTarget,
  1.2067 +                                        assertion->u.as.mTruthValue);
  1.2068 +        if (NS_FAILED(cls->mRv) || cls->mRv == NS_RDF_STOP_VISIT) {
  1.2069 +            return PL_DHASH_STOP;
  1.2070 +        }
  1.2071 +        assertion = assertion->mNext;
  1.2072 +    }
  1.2073 +    return PL_DHASH_NEXT;
  1.2074 +}
  1.2075 +PLDHashOperator
  1.2076 +TriplesEnumerator(PLDHashTable* aTable, PLDHashEntryHdr* aHdr,
  1.2077 +                  uint32_t aNumber, void* aArg) {
  1.2078 +    Entry* entry = reinterpret_cast<Entry*>(aHdr);
  1.2079 +    VisitorClosure* closure = static_cast<VisitorClosure*>(aArg);
  1.2080 +
  1.2081 +    nsresult rv;
  1.2082 +    nsCOMPtr<nsIRDFNode> subject = do_QueryInterface(entry->mNode, &rv);
  1.2083 +    NS_ENSURE_SUCCESS(rv, PL_DHASH_NEXT);
  1.2084 +
  1.2085 +    if (entry->mAssertions->mHashEntry) {
  1.2086 +        TriplesInnerClosure cls(subject, closure);
  1.2087 +        PL_DHashTableEnumerate(entry->mAssertions->u.hash.mPropertyHash,
  1.2088 +                               TriplesInnerEnumerator, &cls);
  1.2089 +        if (NS_FAILED(closure->mRv)) {
  1.2090 +            return PL_DHASH_STOP;
  1.2091 +        }
  1.2092 +        return PL_DHASH_NEXT;
  1.2093 +    }
  1.2094 +    Assertion* assertion = entry->mAssertions;
  1.2095 +    while (assertion) {
  1.2096 +        NS_ASSERTION(!assertion->mHashEntry, "shouldn't have to hashes");
  1.2097 +        closure->mRv = closure->mVisitor->Visit(subject,
  1.2098 +                                                assertion->u.as.mProperty,
  1.2099 +                                                assertion->u.as.mTarget,
  1.2100 +                                                assertion->u.as.mTruthValue);
  1.2101 +        if (NS_FAILED(closure->mRv) || closure->mRv == NS_RDF_STOP_VISIT) {
  1.2102 +            return PL_DHASH_STOP;
  1.2103 +        }
  1.2104 +        assertion = assertion->mNext;
  1.2105 +    }
  1.2106 +    return PL_DHASH_NEXT;
  1.2107 +}
  1.2108 +NS_IMETHODIMP
  1.2109 +InMemoryDataSource::VisitAllTriples(rdfITripleVisitor *aVisitor)
  1.2110 +{
  1.2111 +    // Lock datasource against writes
  1.2112 +    ++mReadCount;
  1.2113 +
  1.2114 +    // Enumerate all of our entries into an nsISupportsArray.
  1.2115 +    VisitorClosure cls(aVisitor);
  1.2116 +    PL_DHashTableEnumerate(&mForwardArcs, TriplesEnumerator, &cls);
  1.2117 +
  1.2118 +    // Unlock datasource
  1.2119 +    --mReadCount;
  1.2120 +
  1.2121 +    return cls.mRv;
  1.2122 +} 
  1.2123 +
  1.2124 +////////////////////////////////////////////////////////////////////////
  1.2125 +

mercurial