From 6265d667576d1cbea3d71dc20b768da5eafd5754 Mon Sep 17 00:00:00 2001 From: "sicking%bigfoot.com" Date: Tue, 5 Feb 2002 14:22:34 +0000 Subject: [PATCH] Speed up NodeSets by always keeping them in document order. Only sort when we get nodes in random order (such as for id()) or when merging NodeSets. This removes the need for the sortByDocumentOrder function. b=85893 r=Pike rs=jag git-svn-id: svn://10.0.0.236/trunk@113703 18797224-902f-48f8-a5cc-f745e15eee43 --- .../source/xpath/AttributeExpr.cpp | 23 +- .../source/xpath/BasicNodeExpr.cpp | 12 +- .../transformiix/source/xpath/ElementExpr.cpp | 14 +- .../transformiix/source/xpath/Expr.h | 8 - .../transformiix/source/xpath/FilterExpr.cpp | 1 - .../source/xpath/FunctionCall.cpp | 5 +- .../source/xpath/LocationStep.cpp | 48 +- .../transformiix/source/xpath/NodeSet.cpp | 694 ++++++++++-------- .../transformiix/source/xpath/NodeSet.h | 315 ++++---- .../transformiix/source/xpath/PathExpr.cpp | 16 +- .../source/xpath/PredicateList.cpp | 17 +- .../transformiix/source/xpath/RootExpr.cpp | 19 +- .../transformiix/source/xpath/UnionExpr.cpp | 18 +- .../source/xpath/VariableRefExpr.cpp | 7 +- .../transformiix/source/xslt/Numbering.cpp | 2 +- .../source/xslt/ProcessorState.cpp | 49 +- .../transformiix/source/xslt/ProcessorState.h | 8 - .../source/xslt/XSLTProcessor.cpp | 20 +- .../xslt/functions/CurrentFunctionCall.cpp | 10 +- .../xslt/functions/DocumentFunctionCall.cpp | 1 - .../xslt/functions/GenerateIdFunctionCall.cpp | 18 +- .../xslt/functions/txKeyFunctionCall.cpp | 19 +- .../transformiix/source/xslt/txRtfHandler.cpp | 2 +- .../source/xslt/util/txNodeSorter.cpp | 4 +- 24 files changed, 636 insertions(+), 694 deletions(-) diff --git a/mozilla/extensions/transformiix/source/xpath/AttributeExpr.cpp b/mozilla/extensions/transformiix/source/xpath/AttributeExpr.cpp index b7ce6bcb767..b9b26725945 100644 --- a/mozilla/extensions/transformiix/source/xpath/AttributeExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/AttributeExpr.cpp @@ -69,27 +69,8 @@ AttributeExpr::AttributeExpr(String& name) * @return the result of the evaluation **/ ExprResult* AttributeExpr::evaluate(Node* context, ContextState* cs) { - - NodeSet* nodeSet = new NodeSet(); - if ( !context ) return nodeSet; - NamedNodeMap* atts = context->getAttributes(); - if ( atts ) { - PRUint32 i = 0; - if ( isNameWild && isNamespaceWild ) { - for ( ; i < atts->getLength(); i++ ) - nodeSet->add(atts->item(i)); - } - else { - for ( ; i < atts->getLength(); i++ ) { - Node* attr = atts->item(i); - if (matches(attr, context, cs)) { - nodeSet->add(attr); - if (!isNameWild) break; - } - } - } - } - return nodeSet; + NS_ASSERTION(0, "AttributeExpr::evaluate called"); + return 0; } //-- evaluate /** diff --git a/mozilla/extensions/transformiix/source/xpath/BasicNodeExpr.cpp b/mozilla/extensions/transformiix/source/xpath/BasicNodeExpr.cpp index 1702977b5df..6dabc4a5d3d 100644 --- a/mozilla/extensions/transformiix/source/xpath/BasicNodeExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/BasicNodeExpr.cpp @@ -56,16 +56,8 @@ void BasicNodeExpr::setNodeName(const String& name) { * @return the result of the evaluation **/ ExprResult* BasicNodeExpr::evaluate(Node* context, ContextState* cs) { - NodeSet* nodeSet = new NodeSet(); - if (!context) - return nodeSet; - Node* node = context->getFirstChild(); - while (node) { - if (matches(node, context, cs)) - nodeSet->add(node); - node = node->getNextSibling(); - } - return nodeSet; + NS_ASSERTION(0, "BasicNodeExpr::evaluate called"); + return 0; } //-- evaluate /** diff --git a/mozilla/extensions/transformiix/source/xpath/ElementExpr.cpp b/mozilla/extensions/transformiix/source/xpath/ElementExpr.cpp index c2f3d64c7cc..c09a6fb9af7 100644 --- a/mozilla/extensions/transformiix/source/xpath/ElementExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/ElementExpr.cpp @@ -63,18 +63,8 @@ ElementExpr::ElementExpr(String& name) * @return the result of the evaluation **/ ExprResult* ElementExpr::evaluate(Node* context, ContextState* cs) { - - NodeSet* nodeSet = new NodeSet(); - - if ( !context ) return nodeSet; - - Node* node = context->getFirstChild(); - while (node) { - if (matches(node, context, cs)) - nodeSet->add(node); - node = node->getNextSibling(); - } - return nodeSet; + NS_ASSERTION(0, "ElementExpr::evaluate called"); + return 0; } //-- evaluate /** diff --git a/mozilla/extensions/transformiix/source/xpath/Expr.h b/mozilla/extensions/transformiix/source/xpath/Expr.h index 9dcb61a1b35..f46a3e0d06e 100644 --- a/mozilla/extensions/transformiix/source/xpath/Expr.h +++ b/mozilla/extensions/transformiix/source/xpath/Expr.h @@ -87,14 +87,6 @@ public: **/ virtual FunctionCall* resolveFunctionCall(const String& name) = 0; - /** - * Sorts the given NodeSet by DocumentOrder. - * @param nodes the NodeSet to sort - * - * Note: I will be moving this functionality elsewhere soon - **/ - virtual void sortByDocumentOrder(NodeSet* nodes) = 0; - /** * Returns the namespace URI for the given namespace prefix, this method should * only be called for determining a namespace declared within the context diff --git a/mozilla/extensions/transformiix/source/xpath/FilterExpr.cpp b/mozilla/extensions/transformiix/source/xpath/FilterExpr.cpp index 70946f59f36..0be6684cd21 100644 --- a/mozilla/extensions/transformiix/source/xpath/FilterExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/FilterExpr.cpp @@ -67,7 +67,6 @@ ExprResult* FilterExpr::evaluate(Node* context, ContextState* cs) { if (exprResult->getResultType() == ExprResult::NODESET) { // Result is a nodeset, filter it. - cs->sortByDocumentOrder((NodeSet*)exprResult); evaluatePredicates((NodeSet*)exprResult, cs); } else if(!isEmpty()) { diff --git a/mozilla/extensions/transformiix/source/xpath/FunctionCall.cpp b/mozilla/extensions/transformiix/source/xpath/FunctionCall.cpp index c2b6bbafdff..5decbc12b88 100644 --- a/mozilla/extensions/transformiix/source/xpath/FunctionCall.cpp +++ b/mozilla/extensions/transformiix/source/xpath/FunctionCall.cpp @@ -182,10 +182,7 @@ NodeSet* FunctionCall::evaluateToNodeSet(Expr* aExpr, return 0; } - NodeSet* nodes = (NodeSet*)exprResult; - aCs->sortByDocumentOrder(nodes); - - return nodes; + return (NodeSet*)exprResult; } /** diff --git a/mozilla/extensions/transformiix/source/xpath/LocationStep.cpp b/mozilla/extensions/transformiix/source/xpath/LocationStep.cpp index 658ec7dd2df..0e5511b1d95 100644 --- a/mozilla/extensions/transformiix/source/xpath/LocationStep.cpp +++ b/mozilla/extensions/transformiix/source/xpath/LocationStep.cpp @@ -62,8 +62,11 @@ LocationStep::~LocationStep() { **/ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { - NodeSet* nodes = new NodeSet(); - if (( !context ) || (! nodeExpr )) return nodes; + NodeSet* nodes = new NodeSet(); + if (!context || !nodeExpr || !nodes) + return nodes; + + MBool reverse = MB_FALSE; Node* node = context; switch (axisIdentifier) { @@ -71,9 +74,10 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { node = context->getXPathParent(); //-- do not break here case ANCESTOR_OR_SELF_AXIS : + reverse = MB_TRUE; while (node) { if (nodeExpr->matches(node, context, cs)) { - nodes->add(node); + nodes->append(node); } node = node->getXPathParent(); } @@ -81,17 +85,18 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { case ATTRIBUTE_AXIS : { NamedNodeMap* atts = context->getAttributes(); - if ( atts ) { - for ( PRUint32 i = 0; i < atts->getLength(); i++ ) { + if (atts) { + for (PRUint32 i = 0; i < atts->getLength(); i++) { Node* attr = atts->item(i); - if ( nodeExpr->matches(attr, context, cs) ) nodes->add(attr); + if (nodeExpr->matches(attr, context, cs)) + nodes->append(attr); } } break; } case DESCENDANT_OR_SELF_AXIS : - if ( nodeExpr->matches(context, context, cs)) - nodes->add(context); + if (nodeExpr->matches(context, context, cs)) + nodes->append(context); //-- do not break here case DESCENDANT_AXIS : fromDescendants(context, cs, nodes); @@ -109,7 +114,7 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { node = node->getNextSibling(); if (nodeExpr->matches(node, context, cs)) - nodes->add(node); + nodes->append(node); if (node->hasChildNodes()) fromDescendants(node, cs, nodes); @@ -124,7 +129,7 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { node = context->getNextSibling(); while (node) { if (nodeExpr->matches(node, context, cs)) - nodes->add(node); + nodes->append(node); node = node->getNextSibling(); } break; @@ -138,10 +143,11 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { { Node* parent = context->getXPathParent(); if ( nodeExpr->matches(parent, context, cs) ) - nodes->add(parent); + nodes->append(parent); break; } case PRECEDING_AXIS : + reverse = MB_TRUE; while (node && !node->getPreviousSibling()) { node = node->getXPathParent(); } @@ -152,7 +158,7 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { fromDescendantsRev(node, cs, nodes); if (nodeExpr->matches(node, context, cs)) - nodes->add(node); + nodes->append(node); while (node && !node->getPreviousSibling()) { node = node->getParentNode(); @@ -160,23 +166,24 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { } break; case PRECEDING_SIBLING_AXIS: + reverse = MB_TRUE; node = context->getPreviousSibling(); while (node) { if (nodeExpr->matches(node, context, cs)) - nodes->add(node); + nodes->append(node); node = node->getPreviousSibling(); } break; case SELF_AXIS : - if ( nodeExpr->matches(context, context, cs) ) - nodes->add(context); + if (nodeExpr->matches(context, context, cs)) + nodes->append(context); break; default: //-- Children Axis { Node* tmpNode = context->getFirstChild(); while (tmpNode) { - if ( nodeExpr->matches(tmpNode, context, cs) ) - nodes->add(tmpNode); + if (nodeExpr->matches(tmpNode, context, cs)) + nodes->append(tmpNode); tmpNode = tmpNode->getNextSibling(); } break; @@ -186,6 +193,9 @@ ExprResult* LocationStep::evaluate(Node* context, ContextState* cs) { //-- apply predicates evaluatePredicates(nodes, cs); + if (reverse) + nodes->reverse(); + return nodes; } //-- evaluate @@ -207,7 +217,7 @@ void LocationStep::fromDescendants(Node* context, ContextState* cs, NodeSet* nod Node* child = context->getFirstChild(); while (child) { if (nodeExpr->matches(child, context, cs)) - nodes->add(child); + nodes->append(child); //-- check childs descendants if (child->hasChildNodes()) fromDescendants(child, cs, nodes); @@ -228,7 +238,7 @@ void LocationStep::fromDescendantsRev(Node* context, ContextState* cs, NodeSet* fromDescendantsRev(child, cs, nodes); if (nodeExpr->matches(child, context, cs)) - nodes->add(child); + nodes->append(child); child = child->getPreviousSibling(); } diff --git a/mozilla/extensions/transformiix/source/xpath/NodeSet.cpp b/mozilla/extensions/transformiix/source/xpath/NodeSet.cpp index b298e123157..efe350c5568 100644 --- a/mozilla/extensions/transformiix/source/xpath/NodeSet.cpp +++ b/mozilla/extensions/transformiix/source/xpath/NodeSet.cpp @@ -32,325 +32,439 @@ #include "NodeSet.h" #include "XMLDOMUtils.h" -#ifdef TX_EXE -#include -#endif +#include "string.h" +#include "stdio.h" -/** - * NodeSet - * This class was ported from XSL:P. -**/ +static const int kTxNodeSetMinSize = 4; +static const int kTxNodeSetGrowFactor = 2; +/* + * Implementation of an XPath NodeSet + */ - //-------------/ - //- Constants -/ -//-------------/ -const int NodeSet::DEFAULT_SIZE = 25; - - - //----------------/ - //- Constructors -/ -//----------------/ - -/** - * Creates a new NodeSet with the default Size -**/ -NodeSet::NodeSet() { - initialize(DEFAULT_SIZE); -} //-- NodeSet - -/** - * Creates a new NodeSet with the default Size -**/ -NodeSet::NodeSet(int size) { - initialize(size); -} //-- NodeSet - -/** - * Creates a new NodeSet, copying the Node references from the source - * NodeSet -**/ -NodeSet::NodeSet(const NodeSet& source) { - initialize(source.size()); - source.copyInto(*this); -} //--NodeSet - -/** - * Helper method for Constructors -**/ -void NodeSet::initialize(int size) { - checkDuplicates = MB_TRUE; - elements = new Node*[size]; - for ( int i = 0; i < size; i++ ) elements[i] = 0; - elementCount = 0; - bufferSize = size; - initialSize = size; -} //-- initialize - -/** - * Destructor for NodeSet -**/ -NodeSet::~NodeSet() { - delete [] elements; -} //-- ~NodeSet - -/** - * Adds the specified Node to this NodeSet if it is not already - * contained within in this NodeSet. - * @param node the Node to add to the NodeSet - * @return true if the Node is added to the NodeSet -**/ -MBool NodeSet::add(Node* node) { - - if (node) { - if (checkDuplicates && contains(node)) return MB_FALSE; - if (elementCount == bufferSize) increaseSize(); - elements[elementCount++] = node; - return MB_TRUE; - } - return MB_FALSE; -} //-- add - -/** - * Adds the specified Node to the NodeSet at the specified index, - * as long as the Node is not already contained within the set - * @param node the Node to add to the NodeSet - * @return true if the Node is added to the NodeSet. If the index is - * out of bounds the Node will not be added to the set and false will be returned. -**/ -MBool NodeSet::add(int index, Node* node) +/* + * Creates a new empty NodeSet + */ +NodeSet::NodeSet() : mElements(0), + mBufferSize(0), + mElementCount(0) { - if (!node || (index < 0) || (index > elementCount)) return MB_FALSE; +} - if (checkDuplicates && contains(node)) return MB_FALSE; - - // make sure we have room to add the object - if (elementCount == bufferSize) increaseSize(); - - if (index == elementCount) { - elements[elementCount++] = node; +/* + * Creates a new NodeSet containing the supplied Node + */ +NodeSet::NodeSet(Node* aNode) : mBufferSize(1), + mElementCount(1) +{ + NS_ASSERTION(aNode, "missing node to NodeSet::add") + mElements = new Node*[1]; + if (!mElements) { + NS_ASSERTION(0, "out of memory"); + mBufferSize = 0; + mElementCount = 0; } else { - shiftUp(index); - elements[index] = node; - ++elementCount; + mElements[0] = aNode; } - return MB_TRUE; -} //-- add +} -/** - * Removes all elements from the list -**/ -void NodeSet::clear() { - for (int i = 0; i < elementCount; i++) { - elements[i] = 0; +/* + * Creates a new NodeSet, copying the Node references from the source + * NodeSet + */ +NodeSet::NodeSet(const NodeSet& aSource) : mElements(0), + mBufferSize(0), + mElementCount(0) +{ + append(&aSource); +} + +/* + * Adds the specified Node to this NodeSet if it is not already in this + * NodeSet. The node is inserted according to document order. + * @param aNode the Node to add to the NodeSet + * @return errorcode. + */ +nsresult NodeSet::add(Node* aNode) +{ + NS_ASSERTION(aNode, "missing node to NodeSet::add") + if (!aNode) + return NS_ERROR_NULL_POINTER; + + MBool nonDup; + int pos = findPosition(aNode, 0, mElementCount - 1, nonDup); + if (nonDup) { + if (!ensureSize(mElementCount + 1)) + return NS_ERROR_OUT_OF_MEMORY; + memmove(mElements + pos + 1, + mElements + pos, + (mElementCount - pos) * sizeof(Node*)); + mElements[pos] = aNode; + ++mElementCount; } - elementCount = 0; -} //-- clear + return NS_OK; +} -/** - * Returns true if the specified Node is contained in the set. - * if the specfied Node is null, then if the NodeSet contains a null - * value, true will be returned. - * @param node the element to search the NodeSet for - * @return true if specified Node is contained in the NodeSet -**/ -MBool NodeSet::contains(Node* node) { - return (MBool)(indexOf(node) >= 0); -} //-- contains +/* + * Adds the nodes in specified NodeSet to this NodeSet. The resulting NodeSet + * is sorted in document order and does not contain any duplicate nodes. + * @param aNodes the NodeSet to add, must be in document order. + * @return true on success. false on failure. + */ -/** - * Copies the elements of this NodeSet, into the destination NodeSet -**/ -void NodeSet::copyInto(NodeSet& dest) const { - for ( int i = 0; i < elementCount; i++ ) dest.add(elements[i]); -} //-- copyInto +/* + * The code is optimized to make a minimum number of calls to + * Node::compareDocumentPosition. The idea is this: + * We have the two nodesets (number indicate "document position") + * + * 1 3 7 <- source 1 + * 2 3 6 8 9 <- source 2 + * _ _ _ _ _ _ _ _ <- result + * + * + * We select the last node in the smallest nodeset and find where in the other + * nodeset it would be inserted. In this case we would take the 7 from the + * first nodeset and find the position between the 6 and 8 in the second. + * We then take the nodes after the insert-position and move it to the end of + * the resulting nodeset, and then do the same for the node from the smaller + * nodeset. Which in this case means that we'd first move the 8 and 9 nodes, + * and then the 7 node, giving us the following: + * + * 1 3 <- source 1 + * 2 3 6 <- source 2 + * _ _ _ _ _ 7 8 9 <- result + * + * Repeat until one of the nodesets are empty. If we find a duplicate node + * when searching for where insertposition we skip the step where we move the + * node from the smaller nodeset to the resulting nodeset. So in this next + * step in the example we would only move the 3 and 6 nodes from the second + * nodeset and then just remove the 3 node from the first nodeset. Giving: + * + * 1 <- source 1 + * 2 <- source 2 + * _ _ _ 3 6 7 8 9 <- result + * + * We might therefor end up with some blanks in the bigining of the resulting + * nodeset, which we simply fix by moving all the nodes one step down. + */ +nsresult NodeSet::add(const NodeSet* aNodes) +{ + NS_ASSERTION(aNodes, "missing nodeset to NodeSet::add") + if (!aNodes) + return NS_ERROR_NULL_POINTER; -/** - * Returns the Node at the specified position in this NodeSet. - * @param index the position of the Node to return -**/ -Node* NodeSet::get(int index) { - if ((index < 0) || index >= elementCount) return 0; - return elements[index]; -} //-- get + if (aNodes->mElementCount == 0) + return NS_OK; -/** - * Returns true if duplicate checking is enabled, otherwise false. - * - * @return true if duplicate checking is enabled, otherwise false. -**/ -MBool NodeSet::getDuplicateChecking() { - return checkDuplicates; -} //-- getDuplicateChecking + // This is probably a rather common case, so lets try to shortcut + if (mElementCount == 0 || + mElements[mElementCount-1]->compareDocumentPosition(aNodes->mElements[0]) < 0) + return append(aNodes); -/** + if (!ensureSize(mElementCount + aNodes->mElementCount)) + return NS_ERROR_OUT_OF_MEMORY; + + // Index of last node in this nodeset + int thisPos = mElementCount - 1; + // Index of last node in other nodeset + int otherPos = aNodes->mElementCount - 1; + // Index in result where last insert was done. + int lastInsertPos = mElementCount + aNodes->mElementCount; + + while (thisPos >= 0 && otherPos >= 0) { + if (thisPos > otherPos) { + int pos; + MBool nonDup; + // Find where in the remaining nodes in this nodeset a node from + // the other nodeset should be inserted + pos = findPosition(aNodes->mElements[otherPos], 0, thisPos, + nonDup); + + // Move nodes in this nodeset + lastInsertPos -= thisPos - pos + 1; + memmove(mElements + lastInsertPos, + mElements + pos, + (thisPos - pos + 1) * sizeof(Node*)); + + // Copy node from the other nodeset unless it's a dup + if (nonDup) + mElements[--lastInsertPos] = aNodes->mElements[otherPos]; + + // Adjust positions in both nodesets + thisPos = pos - 1; + --otherPos; + } + else { + int pos; + MBool nonDup; + // Find where in the remaining nodes in the other nodeset a node + // from this nodeset should be inserted + pos = aNodes->findPosition(mElements[thisPos], 0, otherPos, + nonDup); + + // Copy nodes from other nodeset to this + lastInsertPos -= otherPos - pos + 1; + memcpy(mElements + lastInsertPos, + aNodes->mElements + pos, + (otherPos - pos + 1) * sizeof(Node*)); + + // Move node in this nodeset unless it's a dup + if (nonDup) + mElements[--lastInsertPos] = mElements[thisPos]; + + // Adjust positions in both nodesets + otherPos = pos - 1; + --thisPos; + } + } + + if (thisPos >= 0) { + // There were some elements still left in this nodeset that need to + // be moved + lastInsertPos -= thisPos + 1; + memmove(mElements + lastInsertPos, + mElements, + (thisPos + 1) * sizeof(Node*)); + } + else if (otherPos >= 0) { + // There were some elements still left in the other nodeset that need + // to be copied + lastInsertPos -= otherPos + 1; + memcpy(mElements + lastInsertPos, + aNodes->mElements, + (otherPos + 1) * sizeof(Node*)); + } + + // if lastInsertPos != 0 then we have found some duplicates causing the + // first element to not be placed at mElements[0] + mElementCount += aNodes->mElementCount - lastInsertPos; + if (lastInsertPos) { + memmove(mElements, + mElements + lastInsertPos, + mElementCount * sizeof(Node*)); + } + + return NS_OK; +} + +/* + * Append API + * These functions should be used with care. + * They are intended to be used when the caller assures that the resulting + * NodeSet remains in document order. + * Abuse will break document order, and cause errors in the result. + * These functions are significantly faster than the add API, as no + * Node::OrderInfo structs will be generated. + */ + +/* + * Appends the specified Node to the end of this NodeSet + * @param aNode the Node to append to the NodeSet + * @return true on success. false on failure. + */ +nsresult NodeSet::append(Node* aNode) +{ + NS_ASSERTION(aNode, "missing node to NodeSet::append") + if (!aNode) + return NS_ERROR_NULL_POINTER; + + if (!ensureSize(mElementCount + 1)) + return NS_ERROR_OUT_OF_MEMORY; + + mElements[mElementCount++] = aNode; + + return NS_OK; +} + +/* + * Appends the nodes in the specified NodeSet to the end of this NodeSet + * @param aNodes the NodeSet to append to the NodeSet + * @return true on success. false on failure. + */ +nsresult NodeSet::append(const NodeSet* aNodes) +{ + NS_ASSERTION(aNodes, "missing nodeset to NodeSet::append") + if (!aNodes) + return NS_ERROR_NULL_POINTER; + + if (!ensureSize(mElementCount + aNodes->mElementCount)) + return NS_ERROR_OUT_OF_MEMORY; + + memcpy(mElements + mElementCount, + aNodes->mElements, + aNodes->mElementCount * sizeof(Node*)); + mElementCount += aNodes->mElementCount; + + return NS_OK; +} + +/* + * Reverse the order of the nodes. + */ +void NodeSet::reverse() +{ + int i; + for (i = 0; i < mElementCount / 2; ++i) { + Node* tmp; + tmp = mElements[i]; + mElements[i] = mElements[mElementCount - 1 - i]; + mElements[mElementCount - 1 - i] = tmp; + } +} + +/* * Returns the index of the specified Node, * or -1 if the Node is not contained in the NodeSet - * @param node the Node to get the index for -**/ -int NodeSet::indexOf(Node* node) { - for (int i = 0; i < elementCount; i++) - if (node == elements[i]) return i; - return -1; -} //-- indexOf + * @param aNode the Node to get the index for + * @return index of specified node or -1 if the node does not exist + */ +MBool NodeSet::indexOf(Node* aNode) const +{ + // XXX evaluate cost of this + // Workaround to fix the fact that attributes can't be + // pointer-compared + MBool nonDup; + int pos = findPosition(aNode, 0, mElementCount - 1, nonDup); + return nonDup ? -1 : pos; +} -/** - * Returns true if there are no Nodes in the NodeSet. - * @return true if there are no Nodes in the NodeSet. -**/ -MBool NodeSet::isEmpty() { - return (elementCount == 0) ? MB_TRUE : MB_FALSE; -} //-- isEmpty +/* + * Returns the Node at the specified position in this NodeSet. + * @param aIndex the position of the Node to return + * @return Node at specified position + */ +Node* NodeSet::get(int aIndex) const +{ + NS_ASSERTION(aIndex >= 0 && aIndex < mElementCount, + "invalid index in NodeSet::get") + if (aIndex < 0 || aIndex >= mElementCount) + return 0; -/** - * Removes the Node at the specified index from the NodeSet - * @param index the position in the NodeSet to remove the Node from - * @return the Node that was removed from the list -**/ -Node* NodeSet::remove(int index) { + return mElements[aIndex]; +} - if ((index < 0) || (index >= elementCount)) return 0; - - Node* node = elements[index]; - shiftDown(index+1); - --elementCount; - return node; -} //-- remove - -/** - * Removes the the specified Node from the NodeSet - * @param node the Node to remove from the NodeSet - * @return true if the Node was removed from the list -**/ -MBool NodeSet::remove(Node* node) { - int index = indexOf(node); - - if (index > -1) { - remove(index); - } - else return MB_FALSE; - - return MB_TRUE; -} //-- remove - -/** - * Enables or disables checking for duplicates. By default - * the #add method will check for duplicate nodes. This should - * only be disabled when no possibility of duplicates could occur. - * - * @param checkDuplicates an MBool indicating, when true, to perform duplicate checking, - * otherwise duplicate checking is disabled. -**/ -void NodeSet::setDuplicateChecking(MBool checkDuplicates) { - this->checkDuplicates = checkDuplicates; -} //-- setDuplicateChecking - -/** - * Returns the number of elements in the NodeSet - * @return the number of elements in the NodeSet -**/ -int NodeSet::size() const{ - return elementCount; -} //-- size - -/** - * Creates a String representation of this NodeSet - * @param str the destination string to append the String representation to. -**/ -void NodeSet::toString(String& str) { - str.append("#NodeSet"); -} //-- toString - - //-------------------/ - //- Private Methods -/ -//-------------------/ - -/** - * increase the NodeSet capacity by a factor of its initial size -**/ -void NodeSet::increaseSize() { - - bufferSize += bufferSize; - Node** tmpNodes = elements; - elements = new Node*[bufferSize]; - int i=0; - for (i=0;i < elementCount; i++) elements[i] = tmpNodes[i]; - for (;i elementCount)) return; - - //-- from Java - //-- System.arraycopy(elements, index, elements, index - 1, elementCount - index); - for (int i = index; i < elementCount; i++) { - elements[i-1] = elements[i]; - } - - elements[elementCount-1] = 0; -} //-- shiftDown - -/** - * Shifts all elements at the specified index up by 1 -**/ -void NodeSet::shiftUp(int index) { - if (index == elementCount) return; - if (elementCount == bufferSize) increaseSize(); - - //-- from Java - //-- System.arraycopy(elements, index, elements, index + 1, elementCount - index); - for (int i = elementCount; i > index; i--) { - elements[i] = elements[i-1]; - } -} //-- shiftUp - - //------------------------------------/ - //- Virtual Methods from: ExprResult -/ -//------------------------------------/ - -/** +/* * Returns the type of ExprResult represented * @return the type of ExprResult represented -**/ -short NodeSet::getResultType() { + */ +short NodeSet::getResultType() +{ return ExprResult::NODESET; -} //-- getResultType +} -/** +/* * Converts this ExprResult to a Boolean (MBool) value * @return the Boolean value -**/ -MBool NodeSet::booleanValue() { - return (MBool) (size() > 0); -} //- booleanValue + */ +MBool NodeSet::booleanValue() +{ + return mElementCount > 0; +} -/** +/* * Converts this ExprResult to a Number (double) value * @return the Number value -**/ -double NodeSet::numberValue() { - // OG+ - // As per the XPath spec, the number value of a node-set is the number value - // of its string value. - String str; - stringValue(str); - return Double::toDouble(str); - // OG- -} //-- numberValue + */ +double NodeSet::numberValue() +{ + String str; + stringValue(str); + return Double::toDouble(str); +} -/** +/* * Creates a String representation of this ExprResult - * @param str the destination string to append the String representation to. -**/ -void NodeSet::stringValue(String& str) { - if ( size()>0) { - // XXX Sort by document order here - XMLDOMUtils::getNodeValue(get(0), str); + * @param aStr the destination string to append the String representation to. + */ +void NodeSet::stringValue(String& aStr) +{ + if (mElementCount > 0) + XMLDOMUtils::getNodeValue(get(0), aStr); +} + +/* + * Makes sure that the mElements buffer contains at least aSize elements. + * If a new allocation is required the elements are copied over to the new + * buffer + * @param aSize requested number of elements + * @return true if allocation succeded, false on out of memory + */ +MBool NodeSet::ensureSize(int aSize) +{ + if (aSize <= mBufferSize) + return MB_TRUE; + + // This isn't 100% safe. But until someone manages to make a 1gig nodeset + // it should be ok. + int newSize = mBufferSize ? mBufferSize : kTxNodeSetMinSize; + while (newSize < aSize) + newSize *= kTxNodeSetGrowFactor; + + Node** newArr = new Node*[newSize]; + if (!newArr) + return MB_FALSE; + + if (mElementCount) + memcpy(newArr, mElements, mElementCount * sizeof(Node*)); + + delete [] mElements; + mElements = newArr; + mBufferSize = newSize; + + return MB_TRUE; +} + +/* + * Finds position in the mElements buffer where a node should be inserted + * to keep the nodeset in document order. Searches the positions + * aFirst-aLast, including both aFirst and aLast. + * @param aNode Node to find insert position for + * @param aFirst First index to search, this index will be searched + * @param aLast Last index to search, this index will be searched + * @param aNonDup Out-param. Set to true if the node should be inserted, + * false if it already exists in the NodeSet. + * @return The index where to insert the node. The node should be + * inserted before the node at this index. This value is + * always >= aFirst and <= aLast + 1. This value is always + * set, even if aNode already exists in the NodeSet + */ +int NodeSet::findPosition(Node* aNode, int aFirst, + int aLast, MBool& aNonDup) const +{ + NS_ASSERTION(aNode, "missing node in NodeSet::findPosition"); + NS_ASSERTION(aFirst <= aLast+1 && aLast < mElementCount, + "bad position in NodeSet::findPosition"); + + if (aLast - aFirst <= 1) { + // If we search 2 nodes or less there is no point in further divides + int pos; + for (pos = aFirst; pos <= aLast; ++pos) { + int cmp = aNode->compareDocumentPosition(mElements[pos]); + if (cmp < 0) { + aNonDup = MB_TRUE; + return pos; + } + + if (cmp == 0) { + aNonDup = MB_FALSE; + return pos; + } + } + + aNonDup = MB_TRUE; + return pos; } -} //-- stringValue + + int midpos = (aFirst + aLast) / 2; + int cmp = aNode->compareDocumentPosition(mElements[midpos]); + if (cmp == 0) { + aNonDup = MB_FALSE; + return midpos; + } + + if (cmp > 0) + return findPosition(aNode, midpos + 1, aLast, aNonDup); + + return findPosition(aNode, aFirst, midpos - 1, aNonDup); +} diff --git a/mozilla/extensions/transformiix/source/xpath/NodeSet.h b/mozilla/extensions/transformiix/source/xpath/NodeSet.h index 9cb790b57a9..970a4e412f0 100644 --- a/mozilla/extensions/transformiix/source/xpath/NodeSet.h +++ b/mozilla/extensions/transformiix/source/xpath/NodeSet.h @@ -1,4 +1,5 @@ -/* +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of @@ -26,218 +27,184 @@ * */ -/** - * NodeSet -**/ +/* + * Implementation of an XPath NodeSet + */ #ifndef TRANSFRMX_NODESET_H #define TRANSFRMX_NODESET_H #include "dom.h" #include "ExprResult.h" +#include "txError.h" class NodeSet : public ExprResult { public: - //----------------/ - //- Constructors -/ - //----------------/ - - /** - * Creates a new NodeSet with the default Size - **/ + /* + * Creates a new empty NodeSet + */ NodeSet(); - /** - * Creates a new NodeSet with the specified Size - **/ - NodeSet(int size); + /* + * Creates a new NodeSet containing the supplied node + */ + NodeSet(Node* aNode); - /** - * Creates a new NodeSet using the given NodeSet - **/ - NodeSet(const NodeSet& source); + /* + * Creates a new NodeSet, copying the Node references from the source + * NodeSet + */ + NodeSet(const NodeSet& aSource); - /** - * Destructor for NodeSet, will not delete Node References - **/ - virtual ~NodeSet(); + /* + * Destructor for NodeSet, will not delete referenced Nodes + */ + virtual ~NodeSet() + { + delete [] mElements; + } - /** - * Adds the specified Node to this NodeSet if it is not already - * contained within in this NodeSet. - * @param node the Node to add to the NodeSet - * @return true if the Node is added to the NodeSet - **/ - MBool add(Node* node); + /* + * Adds the specified Node to this NodeSet if it is not already in this + * NodeSet. The node is inserted according to document order. + * @param aNode the Node to add to the NodeSet + * @return errorcode. + */ + nsresult add(Node* aNode); - /** - * Adds the specified Node to the NodeSet at the specified index, - * as long as the Node is not already contained within the set - * @param node the Node to add to the NodeSet - * @return true if the Node is added to the NodeSet - * @exception IndexOutOfBoundsException - **/ - MBool add(int index, Node* node); + /* + * Adds the nodes in specified NodeSet to this NodeSet. The resulting + * NodeSet is sorted in document order and does not contain any duplicate + * nodes. + * @param aNodes the NodeSet to add, must be in document order. + * @return errorcode. + */ + nsresult add(const NodeSet* aNodes); - /** - * Removes all elements from the list - **/ - void clear(); + /* + * Append API + * These functions should be used with care. + * They are intended to be used when the caller assures that the resulting + * NodeSet remains in document order. + * Abuse will break document order, and cause errors in the result. + * These functions are significantly faster than the add API, as no + * Node::OrderInfo structs will be generated. + */ - /** - * Returns true if the specified Node is contained in the set. - * if the specfied Node is null, then if the NodeSet contains a null - * value, true will be returned. - * @param node the element to search the NodeSet for - * @return true if specified Node is contained in the NodeSet - **/ - MBool contains(Node* node); + /* + * Appends the specified Node to the end of this NodeSet + * @param aNode the Node to append to the NodeSet + * @return errorcode. + */ + nsresult append(Node* aNode); - /** - * Copies the elements of this NodeSet, into the destination NodeSet - **/ - void copyInto(NodeSet& dest) const; + /* + * Appends the nodes in the specified NodeSet to the end of this NodeSet + * @param aNodes the NodeSet to append to the NodeSet + * @return errorcode. + */ + nsresult append(const NodeSet* aNodes); - /** - * Returns the Node at the specified position in this NodeSet. - * @param index the position of the Node to return - * @exception IndexOutOfBoundsException - **/ - Node* get(int index); + /* + * Reverse the order of the nodes. + */ + void reverse(); - /** - * Returns true if duplicate checking is enabled, otherwise false. - * - * @return true if duplicate checking is enabled, otherwise false. - **/ - MBool getDuplicateChecking(); + /* + * Removes all nodes from this nodeset + */ + void clear() + { + mElementCount = 0; + } - /** + /* * Returns the index of the specified Node, * or -1 if the Node is not contained in the NodeSet - * @param node the Node to get the index for - **/ - int indexOf(Node* node); + * @param aNode the Node to get the index for + * @return index of specified node or -1 if the node does not exist + */ + int indexOf(Node* aNode) const; - /** + /* + * Returns true if the specified Node is contained in the set. + * @param aNode the Node to search for + * @return true if specified Node is contained in the NodeSet + */ + MBool contains(Node* aNode) const + { + return indexOf(aNode) >= 0; + } + + /* + * Returns the Node at the specified position in this NodeSet. + * @param aIndex the position of the Node to return + * @return Node at specified position + */ + Node* get(int aIndex) const; + + /* * Returns true if there are no Nodes in the NodeSet. * @return true if there are no Nodes in the NodeSet. - **/ - MBool isEmpty(); + */ + MBool isEmpty() const + { + return mElementCount == 0; + } - /** - * Removes the Node at the specified index from the NodeSet - * @param index the position in the NodeSet to remove the Node from - * @return the Node that was removed from the list - **/ - Node* remove(int index); - - /** - * Removes the the specified Node from the NodeSet - * @param node the Node to remove from the NodeSet - * @return true if the Node was removed from the list - **/ - MBool remove(Node* node); - - /** - * Enables or disables checking for duplicates. By default - * the #add method will check for duplicate nodes. This should - * only be disabled when no possibility of duplicates could occur. - * - * @param checkDuplicates an MBool indicating, when true, to perform duplicate checking, - * otherwise duplicate checking is disabled. - **/ - void setDuplicateChecking(MBool checkDuplicates); - - /** + /* * Returns the number of elements in the NodeSet * @return the number of elements in the NodeSet - **/ - int size() const; + */ + int size() const + { + return mElementCount; + } - /** - * Creates a String representation of this NodeSet - * @param str the destination string to append the String representation to. - **/ - void toString(String& str); - - //------------------------------------/ - //- Virtual Methods from: ExprResult -/ - //------------------------------------/ - - /** - * Returns the type of ExprResult represented - * @return the type of ExprResult represented - **/ - virtual short getResultType(); - - /** - * Converts this ExprResult to a Boolean (MBool) value - * @return the Boolean value - **/ - virtual MBool booleanValue(); - - /** - * Converts this ExprResult to a Number (double) value - * @return the Number value - **/ - virtual double numberValue(); - - /** - * Creates a String representation of this ExprResult - * @param str the destination string to append the String representation to. - **/ - virtual void stringValue(String& str); + /* + * Virtual methods from ExprResult + */ + short getResultType(); + MBool booleanValue(); + double numberValue(); + void stringValue(String& aStr); private: + /* + * Makes sure that the mElements buffer contains at least aSize elements. + * If a new allocation is required the elements are copied over to the new + * buffer + * @param aSize requested number of elements + * @return true if allocation succeded, false on out of memory + */ + MBool ensureSize(int aSize); - //-------------------/ - //- Private Members -/ - //-------------------/ + /* + * Finds position in the mElements buffer where a node should be inserted + * to keep the nodeset in document order. Searches the positions + * aFirst-aLast, including both aFirst and aLast. + * @param aNode Node to find insert position for + * @param aFirst First index to search, this index will be searched + * @param aLast Last index to search, this index will be searched + * @param aPos out-param. Will be set to the index where to insert the + * node. The node should be inserted before the node at + * this index. This value is always >= aFirst and + * <= aLast + 1. This value is always set, even if aNode + * already exists in the NodeSet. + * @return true if the node should be inserted, false if it already exists + * in the NodeSet + */ + MBool findPosition(Node* aNode, int aFirst, int aLast, int& aPos) const; - static const int DEFAULT_SIZE; + Node** mElements; + int mBufferSize; + int mElementCount; - Node** elements; - - int initialSize; - int bufferSize; - - MBool checkDuplicates; - - /** - * The next available location in the elements array - **/ - int elementCount; - - //-------------------/ - //- Private Methods -/ - //-------------------/ - - /** - * Helper method for constructors - **/ - void initialize(int size); - - /** - * increase the NodeSet capacity by a factor of its initial size - **/ - void increaseSize(); - - /** - * Shifts all elements at the specified index to down by 1 - **/ - void shiftDown(int index); - - /** - * Shifts all elements at the specified index up by 1 - **/ - void shiftUp(int index); - -}; //-- NodeSet +}; typedef NodeSet txResultTreeFragment; diff --git a/mozilla/extensions/transformiix/source/xpath/PathExpr.cpp b/mozilla/extensions/transformiix/source/xpath/PathExpr.cpp index 32ed50ae8d6..02ad5dbdac2 100644 --- a/mozilla/extensions/transformiix/source/xpath/PathExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/PathExpr.cpp @@ -96,18 +96,15 @@ void PathExpr::addExpr(Expr* expr, PathOperator pathOp) **/ ExprResult* PathExpr::evaluate(Node* context, ContextState* cs) { - //-- add selectExpr functionality here + if (!context || !expressions.getLength()) + return new StringResult("error"); - if (!context || (expressions.getLength() == 0)) - return new NodeSet(0); - - NodeSet* nodes = new NodeSet(); + NodeSet* nodes = new NodeSet(context); if (!nodes) { // XXX ErrorReport: out of memory NS_ASSERTION(0, "out of memory"); return 0; } - nodes->add(context); ListIterator iter(&expressions); PathExprItem* pxi; @@ -133,7 +130,7 @@ ExprResult* PathExpr::evaluate(Node* context, ContextState* cs) } if (tmpNodes) { - resNodes->copyInto(*tmpNodes); + tmpNodes->add(resNodes); delete resNodes; } else @@ -159,8 +156,9 @@ void PathExpr::evalDescendants (Expr* expr, Node* context, if (!res || (res->getResultType() != ExprResult::NODESET)) { //XXX ErrorReport: report nonnodeset error } - else - ((NodeSet*)res)->copyInto(*resNodes); + else { + resNodes->add((NodeSet*)res); + } delete res; MBool filterWS = cs->isStripSpaceAllowed(context); diff --git a/mozilla/extensions/transformiix/source/xpath/PredicateList.cpp b/mozilla/extensions/transformiix/source/xpath/PredicateList.cpp index 7a83e003e87..689dd3c3a6a 100644 --- a/mozilla/extensions/transformiix/source/xpath/PredicateList.cpp +++ b/mozilla/extensions/transformiix/source/xpath/PredicateList.cpp @@ -64,13 +64,6 @@ void PredicateList::evaluatePredicates(NodeSet* nodes, ContextState* cs) cs->getNodeSetStack()->push(nodes); NodeSet newNodes; - // optimize; set DuplicateChecking to MB_FALSE, - // restore original state later - // we only work with |Node|s already in the NodeSet, so they - // have been checked already, no need to check again in here. - MBool ndsCheckDupl = nodes->getDuplicateChecking(); - nodes->setDuplicateChecking(MB_FALSE); - newNodes.setDuplicateChecking(MB_FALSE); txListIterator iter(&predicates); while (iter.hasNext()) { Expr* expr = (Expr*)iter.next(); @@ -90,23 +83,21 @@ void PredicateList::evaluatePredicates(NodeSet* nodes, ContextState* cs) case ExprResult::NUMBER : // handle default, [position() == numberValue()] if ((double)(nIdx+1) == exprResult->numberValue()) - newNodes.add(node); + newNodes.append(node); break; default: if (exprResult->booleanValue()) - newNodes.add(node); + newNodes.append(node); break; } delete exprResult; } // Move new NodeSet to the current one nodes->clear(); - newNodes.copyInto(*nodes); + nodes->append(&newNodes); } cs->getNodeSetStack()->pop(); - // restore DuplicateChecking of NodeSet - nodes->setDuplicateChecking(ndsCheckDupl); -} // evaluatePredicates +} /* * returns true if this predicate list is empty diff --git a/mozilla/extensions/transformiix/source/xpath/RootExpr.cpp b/mozilla/extensions/transformiix/source/xpath/RootExpr.cpp index cbd6f1a5dce..a7562f6c280 100644 --- a/mozilla/extensions/transformiix/source/xpath/RootExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/RootExpr.cpp @@ -40,23 +40,14 @@ RootExpr::RootExpr(MBool aSerialize) { * for evaluation * @return the result of the evaluation **/ -ExprResult* RootExpr::evaluate(Node* context, ContextState* cs) { - NodeSet* nodeSet = new NodeSet(); - if (!nodeSet) { - // XXX ErrorReport: out of memory - NS_ASSERTION(0, "out of memory"); - return 0; - } - +ExprResult* RootExpr::evaluate(Node* context, ContextState* cs) +{ if (!context) - return nodeSet; + return new StringResult("error"); if (context->getNodeType() != Node::DOCUMENT_NODE) - nodeSet->add(context->getOwnerDocument()); - else - nodeSet->add(context); - - return nodeSet; + return new NodeSet(context->getOwnerDocument()); + return new NodeSet(context); } //-- evaluate /** diff --git a/mozilla/extensions/transformiix/source/xpath/UnionExpr.cpp b/mozilla/extensions/transformiix/source/xpath/UnionExpr.cpp index bb250f3db46..eae7a2849c1 100644 --- a/mozilla/extensions/transformiix/source/xpath/UnionExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/UnionExpr.cpp @@ -69,22 +69,24 @@ void UnionExpr::addExpr(Expr* expr) { * for evaluation * @return the result of the evaluation **/ -ExprResult* UnionExpr::evaluate(Node* context, ContextState* cs) { - - if (!context || (expressions.getLength() == 0)) - return new NodeSet(0); - +ExprResult* UnionExpr::evaluate(Node* context, ContextState* cs) +{ NodeSet* nodes = new NodeSet(); + if (!context || expressions.getLength() == 0 || !nodes) + return nodes; + txListIterator iter(&expressions); while (iter.hasNext()) { Expr* expr = (Expr*)iter.next(); ExprResult* exprResult = expr->evaluate(context, cs); - if (exprResult && - exprResult->getResultType() == ExprResult::NODESET) { - ((NodeSet*)exprResult)->copyInto(*nodes); + if (!exprResult || + exprResult->getResultType() != ExprResult::NODESET) { + delete exprResult; + return new StringResult("error"); } + nodes->add((NodeSet*)exprResult); delete exprResult; } diff --git a/mozilla/extensions/transformiix/source/xpath/VariableRefExpr.cpp b/mozilla/extensions/transformiix/source/xpath/VariableRefExpr.cpp index 87a3ea977bf..b48da2807b6 100644 --- a/mozilla/extensions/transformiix/source/xpath/VariableRefExpr.cpp +++ b/mozilla/extensions/transformiix/source/xpath/VariableRefExpr.cpp @@ -59,11 +59,7 @@ ExprResult* VariableRefExpr::evaluate(Node* context, ContextState* cs) { //-- NodeSet case ExprResult::NODESET : { - NodeSet* src = (NodeSet*)exprResult; - NodeSet* dest = new NodeSet(src->size()); - for ( int i = 0; i < src->size(); i++) - dest->add(src->get(i)); - copyOfResult = dest; + copyOfResult = new NodeSet(*(NodeSet*)exprResult); break; } //-- NumberResult @@ -96,4 +92,3 @@ void VariableRefExpr::toString(String& str) { str.append('$'); str.append(name); } //-- toString - diff --git a/mozilla/extensions/transformiix/source/xslt/Numbering.cpp b/mozilla/extensions/transformiix/source/xslt/Numbering.cpp index da9b8fdf811..6b215e7be82 100644 --- a/mozilla/extensions/transformiix/source/xslt/Numbering.cpp +++ b/mozilla/extensions/transformiix/source/xslt/Numbering.cpp @@ -178,7 +178,7 @@ NodeSet* Numbering::getAncestorsOrSelf if ((from) && from->matches(parent, parent->getParentNode(), ps)) break; if (countExpr->matches(parent, parent->getParentNode(), ps)) { - nodeSet->add(parent); + nodeSet->append(parent); if (findNearest) break; } parent = parent->getParentNode(); diff --git a/mozilla/extensions/transformiix/source/xslt/ProcessorState.cpp b/mozilla/extensions/transformiix/source/xslt/ProcessorState.cpp index 522db857db4..095f67a40b7 100644 --- a/mozilla/extensions/transformiix/source/xslt/ProcessorState.cpp +++ b/mozilla/extensions/transformiix/source/xslt/ProcessorState.cpp @@ -131,7 +131,7 @@ void ProcessorState::addAttributeSet(Element* aAttributeSet, if (!node->getLocalName(&nodeName) || !nodeName) continue; if (nodeName == txXSLTAtoms::attribute) - attSet->add(node); + attSet->append(node); TX_RELEASE_ATOM(nodeName); } node = node->getNextSibling(); @@ -427,8 +427,6 @@ NodeSet* ProcessorState::getAttributeSet(const String& aName) if (!attset) return attset; - attset->setDuplicateChecking(MB_FALSE); - ImportFrame* frame; txListIterator frameIter(&mImportFrames); frameIter.resetToEnd(); @@ -436,7 +434,7 @@ NodeSet* ProcessorState::getAttributeSet(const String& aName) while ((frame = (ImportFrame*)frameIter.previous())) { NodeSet* nodes = (NodeSet*)frame->mNamedAttributeSets.get(aName); if (nodes) - nodes->copyInto(*attset); + attset->append(nodes); } return attset; } @@ -965,49 +963,6 @@ FunctionCall* ProcessorState::resolveFunctionCall(const String& name) { } //-- resolveFunctionCall - -/** - * Sorts the given NodeSet by DocumentOrder. - * @param nodes the NodeSet to sort - * - * Note: I will be moving this functionality elsewhere soon -**/ -void ProcessorState::sortByDocumentOrder(NodeSet* nodes) { - if (!nodes || (nodes->size() < 2)) - return; - - NodeSet sorted(nodes->size()); - sorted.setDuplicateChecking(MB_FALSE); - sorted.add(nodes->get(0)); - - int i, k; - for (i = 1; i < nodes->size(); i++) { - Node* node = nodes->get(i); - for (k = i - 1; k >= 0; k--) { - Node* tmpNode = sorted.get(k); - if (node->compareDocumentPosition(tmpNode) > 0) { - sorted.add(k + 1, node); - break; - } - else if (k == 0) { - sorted.add(0, node); - break; - } - } - } - - //-- save current state of duplicates checking - MBool checkDuplicates = nodes->getDuplicateChecking(); - nodes->setDuplicateChecking(MB_FALSE); - nodes->clear(); - for (i = 0; i < sorted.size(); i++) { - nodes->add(sorted.get(i)); - } - nodes->setDuplicateChecking(checkDuplicates); - sorted.clear(); - -} //-- sortByDocumentOrder - //-------------------/ //- Private Methods -/ //-------------------/ diff --git a/mozilla/extensions/transformiix/source/xslt/ProcessorState.h b/mozilla/extensions/transformiix/source/xslt/ProcessorState.h index 26278b2386f..bc9f64ee24c 100644 --- a/mozilla/extensions/transformiix/source/xslt/ProcessorState.h +++ b/mozilla/extensions/transformiix/source/xslt/ProcessorState.h @@ -351,14 +351,6 @@ public: **/ virtual FunctionCall* resolveFunctionCall(const String& name); - /** - * Sorts the given NodeSet by DocumentOrder. - * @param nodes the NodeSet to sort - * - * Note: I will be moving this functionality elsewhere soon - **/ - virtual void sortByDocumentOrder(NodeSet* nodes); - /** * Returns the namespace URI for the given namespace prefix. This method * should only be called to get a namespace declared within the diff --git a/mozilla/extensions/transformiix/source/xslt/XSLTProcessor.cpp b/mozilla/extensions/transformiix/source/xslt/XSLTProcessor.cpp index 5313b37c901..3d8ee4d9ee3 100644 --- a/mozilla/extensions/transformiix/source/xslt/XSLTProcessor.cpp +++ b/mozilla/extensions/transformiix/source/xslt/XSLTProcessor.cpp @@ -813,8 +813,7 @@ Document* XSLTProcessor::process(Document& xmlDocument, while (iter.hasNext()) ps.addErrorObserver(*(ErrorObserver*)iter.next()); - NodeSet nodeSet; - nodeSet.add(&aXMLDocument); + NodeSet nodeSet(&aXMLDocument); ps.pushCurrentNode(&aXMLDocument); ps.getNodeSetStack()->push(&nodeSet); @@ -864,8 +863,7 @@ void XSLTProcessor::process(Document& aXMLDocument, while (iter.hasNext()) ps.addErrorObserver(*(ErrorObserver*)iter.next()); - NodeSet nodeSet; - nodeSet.add(&aXMLDocument); + NodeSet nodeSet(&aXMLDocument); ps.pushCurrentNode(&aXMLDocument); ps.getNodeSetStack()->push(&nodeSet); @@ -1142,9 +1140,6 @@ void XSLTProcessor::processAction(Node* aNode, if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* nodeSet = (NodeSet*)exprResult; - //-- make sure nodes are in DocumentOrder - aPs->sortByDocumentOrder(nodeSet); - //-- push nodeSet onto context stack aPs->getNodeSetStack()->push(nodeSet); @@ -1417,9 +1412,6 @@ void XSLTProcessor::processAction(Node* aNode, if (exprResult->getResultType() == ExprResult::NODESET) { NodeSet* nodeSet = (NodeSet*)exprResult; - //-- make sure nodes are in DocumentOrder - aPs->sortByDocumentOrder(nodeSet); - //-- push nodeSet onto context stack aPs->getNodeSetStack()->push(nodeSet); @@ -1917,10 +1909,6 @@ void XSLTProcessor::processDefaultTemplate(Node* node, NodeSet* nodeSet = (NodeSet*)exprResult; - //-- make sure nodes are in DocumentOrder - //-- this isn't strictly neccecary with the current XPath engine - ps->sortByDocumentOrder(nodeSet); - //-- push nodeSet onto context stack ps->getNodeSetStack()->push(nodeSet); for (int i = 0; i < nodeSet->size(); i++) { @@ -2157,7 +2145,6 @@ void XSLTProcessor::xslCopyOf(ExprResult* aExprResult, ProcessorState* aPs) case ExprResult::NODESET: { NodeSet* nodes = (NodeSet*)aExprResult; - aPs->sortByDocumentOrder(nodes); int i; for (i = 0; i < nodes->size(); i++) { Node* node = nodes->get(i); @@ -2348,8 +2335,7 @@ XSLTProcessor::TransformDocument(nsIDOMNode* aSourceDOM, // XXX Need to add error observers // Set current node and nodeset. - NodeSet nodeSet; - nodeSet.add(&sourceDocument); + NodeSet nodeSet(&sourceDocument); ps.pushCurrentNode(&sourceDocument); ps.getNodeSetStack()->push(&nodeSet); diff --git a/mozilla/extensions/transformiix/source/xslt/functions/CurrentFunctionCall.cpp b/mozilla/extensions/transformiix/source/xslt/functions/CurrentFunctionCall.cpp index 5a8a906d7a3..cd9adf74937 100644 --- a/mozilla/extensions/transformiix/source/xslt/functions/CurrentFunctionCall.cpp +++ b/mozilla/extensions/transformiix/source/xslt/functions/CurrentFunctionCall.cpp @@ -22,10 +22,8 @@ CurrentFunctionCall::CurrentFunctionCall(ProcessorState* ps) : * @return the result of the evaluation * @see FunctionCall.h **/ -ExprResult* CurrentFunctionCall::evaluate(Node* context, ContextState* cs) { - - NodeSet* result = new NodeSet(1); - result->add(processorState->getCurrentNode()); - return result; -} //-- evaluate +ExprResult* CurrentFunctionCall::evaluate(Node* context, ContextState* cs) +{ + return new NodeSet(processorState->getCurrentNode()); +} diff --git a/mozilla/extensions/transformiix/source/xslt/functions/DocumentFunctionCall.cpp b/mozilla/extensions/transformiix/source/xslt/functions/DocumentFunctionCall.cpp index e3a14093c13..e808d6c283d 100644 --- a/mozilla/extensions/transformiix/source/xslt/functions/DocumentFunctionCall.cpp +++ b/mozilla/extensions/transformiix/source/xslt/functions/DocumentFunctionCall.cpp @@ -92,7 +92,6 @@ ExprResult* DocumentFunctionCall::evaluate(Node* context, ContextState* cs) NodeSet* nodeSet2 = (NodeSet*) exprResult2; if (!nodeSet2->isEmpty()) { - mProcessorState->sortByDocumentOrder(nodeSet2); baseURI = nodeSet2->get(0)->getBaseURI(); } delete exprResult2; diff --git a/mozilla/extensions/transformiix/source/xslt/functions/GenerateIdFunctionCall.cpp b/mozilla/extensions/transformiix/source/xslt/functions/GenerateIdFunctionCall.cpp index 3fa3fe8774e..59331770397 100644 --- a/mozilla/extensions/transformiix/source/xslt/functions/GenerateIdFunctionCall.cpp +++ b/mozilla/extensions/transformiix/source/xslt/functions/GenerateIdFunctionCall.cpp @@ -81,10 +81,11 @@ ExprResult* GenerateIdFunctionCall::evaluate(Node* aContext, } NodeSet* nodes = (NodeSet*) exprResult; - if (nodes->size() > 0) { - aCs->sortByDocumentOrder(nodes); - node = nodes->get(0); - } + if (nodes->isEmpty()) + return new StringResult(); + + node = nodes->get(0); + delete exprResult; } else { @@ -93,15 +94,10 @@ ExprResult* GenerateIdFunctionCall::evaluate(Node* aContext, // generate id for selected node char buf[22]; - if (node) { #ifdef TX_EXE - sprintf(buf, printfFmt, node); + sprintf(buf, printfFmt, node); #else - PR_snprintf(buf, 21, printfFmt, node); + PR_snprintf(buf, 21, printfFmt, node); #endif - } - else { - buf[0] = 0; - } return new StringResult(buf); } diff --git a/mozilla/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp b/mozilla/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp index 4c7fdc79a39..0792360cb65 100644 --- a/mozilla/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp +++ b/mozilla/extensions/transformiix/source/xslt/functions/txKeyFunctionCall.cpp @@ -46,15 +46,15 @@ txKeyFunctionCall::txKeyFunctionCall(ProcessorState* aPs) : */ ExprResult* txKeyFunctionCall::evaluate(Node* aContext, ContextState* aCs) { + if (!aContext || !requireParams(2, 2, aCs)) + return new StringResult("error"); + NodeSet* res = new NodeSet; if (!res) { // ErrorReport: out of memory - return NULL; + return 0; } - if (!requireParams(2, 2, aCs)) - return res; - ListIterator iter(¶ms); String keyName; evaluateToString((Expr*)iter.next(), aContext, aCs, keyName); @@ -83,13 +83,13 @@ ExprResult* txKeyFunctionCall::evaluate(Node* aContext, ContextState* aCs) for (int i=0; isize(); i++) { String val; XMLDOMUtils::getNodeValue(nodeSet->get(i), val); - key->getNodes(val,contextDoc)->copyInto(*res); + res->add(key->getNodes(val, contextDoc)); } } else { String val; exprResult->stringValue(val); - key->getNodes(val,contextDoc)->copyInto(*res); + res->append(key->getNodes(val, contextDoc)); } delete exprResult; return res; @@ -227,8 +227,7 @@ void txXSLKey::testNode(Node* aNode, NamedMap* aMap) { Key* key=(Key*)iter.next(); if (key->matchPattern->matches(aNode, 0, mProcessorState)) { - NodeSet contextNodeSet; - contextNodeSet.add(aNode); + NodeSet contextNodeSet(aNode); mProcessorState->getNodeSetStack()->push(&contextNodeSet); mProcessorState->pushCurrentNode(aNode); ExprResult* exprResult = key->useExpr->evaluate(aNode, mProcessorState); @@ -247,7 +246,7 @@ void txXSLKey::testNode(Node* aNode, NamedMap* aMap) return; aMap->put(val, nodeSet); } - nodeSet->add(aNode); + nodeSet->append(aNode); } } else { @@ -259,7 +258,7 @@ void txXSLKey::testNode(Node* aNode, NamedMap* aMap) return; aMap->put(val, nodeSet); } - nodeSet->add(aNode); + nodeSet->append(aNode); } delete exprResult; } diff --git a/mozilla/extensions/transformiix/source/xslt/txRtfHandler.cpp b/mozilla/extensions/transformiix/source/xslt/txRtfHandler.cpp index e93075999e2..0f3b1bff067 100644 --- a/mozilla/extensions/transformiix/source/xslt/txRtfHandler.cpp +++ b/mozilla/extensions/transformiix/source/xslt/txRtfHandler.cpp @@ -54,7 +54,7 @@ txRtfHandler::txRtfHandler(Document* aDocument, DocumentFragment* fragment = mDocument->createDocumentFragment(); NS_ASSERTION(fragment, "Out of memory creating a document fragmen"); // XXX ErrorReport: Out of memory - mResultTreeFragment->add(fragment); + mResultTreeFragment->append(fragment); mCurrentNode = fragment; } diff --git a/mozilla/extensions/transformiix/source/xslt/util/txNodeSorter.cpp b/mozilla/extensions/transformiix/source/xslt/util/txNodeSorter.cpp index cccf9e08c8d..1ad4e335420 100644 --- a/mozilla/extensions/transformiix/source/xslt/util/txNodeSorter.cpp +++ b/mozilla/extensions/transformiix/source/xslt/util/txNodeSorter.cpp @@ -199,15 +199,13 @@ MBool txNodeSorter::sortNodeSet(NodeSet* aNodes) // Note that the nodeset shouldn't be changed until the sort is done // since it's the current-nodeset used during xpath evaluation aNodes->clear(); - aNodes->setDuplicateChecking(MB_FALSE); iter.reset(); while (iter.hasNext()) { SortableNode* sNode = (SortableNode*)iter.next(); - aNodes->add(sNode->mNode); + aNodes->append(sNode->mNode); sNode->clear(mNKeys); delete sNode; } - aNodes->setDuplicateChecking(MB_TRUE); return MB_TRUE; }