Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / content / xul / templates / src / nsRDFBinding.cpp
blob6b9689a8b0845235d8d938f11ced94197d6765d8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is Neil Deakin
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either of the GNU General Public License Version 2 or later (the "GPL"),
25 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #include "nsXULTemplateQueryProcessorRDF.h"
38 #include "nsXULTemplateResultRDF.h"
39 #include "nsRDFBinding.h"
41 #ifdef DEBUG
42 #include "nsXULContentUtils.h"
43 #endif
45 RDFBindingSet::~RDFBindingSet()
47 while (mFirst) {
48 RDFBinding* doomed = mFirst;
49 mFirst = mFirst->mNext;
50 delete doomed;
53 MOZ_COUNT_DTOR(RDFBindingSet);
56 nsresult
57 RDFBindingSet::AddBinding(nsIAtom* aVar, nsIAtom* aRef, nsIRDFResource* aPredicate)
59 RDFBinding* newbinding = new RDFBinding(aRef, aPredicate, aVar);
60 if (! newbinding)
61 return NS_ERROR_OUT_OF_MEMORY;
63 if (mFirst) {
64 RDFBinding* binding = mFirst;
66 while (binding) {
67 // the binding is dependant on the calculation of a previous binding
68 if (binding->mSubjectVariable == aVar)
69 newbinding->mHasDependency = PR_TRUE;
71 // if the target variable is already used in a binding, ignore it
72 // since it won't be useful for anything
73 if (binding->mTargetVariable == aVar) {
74 delete newbinding;
75 return NS_OK;
78 // add the binding at the end of the list
79 if (! binding->mNext) {
80 binding->mNext = newbinding;
81 break;
84 binding = binding->mNext;
87 else {
88 mFirst = newbinding;
91 mCount++;
93 return NS_OK;
96 PRBool
97 RDFBindingSet::SyncAssignments(nsIRDFResource* aSubject,
98 nsIRDFResource* aPredicate,
99 nsIRDFNode* aTarget,
100 nsIAtom* aMemberVariable,
101 nsXULTemplateResultRDF* aResult,
102 nsBindingValues& aBindingValues)
104 NS_ASSERTION(aBindingValues.GetBindingSet() == this,
105 "nsBindingValues not for this RDFBindingSet");
106 NS_PRECONDITION(aResult, "Must have result");
108 PRBool needSync = PR_FALSE;
109 nsCOMPtr<nsIRDFNode>* valuesArray = aBindingValues.ValuesArray();
110 if (!valuesArray)
111 return PR_FALSE;
113 RDFBinding* binding = mFirst;
114 PRInt32 count = 0;
116 // QI for proper comparisons just to be safe
117 nsCOMPtr<nsIRDFNode> subjectnode = do_QueryInterface(aSubject);
119 // iterate through the bindings looking for ones that would match the RDF
120 // nodes that were involved in a change
121 nsCOMPtr<nsIRDFNode> value;
122 while (binding) {
123 if (aPredicate == binding->mPredicate) {
124 // if the source of the binding is the member variable, optimize
125 if (binding->mSubjectVariable == aMemberVariable) {
126 valuesArray[count] = aTarget;
127 needSync = PR_TRUE;
129 else {
130 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
131 if (value == subjectnode) {
132 valuesArray[count] = aTarget;
133 needSync = PR_TRUE;
138 binding = binding->mNext;
139 count++;
142 return needSync;
145 void
146 RDFBindingSet::AddDependencies(nsIRDFResource* aSubject,
147 nsXULTemplateResultRDF* aResult)
149 NS_PRECONDITION(aResult, "Must have result");
151 // iterate through the bindings and add binding dependencies to the
152 // processor
154 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
155 if (! processor)
156 return;
158 nsCOMPtr<nsIRDFNode> value;
160 RDFBinding* binding = mFirst;
161 while (binding) {
162 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
164 nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
165 if (valueres)
166 processor->AddBindingDependency(aResult, valueres);
168 binding = binding->mNext;
172 void
173 RDFBindingSet::RemoveDependencies(nsIRDFResource* aSubject,
174 nsXULTemplateResultRDF* aResult)
176 NS_PRECONDITION(aResult, "Must have result");
178 // iterate through the bindings and remove binding dependencies from the
179 // processor
181 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
182 if (! processor)
183 return;
185 nsCOMPtr<nsIRDFNode> value;
187 RDFBinding* binding = mFirst;
188 while (binding) {
189 aResult->GetAssignment(binding->mSubjectVariable, getter_AddRefs(value));
191 nsCOMPtr<nsIRDFResource> valueres = do_QueryInterface(value);
192 if (valueres)
193 processor->RemoveBindingDependency(aResult, valueres);
195 binding = binding->mNext;
199 PRInt32
200 RDFBindingSet::LookupTargetIndex(nsIAtom* aTargetVariable, RDFBinding** aBinding)
202 PRInt32 idx = 0;
203 RDFBinding* binding = mFirst;
205 while (binding) {
206 if (binding->mTargetVariable == aTargetVariable) {
207 *aBinding = binding;
208 return idx;
210 idx++;
211 binding = binding->mNext;
214 return -1;
217 nsBindingValues::~nsBindingValues()
219 ClearBindingSet();
220 MOZ_COUNT_DTOR(nsBindingValues);
223 void
224 nsBindingValues::ClearBindingSet()
226 if (mBindings && mValues) {
227 delete [] mValues;
228 mValues = nsnull;
231 mBindings = nsnull;
234 nsresult
235 nsBindingValues::SetBindingSet(RDFBindingSet* aBindings)
237 ClearBindingSet();
239 PRInt32 count = aBindings->Count();
240 if (count) {
241 mValues = new nsCOMPtr<nsIRDFNode>[count];
242 if (!mValues)
243 return NS_ERROR_OUT_OF_MEMORY;
245 mBindings = aBindings;
247 else {
248 mValues = nsnull;
251 return NS_OK;
254 void
255 nsBindingValues::GetAssignmentFor(nsXULTemplateResultRDF* aResult,
256 nsIAtom* aVar,
257 nsIRDFNode** aValue)
259 *aValue = nsnull;
261 // assignments are calculated lazily when asked for. The only issue is
262 // when a binding has no value in the RDF graph, it will be checked again
263 // every time.
265 if (mBindings && mValues) {
266 RDFBinding* binding;
267 PRInt32 idx = mBindings->LookupTargetIndex(aVar, &binding);
268 if (idx >= 0) {
269 *aValue = mValues[idx];
270 if (*aValue) {
271 NS_ADDREF(*aValue);
273 else {
274 nsXULTemplateQueryProcessorRDF* processor = aResult->GetProcessor();
275 if (! processor)
276 return;
278 nsIRDFDataSource* ds = processor->GetDataSource();
279 if (! ds)
280 return;
282 nsCOMPtr<nsIRDFNode> subjectValue;
283 aResult->GetAssignment(binding->mSubjectVariable,
284 getter_AddRefs(subjectValue));
286 NS_ASSERTION(subjectValue, "Value of subject is not set");
288 if (subjectValue) {
289 nsCOMPtr<nsIRDFResource> subject = do_QueryInterface(subjectValue);
291 ds->GetTarget(subject, binding->mPredicate, PR_TRUE, aValue);
292 if (*aValue)
293 mValues[idx] = *aValue;
300 void
301 nsBindingValues::RemoveDependencies(nsIRDFResource* aSubject,
302 nsXULTemplateResultRDF* aResult)
304 if (mBindings)
305 mBindings->RemoveDependencies(aSubject, aResult);