/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "txResultRecycler.h" #include "txExprResult.h" #include "txNodeSet.h" txResultRecycler::txResultRecycler() : mEmptyStringResult(new StringResult(nullptr)), mTrueResult(new BooleanResult(true)), mFalseResult(new BooleanResult(false)) {} txResultRecycler::~txResultRecycler() { txStackIterator stringIter(&mStringResults); while (stringIter.hasNext()) { delete static_cast(stringIter.next()); } txStackIterator nodesetIter(&mNodeSetResults); while (nodesetIter.hasNext()) { delete static_cast(nodesetIter.next()); } txStackIterator numberIter(&mNumberResults); while (numberIter.hasNext()) { delete static_cast(numberIter.next()); } } void txResultRecycler::recycle(txAExprResult* aResult) { NS_ASSERTION(aResult->mRefCnt == 0, "In-use txAExprResult recycled"); RefPtr kungFuDeathGrip; aResult->mRecycler.swap(kungFuDeathGrip); nsresult rv = NS_OK; switch (aResult->getResultType()) { case txAExprResult::STRING: { rv = mStringResults.push(static_cast(aResult)); if (NS_FAILED(rv)) { delete aResult; } return; } case txAExprResult::NODESET: { static_cast(aResult)->clear(); rv = mNodeSetResults.push(static_cast(aResult)); if (NS_FAILED(rv)) { delete aResult; } return; } case txAExprResult::NUMBER: { rv = mNumberResults.push(static_cast(aResult)); if (NS_FAILED(rv)) { delete aResult; } return; } default: { delete aResult; } } } nsresult txResultRecycler::getStringResult(StringResult** aResult) { if (mStringResults.isEmpty()) { *aResult = new StringResult(this); } else { *aResult = static_cast(mStringResults.pop()); (*aResult)->mValue.Truncate(); (*aResult)->mRecycler = this; } NS_ADDREF(*aResult); return NS_OK; } nsresult txResultRecycler::getStringResult(const nsAString& aValue, txAExprResult** aResult) { if (mStringResults.isEmpty()) { *aResult = new StringResult(aValue, this); } else { StringResult* strRes = static_cast(mStringResults.pop()); strRes->mValue = aValue; strRes->mRecycler = this; *aResult = strRes; } NS_ADDREF(*aResult); return NS_OK; } void txResultRecycler::getEmptyStringResult(txAExprResult** aResult) { *aResult = mEmptyStringResult; NS_ADDREF(*aResult); } nsresult txResultRecycler::getNodeSet(txNodeSet** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(this); } else { *aResult = static_cast(mNodeSetResults.pop()); (*aResult)->mRecycler = this; } NS_ADDREF(*aResult); return NS_OK; } nsresult txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(*aNodeSet, this); } else { *aResult = static_cast(mNodeSetResults.pop()); (*aResult)->append(*aNodeSet); (*aResult)->mRecycler = this; } NS_ADDREF(*aResult); return NS_OK; } nsresult txResultRecycler::getNodeSet(const txXPathNode& aNode, txAExprResult** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(aNode, this); } else { txNodeSet* nodes = static_cast(mNodeSetResults.pop()); nodes->append(aNode); nodes->mRecycler = this; *aResult = nodes; } NS_ADDREF(*aResult); return NS_OK; } nsresult txResultRecycler::getNumberResult(double aValue, txAExprResult** aResult) { if (mNumberResults.isEmpty()) { *aResult = new NumberResult(aValue, this); } else { NumberResult* numRes = static_cast(mNumberResults.pop()); numRes->value = aValue; numRes->mRecycler = this; *aResult = numRes; } NS_ADDREF(*aResult); return NS_OK; } void txResultRecycler::getBoolResult(bool aValue, txAExprResult** aResult) { *aResult = aValue ? mTrueResult : mFalseResult; NS_ADDREF(*aResult); } nsresult txResultRecycler::getNonSharedNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult) { if (aNodeSet->mRefCnt > 1) { return getNodeSet(aNodeSet, aResult); } *aResult = aNodeSet; NS_ADDREF(*aResult); return NS_OK; } void txAExprResult::Release() { --mRefCnt; NS_LOG_RELEASE(this, mRefCnt, "txAExprResult"); if (mRefCnt == 0) { if (mRecycler) { mRecycler->recycle(this); } else { delete this; } } }