1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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/. */
5
6 #include "txResultRecycler.h"
7 #include "txExprResult.h"
8 #include "txNodeSet.h"
9
txResultRecycler()10 txResultRecycler::txResultRecycler()
11 : mEmptyStringResult(new StringResult(nullptr)),
12 mTrueResult(new BooleanResult(true)),
13 mFalseResult(new BooleanResult(false)) {}
14
~txResultRecycler()15 txResultRecycler::~txResultRecycler() {
16 txStackIterator stringIter(&mStringResults);
17 while (stringIter.hasNext()) {
18 delete static_cast<StringResult*>(stringIter.next());
19 }
20 txStackIterator nodesetIter(&mNodeSetResults);
21 while (nodesetIter.hasNext()) {
22 delete static_cast<txNodeSet*>(nodesetIter.next());
23 }
24 txStackIterator numberIter(&mNumberResults);
25 while (numberIter.hasNext()) {
26 delete static_cast<NumberResult*>(numberIter.next());
27 }
28 }
29
recycle(txAExprResult * aResult)30 void txResultRecycler::recycle(txAExprResult* aResult) {
31 NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled");
32 RefPtr<txResultRecycler> kungFuDeathGrip;
33 aResult->mRecycler.swap(kungFuDeathGrip);
34
35 nsresult rv = NS_OK;
36 switch (aResult->getResultType()) {
37 case txAExprResult::STRING: {
38 rv = mStringResults.push(static_cast<StringResult*>(aResult));
39 if (NS_FAILED(rv)) {
40 delete aResult;
41 }
42 return;
43 }
44 case txAExprResult::NODESET: {
45 static_cast<txNodeSet*>(aResult)->clear();
46 rv = mNodeSetResults.push(static_cast<txNodeSet*>(aResult));
47 if (NS_FAILED(rv)) {
48 delete aResult;
49 }
50 return;
51 }
52 case txAExprResult::NUMBER: {
53 rv = mNumberResults.push(static_cast<NumberResult*>(aResult));
54 if (NS_FAILED(rv)) {
55 delete aResult;
56 }
57 return;
58 }
59 default: {
60 delete aResult;
61 }
62 }
63 }
64
getStringResult(StringResult ** aResult)65 nsresult txResultRecycler::getStringResult(StringResult** aResult) {
66 if (mStringResults.isEmpty()) {
67 *aResult = new StringResult(this);
68 } else {
69 *aResult = static_cast<StringResult*>(mStringResults.pop());
70 (*aResult)->mValue.Truncate();
71 (*aResult)->mRecycler = this;
72 }
73 NS_ADDREF(*aResult);
74
75 return NS_OK;
76 }
77
getStringResult(const nsAString & aValue,txAExprResult ** aResult)78 nsresult txResultRecycler::getStringResult(const nsAString& aValue,
79 txAExprResult** aResult) {
80 if (mStringResults.isEmpty()) {
81 *aResult = new StringResult(aValue, this);
82 } else {
83 StringResult* strRes = static_cast<StringResult*>(mStringResults.pop());
84 strRes->mValue = aValue;
85 strRes->mRecycler = this;
86 *aResult = strRes;
87 }
88 NS_ADDREF(*aResult);
89
90 return NS_OK;
91 }
92
getEmptyStringResult(txAExprResult ** aResult)93 void txResultRecycler::getEmptyStringResult(txAExprResult** aResult) {
94 *aResult = mEmptyStringResult;
95 NS_ADDREF(*aResult);
96 }
97
getNodeSet(txNodeSet ** aResult)98 nsresult txResultRecycler::getNodeSet(txNodeSet** aResult) {
99 if (mNodeSetResults.isEmpty()) {
100 *aResult = new txNodeSet(this);
101 } else {
102 *aResult = static_cast<txNodeSet*>(mNodeSetResults.pop());
103 (*aResult)->mRecycler = this;
104 }
105 NS_ADDREF(*aResult);
106
107 return NS_OK;
108 }
109
getNodeSet(txNodeSet * aNodeSet,txNodeSet ** aResult)110 nsresult txResultRecycler::getNodeSet(txNodeSet* aNodeSet,
111 txNodeSet** aResult) {
112 if (mNodeSetResults.isEmpty()) {
113 *aResult = new txNodeSet(*aNodeSet, this);
114 } else {
115 *aResult = static_cast<txNodeSet*>(mNodeSetResults.pop());
116 (*aResult)->append(*aNodeSet);
117 (*aResult)->mRecycler = this;
118 }
119 NS_ADDREF(*aResult);
120
121 return NS_OK;
122 }
123
getNodeSet(const txXPathNode & aNode,txAExprResult ** aResult)124 nsresult txResultRecycler::getNodeSet(const txXPathNode& aNode,
125 txAExprResult** aResult) {
126 if (mNodeSetResults.isEmpty()) {
127 *aResult = new txNodeSet(aNode, this);
128 } else {
129 txNodeSet* nodes = static_cast<txNodeSet*>(mNodeSetResults.pop());
130 nodes->append(aNode);
131 nodes->mRecycler = this;
132 *aResult = nodes;
133 }
134 NS_ADDREF(*aResult);
135
136 return NS_OK;
137 }
138
getNumberResult(double aValue,txAExprResult ** aResult)139 nsresult txResultRecycler::getNumberResult(double aValue,
140 txAExprResult** aResult) {
141 if (mNumberResults.isEmpty()) {
142 *aResult = new NumberResult(aValue, this);
143 } else {
144 NumberResult* numRes = static_cast<NumberResult*>(mNumberResults.pop());
145 numRes->value = aValue;
146 numRes->mRecycler = this;
147 *aResult = numRes;
148 }
149 NS_ADDREF(*aResult);
150
151 return NS_OK;
152 }
153
getBoolResult(bool aValue,txAExprResult ** aResult)154 void txResultRecycler::getBoolResult(bool aValue, txAExprResult** aResult) {
155 *aResult = aValue ? mTrueResult : mFalseResult;
156 NS_ADDREF(*aResult);
157 }
158
getNonSharedNodeSet(txNodeSet * aNodeSet,txNodeSet ** aResult)159 nsresult txResultRecycler::getNonSharedNodeSet(txNodeSet* aNodeSet,
160 txNodeSet** aResult) {
161 if (aNodeSet->mRefCnt > 1) {
162 return getNodeSet(aNodeSet, aResult);
163 }
164
165 *aResult = aNodeSet;
166 NS_ADDREF(*aResult);
167
168 return NS_OK;
169 }
170
Release()171 void txAExprResult::Release() {
172 --mRefCnt;
173 NS_LOG_RELEASE(this, mRefCnt, "txAExprResult");
174 if (mRefCnt == 0) {
175 if (mRecycler) {
176 mRecycler->recycle(this);
177 } else {
178 delete this;
179 }
180 }
181 }
182