1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/rdf/base/src/nsContainerEnumerator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,262 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + 1.11 + A simple cursor that enumerates the elements of an RDF container 1.12 + (RDF:Bag, RDF:Seq, or RDF:Alt). 1.13 + 1.14 + Caveats 1.15 + ------- 1.16 + 1.17 + 1. This uses an implementation-specific detail to determine the 1.18 + index of the last element in the container; specifically, the RDF 1.19 + utilities maintain a counter attribute on the container that 1.20 + holds the numeric value of the next value that is to be 1.21 + assigned. So, this cursor will bust if you use it with a bag that 1.22 + hasn't been created using the RDF utility routines. 1.23 + 1.24 + */ 1.25 + 1.26 +#include "nscore.h" 1.27 +#include "nsCOMPtr.h" 1.28 +#include "nsIRDFContainerUtils.h" 1.29 +#include "nsIRDFDataSource.h" 1.30 +#include "nsIRDFNode.h" 1.31 +#include "nsIRDFService.h" 1.32 +#include "nsIServiceManager.h" 1.33 +#include "nsRDFCID.h" 1.34 +#include "nsString.h" 1.35 +#include "nsXPIDLString.h" 1.36 +#include "prlog.h" 1.37 +#include "rdf.h" 1.38 +#include "rdfutil.h" 1.39 + 1.40 +//////////////////////////////////////////////////////////////////////// 1.41 + 1.42 +class ContainerEnumeratorImpl : public nsISimpleEnumerator { 1.43 +private: 1.44 + // pseudo-constants 1.45 + static nsrefcnt gRefCnt; 1.46 + static nsIRDFResource* kRDF_nextVal; 1.47 + static nsIRDFContainerUtils* gRDFC; 1.48 + 1.49 + nsCOMPtr<nsIRDFDataSource> mDataSource; 1.50 + nsCOMPtr<nsIRDFResource> mContainer; 1.51 + nsCOMPtr<nsIRDFResource> mOrdinalProperty; 1.52 + 1.53 + nsCOMPtr<nsISimpleEnumerator> mCurrent; 1.54 + nsCOMPtr<nsIRDFNode> mResult; 1.55 + int32_t mNextIndex; 1.56 + 1.57 +public: 1.58 + ContainerEnumeratorImpl(nsIRDFDataSource* ds, nsIRDFResource* container); 1.59 + virtual ~ContainerEnumeratorImpl(); 1.60 + 1.61 + nsresult Init(); 1.62 + 1.63 + NS_DECL_ISUPPORTS 1.64 + NS_DECL_NSISIMPLEENUMERATOR 1.65 +}; 1.66 + 1.67 +nsrefcnt ContainerEnumeratorImpl::gRefCnt; 1.68 +nsIRDFResource* ContainerEnumeratorImpl::kRDF_nextVal; 1.69 +nsIRDFContainerUtils* ContainerEnumeratorImpl::gRDFC; 1.70 + 1.71 + 1.72 +ContainerEnumeratorImpl::ContainerEnumeratorImpl(nsIRDFDataSource* aDataSource, 1.73 + nsIRDFResource* aContainer) 1.74 + : mDataSource(aDataSource), 1.75 + mContainer(aContainer), 1.76 + mNextIndex(1) 1.77 +{ 1.78 +} 1.79 + 1.80 +nsresult 1.81 +ContainerEnumeratorImpl::Init() 1.82 +{ 1.83 + if (gRefCnt++ == 0) { 1.84 + nsresult rv; 1.85 + 1.86 + NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID); 1.87 + nsCOMPtr<nsIRDFService> rdf = do_GetService(kRDFServiceCID); 1.88 + NS_ASSERTION(rdf != nullptr, "unable to acquire resource manager"); 1.89 + if (! rdf) 1.90 + return NS_ERROR_FAILURE; 1.91 + 1.92 + rv = rdf->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"), &kRDF_nextVal); 1.93 + NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get resource"); 1.94 + if (NS_FAILED(rv)) return rv; 1.95 + 1.96 + NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID); 1.97 + rv = CallGetService(kRDFContainerUtilsCID, &gRDFC); 1.98 + if (NS_FAILED(rv)) return rv; 1.99 + } 1.100 + 1.101 + return NS_OK; 1.102 +} 1.103 + 1.104 + 1.105 +ContainerEnumeratorImpl::~ContainerEnumeratorImpl() 1.106 +{ 1.107 + if (--gRefCnt == 0) { 1.108 + NS_IF_RELEASE(kRDF_nextVal); 1.109 + NS_IF_RELEASE(gRDFC); 1.110 + } 1.111 +} 1.112 + 1.113 +NS_IMPL_ISUPPORTS(ContainerEnumeratorImpl, nsISimpleEnumerator) 1.114 + 1.115 + 1.116 +NS_IMETHODIMP 1.117 +ContainerEnumeratorImpl::HasMoreElements(bool* aResult) 1.118 +{ 1.119 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.120 + if (! aResult) 1.121 + return NS_ERROR_NULL_POINTER; 1.122 + 1.123 + nsresult rv; 1.124 + 1.125 + // If we've already queued up a next value, then we know there are more elements. 1.126 + if (mResult) { 1.127 + *aResult = true; 1.128 + return NS_OK; 1.129 + } 1.130 + 1.131 + // Otherwise, we need to grovel 1.132 + 1.133 + // Figure out the upper bound so we'll know when we're done. Since it's 1.134 + // possible that we're targeting a composite datasource, we'll need to 1.135 + // "GetTargets()" and take the maximum value of "nextVal" to know the 1.136 + // upper bound. 1.137 + // 1.138 + // Remember that since nextVal is the next index that we'd assign 1.139 + // to an element in a container, it's *one more* than count of 1.140 + // elements in the container. 1.141 + int32_t max = 0; 1.142 + 1.143 + nsCOMPtr<nsISimpleEnumerator> targets; 1.144 + rv = mDataSource->GetTargets(mContainer, kRDF_nextVal, true, getter_AddRefs(targets)); 1.145 + if (NS_FAILED(rv)) return rv; 1.146 + 1.147 + while (1) { 1.148 + bool hasmore; 1.149 + targets->HasMoreElements(&hasmore); 1.150 + if (! hasmore) 1.151 + break; 1.152 + 1.153 + nsCOMPtr<nsISupports> isupports; 1.154 + targets->GetNext(getter_AddRefs(isupports)); 1.155 + 1.156 + nsCOMPtr<nsIRDFLiteral> nextValLiteral = do_QueryInterface(isupports); 1.157 + if (! nextValLiteral) 1.158 + continue; 1.159 + 1.160 + const char16_t *nextValStr; 1.161 + nextValLiteral->GetValueConst(&nextValStr); 1.162 + 1.163 + nsresult err; 1.164 + int32_t nextVal = nsAutoString(nextValStr).ToInteger(&err); 1.165 + 1.166 + if (nextVal > max) 1.167 + max = nextVal; 1.168 + } 1.169 + 1.170 + // Now pre-fetch our next value into mResult. 1.171 + while (mCurrent || mNextIndex < max) { 1.172 + 1.173 + // If mCurrent has been depleted, then conjure up a new one 1.174 + if (! mCurrent) { 1.175 + rv = gRDFC->IndexToOrdinalResource(mNextIndex, getter_AddRefs(mOrdinalProperty)); 1.176 + if (NS_FAILED(rv)) return rv; 1.177 + 1.178 + rv = mDataSource->GetTargets(mContainer, mOrdinalProperty, true, getter_AddRefs(mCurrent)); 1.179 + if (NS_FAILED(rv)) return rv; 1.180 + 1.181 + ++mNextIndex; 1.182 + } 1.183 + 1.184 + if (mCurrent) { 1.185 + bool hasMore; 1.186 + rv = mCurrent->HasMoreElements(&hasMore); 1.187 + if (NS_FAILED(rv)) return rv; 1.188 + 1.189 + // Is the current enumerator depleted? If so, iterate to 1.190 + // the next index. 1.191 + if (! hasMore) { 1.192 + mCurrent = nullptr; 1.193 + continue; 1.194 + } 1.195 + 1.196 + // "Peek" ahead and pull out the next target. 1.197 + nsCOMPtr<nsISupports> result; 1.198 + rv = mCurrent->GetNext(getter_AddRefs(result)); 1.199 + if (NS_FAILED(rv)) return rv; 1.200 + 1.201 + mResult = do_QueryInterface(result, &rv); 1.202 + if (NS_FAILED(rv)) return rv; 1.203 + 1.204 + *aResult = true; 1.205 + return NS_OK; 1.206 + } 1.207 + } 1.208 + 1.209 + // If we get here, we ran out of elements. The cursor is empty. 1.210 + *aResult = false; 1.211 + return NS_OK; 1.212 +} 1.213 + 1.214 + 1.215 +NS_IMETHODIMP 1.216 +ContainerEnumeratorImpl::GetNext(nsISupports** aResult) 1.217 +{ 1.218 + nsresult rv; 1.219 + 1.220 + bool hasMore; 1.221 + rv = HasMoreElements(&hasMore); 1.222 + if (NS_FAILED(rv)) return rv; 1.223 + 1.224 + if (! hasMore) 1.225 + return NS_ERROR_UNEXPECTED; 1.226 + 1.227 + NS_ADDREF(*aResult = mResult); 1.228 + mResult = nullptr; 1.229 + 1.230 + return NS_OK; 1.231 +} 1.232 + 1.233 + 1.234 +//////////////////////////////////////////////////////////////////////// 1.235 + 1.236 +nsresult 1.237 +NS_NewContainerEnumerator(nsIRDFDataSource* aDataSource, 1.238 + nsIRDFResource* aContainer, 1.239 + nsISimpleEnumerator** aResult) 1.240 +{ 1.241 + NS_PRECONDITION(aDataSource != nullptr, "null ptr"); 1.242 + if (! aDataSource) 1.243 + return NS_ERROR_NULL_POINTER; 1.244 + 1.245 + NS_PRECONDITION(aContainer != nullptr, "null ptr"); 1.246 + if (! aContainer) 1.247 + return NS_ERROR_NULL_POINTER; 1.248 + 1.249 + NS_PRECONDITION(aResult != nullptr, "null ptr"); 1.250 + if (! aResult) 1.251 + return NS_ERROR_NULL_POINTER; 1.252 + 1.253 + ContainerEnumeratorImpl* result = new ContainerEnumeratorImpl(aDataSource, aContainer); 1.254 + if (! result) 1.255 + return NS_ERROR_OUT_OF_MEMORY; 1.256 + 1.257 + NS_ADDREF(result); 1.258 + 1.259 + nsresult rv = result->Init(); 1.260 + if (NS_FAILED(rv)) 1.261 + NS_RELEASE(result); 1.262 + 1.263 + *aResult = result; 1.264 + return rv; 1.265 +}