Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "txResultRecycler.h"
7 #include "txExprResult.h"
8 #include "txNodeSet.h"
10 txResultRecycler::txResultRecycler()
11 : mEmptyStringResult(nullptr),
12 mTrueResult(nullptr),
13 mFalseResult(nullptr)
14 {
15 }
17 txResultRecycler::~txResultRecycler()
18 {
19 txStackIterator stringIter(&mStringResults);
20 while (stringIter.hasNext()) {
21 delete static_cast<StringResult*>(stringIter.next());
22 }
23 txStackIterator nodesetIter(&mNodeSetResults);
24 while (nodesetIter.hasNext()) {
25 delete static_cast<txNodeSet*>(nodesetIter.next());
26 }
27 txStackIterator numberIter(&mNumberResults);
28 while (numberIter.hasNext()) {
29 delete static_cast<NumberResult*>(numberIter.next());
30 }
32 NS_IF_RELEASE(mEmptyStringResult);
33 NS_IF_RELEASE(mTrueResult);
34 NS_IF_RELEASE(mFalseResult);
35 }
38 nsresult
39 txResultRecycler::init()
40 {
41 NS_ASSERTION(!mEmptyStringResult && !mTrueResult && !mFalseResult,
42 "Already inited");
43 mEmptyStringResult = new StringResult(nullptr);
44 NS_ENSURE_TRUE(mEmptyStringResult, NS_ERROR_OUT_OF_MEMORY);
46 NS_ADDREF(mEmptyStringResult);
48 mTrueResult = new BooleanResult(true);
49 NS_ENSURE_TRUE(mTrueResult, NS_ERROR_OUT_OF_MEMORY);
51 NS_ADDREF(mTrueResult);
53 mFalseResult = new BooleanResult(false);
54 NS_ENSURE_TRUE(mFalseResult, NS_ERROR_OUT_OF_MEMORY);
56 NS_ADDREF(mFalseResult);
58 return NS_OK;
59 }
62 void
63 txResultRecycler::recycle(txAExprResult* aResult)
64 {
65 NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled");
66 nsRefPtr<txResultRecycler> kungFuDeathGrip;
67 aResult->mRecycler.swap(kungFuDeathGrip);
69 nsresult rv = NS_OK;
70 switch (aResult->getResultType()) {
71 case txAExprResult::STRING:
72 {
73 rv = mStringResults.push(static_cast<StringResult*>(aResult));
74 if (NS_FAILED(rv)) {
75 delete aResult;
76 }
77 return;
78 }
79 case txAExprResult::NODESET:
80 {
81 static_cast<txNodeSet*>(aResult)->clear();
82 rv = mNodeSetResults.push(static_cast<txNodeSet*>(aResult));
83 if (NS_FAILED(rv)) {
84 delete aResult;
85 }
86 return;
87 }
88 case txAExprResult::NUMBER:
89 {
90 rv = mNumberResults.push(static_cast<NumberResult*>(aResult));
91 if (NS_FAILED(rv)) {
92 delete aResult;
93 }
94 return;
95 }
96 default:
97 {
98 delete aResult;
99 }
100 }
101 }
103 nsresult
104 txResultRecycler::getStringResult(StringResult** aResult)
105 {
106 if (mStringResults.isEmpty()) {
107 *aResult = new StringResult(this);
108 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
109 }
110 else {
111 *aResult = static_cast<StringResult*>(mStringResults.pop());
112 (*aResult)->mValue.Truncate();
113 (*aResult)->mRecycler = this;
114 }
115 NS_ADDREF(*aResult);
117 return NS_OK;
118 }
120 nsresult
121 txResultRecycler::getStringResult(const nsAString& aValue,
122 txAExprResult** aResult)
123 {
124 if (mStringResults.isEmpty()) {
125 *aResult = new StringResult(aValue, this);
126 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
127 }
128 else {
129 StringResult* strRes =
130 static_cast<StringResult*>(mStringResults.pop());
131 strRes->mValue = aValue;
132 strRes->mRecycler = this;
133 *aResult = strRes;
134 }
135 NS_ADDREF(*aResult);
137 return NS_OK;
138 }
140 void
141 txResultRecycler::getEmptyStringResult(txAExprResult** aResult)
142 {
143 *aResult = mEmptyStringResult;
144 NS_ADDREF(*aResult);
145 }
147 nsresult
148 txResultRecycler::getNodeSet(txNodeSet** aResult)
149 {
150 if (mNodeSetResults.isEmpty()) {
151 *aResult = new txNodeSet(this);
152 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
153 }
154 else {
155 *aResult = static_cast<txNodeSet*>(mNodeSetResults.pop());
156 (*aResult)->mRecycler = this;
157 }
158 NS_ADDREF(*aResult);
160 return NS_OK;
161 }
163 nsresult
164 txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
165 {
166 if (mNodeSetResults.isEmpty()) {
167 *aResult = new txNodeSet(*aNodeSet, this);
168 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
169 }
170 else {
171 *aResult = static_cast<txNodeSet*>(mNodeSetResults.pop());
172 (*aResult)->append(*aNodeSet);
173 (*aResult)->mRecycler = this;
174 }
175 NS_ADDREF(*aResult);
177 return NS_OK;
178 }
180 nsresult
181 txResultRecycler::getNodeSet(const txXPathNode& aNode, txAExprResult** aResult)
182 {
183 if (mNodeSetResults.isEmpty()) {
184 *aResult = new txNodeSet(aNode, this);
185 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
186 }
187 else {
188 txNodeSet* nodes = static_cast<txNodeSet*>(mNodeSetResults.pop());
189 nodes->append(aNode);
190 nodes->mRecycler = this;
191 *aResult = nodes;
192 }
193 NS_ADDREF(*aResult);
195 return NS_OK;
196 }
198 nsresult
199 txResultRecycler::getNumberResult(double aValue, txAExprResult** aResult)
200 {
201 if (mNumberResults.isEmpty()) {
202 *aResult = new NumberResult(aValue, this);
203 NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY);
204 }
205 else {
206 NumberResult* numRes =
207 static_cast<NumberResult*>(mNumberResults.pop());
208 numRes->value = aValue;
209 numRes->mRecycler = this;
210 *aResult = numRes;
211 }
212 NS_ADDREF(*aResult);
214 return NS_OK;
215 }
217 void
218 txResultRecycler::getBoolResult(bool aValue, txAExprResult** aResult)
219 {
220 *aResult = aValue ? mTrueResult : mFalseResult;
221 NS_ADDREF(*aResult);
222 }
224 nsresult
225 txResultRecycler::getNonSharedNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult)
226 {
227 if (aNodeSet->mRefCnt > 1) {
228 return getNodeSet(aNodeSet, aResult);
229 }
231 *aResult = aNodeSet;
232 NS_ADDREF(*aResult);
234 return NS_OK;
235 }
237 void
238 txAExprResult::Release()
239 {
240 --mRefCnt;
241 NS_LOG_RELEASE(this, mRefCnt, "txAExprResult");
242 if (mRefCnt == 0) {
243 if (mRecycler) {
244 mRecycler->recycle(this);
245 }
246 else {
247 delete this;
248 }
249 }
250 }