You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by db...@apache.org on 2001/01/16 03:52:36 UTC
cvs commit: xml-xalan/c/src/XalanSourceTree XalanSourceTreeContentHandler.cpp XalanSourceTreeContentHandler.hpp XalanSourceTreeHelper.cpp XalanSourceTreeHelper.hpp
dbertoni 01/01/15 18:52:36
Modified: c/src/XalanSourceTree XalanSourceTreeContentHandler.cpp
XalanSourceTreeContentHandler.hpp
XalanSourceTreeHelper.cpp XalanSourceTreeHelper.hpp
Log:
Cache last node appended to fix major performance degradation with broad documents.
Revision Changes Path
1.4 +111 -32 xml-xalan/c/src/XalanSourceTree/XalanSourceTreeContentHandler.cpp
Index: XalanSourceTreeContentHandler.cpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XalanSourceTree/XalanSourceTreeContentHandler.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- XalanSourceTreeContentHandler.cpp 2000/12/29 03:23:26 1.3
+++ XalanSourceTreeContentHandler.cpp 2001/01/16 02:52:35 1.4
@@ -68,6 +68,7 @@
#include "XalanSourceTreeDocument.hpp"
#include "XalanSourceTreeElement.hpp"
+#include "XalanSourceTreeHelper.hpp"
@@ -80,6 +81,8 @@
m_document(theDocument),
m_currentElement(0),
m_elementStack(),
+ m_lastChild(0),
+ m_lastChildStack(),
m_ownsDocument(false),
m_accumulateText(fAccumulateText),
m_textBuffer()
@@ -125,7 +128,12 @@
void
XalanSourceTreeContentHandler::endDocument()
{
+ // Pop off the dummy value that we pushed in
+ // startDocument()...
+ m_elementStack.pop_back();
+
assert(m_elementStack.empty() == true);
+ assert(m_lastChildStack.empty() == true);
assert(isEmpty(m_textBuffer) == true);
}
@@ -138,6 +146,7 @@
const XMLCh* const /* localname */,
const XMLCh* const /* qname */)
{
+ // Process any text that we may have accumulated...
processAccumulatedText();
assert(m_elementStack.empty() == false);
@@ -145,20 +154,71 @@
// Pop the element of the stack...
m_elementStack.pop_back();
+ assert(m_elementStack.empty() == false);
+
// Get the element from the back of the
- // stack, if any...
- if (m_elementStack.empty() == false)
+ // stack.
+ m_currentElement = m_elementStack.back();
+
+ assert(m_lastChildStack.empty() == false);
+
+ m_lastChild = m_lastChildStack.back();
+
+ // Pop the last child stack
+ m_lastChildStack.pop_back();
+}
+
+
+
+// A helper function to manage appending the new child.
+template <class ParentNodeType, class ChildNodeType>
+inline void
+doAppendChildNode(
+ ParentNodeType* theParent,
+ XalanNode*& theLastChild,
+ ChildNodeType theNewChild)
+{
+ assert(theParent != 0);
+ assert(theNewChild != 0);
+
+ if (theLastChild == 0)
{
- m_currentElement = m_elementStack.back();
+ theParent->appendChildNode(theNewChild);
}
else
{
- m_currentElement = 0;
+ XalanSourceTreeHelper::appendSibling(theLastChild, theNewChild);
}
+
+ theLastChild = theNewChild;
}
+// A helper function to manage appending the new child.
+template <class ChildNodeType>
+inline void
+doAppendChildNode(
+ XalanSourceTreeDocument* theDocument,
+ XalanSourceTreeElement* theCurrentElement,
+ XalanNode*& theLastChild,
+ ChildNodeType theNewChild)
+{
+ assert(theDocument != 0);
+ assert(theNewChild != 0);
+
+ if (theCurrentElement == 0)
+ {
+ doAppendChildNode(theDocument, theLastChild, theNewChild);
+ }
+ else
+ {
+ doAppendChildNode(theCurrentElement, theLastChild, theNewChild);
+ }
+}
+
+
+
void
XalanSourceTreeContentHandler::ignorableWhitespace(
const XMLCh* const chars,
@@ -167,9 +227,14 @@
// Ignore any whitespace reported before the document element has been parsed.
if (m_elementStack.empty() == false)
{
+ assert(m_currentElement != 0);
+
processAccumulatedText();
+
+ XalanSourceTreeText* theNewTextNode =
+ m_document->createTextIWSNode(chars, length, m_currentElement);
- m_currentElement->appendChildNode(m_document->createTextIWSNode(chars, length, m_currentElement));
+ doAppendChildNode(m_currentElement, m_lastChild, theNewTextNode);
}
}
@@ -180,18 +245,16 @@
const XMLCh* const target,
const XMLCh* const data)
{
- if (m_currentElement == 0)
- {
- assert(m_document != 0);
+ processAccumulatedText();
- m_document->appendChildNode(m_document->createProcessingInstructionNode(target, data));
- }
- else
- {
- processAccumulatedText();
+ XalanSourceTreeProcessingInstruction* const theNewPI =
+ m_document->createProcessingInstructionNode(target, data, m_currentElement);
- m_currentElement->appendChildNode(m_document->createProcessingInstructionNode(target, data, m_currentElement));
- }
+ doAppendChildNode(
+ m_document,
+ m_currentElement,
+ m_lastChild,
+ theNewPI);
}
@@ -206,6 +269,7 @@
void
XalanSourceTreeContentHandler::startDocument()
{
+ // Clean up and reset everything...
if (m_document == 0)
{
m_document = new XalanSourceTreeDocument;
@@ -217,16 +281,28 @@
m_document = new XalanSourceTreeDocument;
}
+ m_currentElement = 0;
+
m_elementStack.clear();
m_elementStack.reserve(eDefaultStackSize);
+ m_lastChild = 0;
+
+ m_lastChildStack.clear();
+
+ m_lastChildStack.reserve(eDefaultStackSize);
+
if (m_accumulateText == true)
{
clear(m_textBuffer);
reserve(m_textBuffer, eDefaultTextBufferSize);
}
+
+ // Push a dummy value for the current element, so we
+ // don't have to check for an empty stack in endElement().
+ m_elementStack.push_back(0);
}
@@ -243,18 +319,19 @@
XalanSourceTreeElement* const theNewElement =
createElement(uri, localname, qname, attrs, m_currentElement);
- if (m_currentElement == 0)
- {
- m_document->appendChildNode(theNewElement);
- }
- else
- {
- m_currentElement->appendChildNode(theNewElement);
- }
+ doAppendChildNode(
+ m_document,
+ m_currentElement,
+ m_lastChild,
+ theNewElement);
m_elementStack.push_back(theNewElement);
+ m_lastChildStack.push_back(m_lastChild);
+
m_currentElement = theNewElement;
+
+ m_lastChild = 0;
}
@@ -325,14 +402,11 @@
XalanSourceTreeComment* const theNewComment =
m_document->createCommentNode(chars, length, m_currentElement);
- if (m_currentElement != 0)
- {
- m_currentElement->appendChildNode(theNewComment);
- }
- else
- {
- m_document->appendChildNode(theNewComment);
- }
+ doAppendChildNode(
+ m_document,
+ m_currentElement,
+ m_lastChild,
+ theNewComment);
}
@@ -451,5 +525,10 @@
const XMLCh* chars,
unsigned int length)
{
- m_currentElement->appendChildNode(m_document->createTextNode(chars, length, m_currentElement));
+ assert(m_currentElement != 0);
+
+ XalanSourceTreeText* theNewTextNode =
+ m_document->createTextNode(chars, length, m_currentElement);
+
+ doAppendChildNode(m_currentElement, m_lastChild, theNewTextNode);
}
1.4 +23 -0 xml-xalan/c/src/XalanSourceTree/XalanSourceTreeContentHandler.hpp
Index: XalanSourceTreeContentHandler.hpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XalanSourceTree/XalanSourceTreeContentHandler.hpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- XalanSourceTreeContentHandler.hpp 2000/12/29 03:23:26 1.3
+++ XalanSourceTreeContentHandler.hpp 2001/01/16 02:52:35 1.4
@@ -78,6 +78,7 @@
+class XalanNode;
class XalanSourceTreeDocument;
class XalanSourceTreeElement;
@@ -90,8 +91,10 @@
#if defined(XALAN_NO_NAMESPACES)
typedef vector<XalanSourceTreeElement*> ElementStackType;
+ typedef vector<XalanNode*> LastChildStackType;
#else
typedef std::vector<XalanSourceTreeElement*> ElementStackType;
+ typedef std::vector<XalanNode*> LastChildStackType;
#endif
enum { eDefaultStackSize = 50, eDefaultTextBufferSize = 100 };
@@ -250,16 +253,36 @@
// Data members...
+
+ // The current document we're building...
XalanSourceTreeDocument* m_document;
+ // The current element...
XalanSourceTreeElement* m_currentElement;
+ // Stack of elements...
ElementStackType m_elementStack;
+ // The last child appended to the current element. This is
+ // an important optimization, because XalanSourceTreeElement
+ // does not have a pointer to it's last child. Without this,
+ // appending a child becomes a linear search.
+ XalanNode* m_lastChild;
+
+ // Stack of last children appended. There is a ono-to-one
+ // correspondance to the entries in m_elementStack.
+ LastChildStackType m_lastChildStack;
+
+ // If true, the instance owns the document and will delete
+ // it when necessary.
bool m_ownsDocument;
+ // If true, the handler will accumulate text from calls to
+ // characters() until another event triggers the creation
+ // of the node.
const bool m_accumulateText;
+ // A buffer to hold accumulated text.
XalanDOMString m_textBuffer;
};
1.4 +114 -21 xml-xalan/c/src/XalanSourceTree/XalanSourceTreeHelper.cpp
Index: XalanSourceTreeHelper.cpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XalanSourceTree/XalanSourceTreeHelper.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- XalanSourceTreeHelper.cpp 2000/12/19 02:34:28 1.3
+++ XalanSourceTreeHelper.cpp 2001/01/16 02:52:35 1.4
@@ -126,13 +126,13 @@
template<class NodeType>
inline void
doAppendSibling(
- XalanNode* theNode,
+ XalanNode* theSibling,
NodeType* theNewSibling)
{
- assert(theNode != 0);
+ assert(theSibling != 0);
assert(theNewSibling != 0);
- XalanNode* const theLastSibling = XalanSourceTreeHelper::getLastSibling(theNode);
+ XalanNode* const theLastSibling = XalanSourceTreeHelper::getLastSibling(theSibling);
switch(theLastSibling->getNodeType())
{
@@ -160,6 +160,42 @@
+template<class NodeType>
+inline void
+doAppendToLastSibling(
+ XalanNode* theLastSibling,
+ NodeType* theNewSibling)
+{
+ assert(theLastSibling != 0);
+ assert(theNewSibling != 0);
+ assert(theLastSibling->getNextSibling() == 0);
+
+ switch(theLastSibling->getNodeType())
+ {
+ case XalanNode::COMMENT_NODE:
+ castToComment(theLastSibling)->appendSiblingNode(theNewSibling);
+ break;
+
+ case XalanNode::ELEMENT_NODE:
+ castToElement(theLastSibling)->appendSiblingNode(theNewSibling);
+ break;
+
+ case XalanNode::PROCESSING_INSTRUCTION_NODE:
+ castToProcessingInstruction(theLastSibling)->appendSiblingNode(theNewSibling);
+ break;
+
+ case XalanNode::TEXT_NODE:
+ castToText(theLastSibling)->appendSiblingNode(theNewSibling);
+ break;
+
+ default:
+ throw XalanDOMException(XalanDOMException::HIERARCHY_REQUEST_ERR);
+ break;
+ }
+}
+
+
+
template <class NodeType1, class NodeType2>
inline void
append(
@@ -317,6 +353,70 @@
+void
+XalanSourceTreeHelper::appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeComment* theNewLastSibling)
+{
+ doAppendToLastSibling(theLastSibling, theNewLastSibling);
+}
+
+
+
+void
+XalanSourceTreeHelper::appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeElement* theNewLastSibling)
+{
+ doAppendToLastSibling(theLastSibling, theNewLastSibling);
+}
+
+
+
+void
+XalanSourceTreeHelper::appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeProcessingInstruction* theNewLastSibling)
+{
+ doAppendToLastSibling(theLastSibling, theNewLastSibling);
+}
+
+
+
+void
+XalanSourceTreeHelper::appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeText* theNewLastSibling)
+{
+ doAppendToLastSibling(theLastSibling, theNewLastSibling);
+}
+
+
+
+XalanNode*
+doGetLastSibling(XalanNode* theNode)
+{
+ if (theNode == 0)
+ {
+ return 0;
+ }
+ else
+ {
+ XalanNode* theNextSibling = theNode->getNextSibling();
+
+ while(theNextSibling != 0)
+ {
+ theNode = theNextSibling;
+
+ theNextSibling = theNode->getNextSibling();
+ }
+
+ return theNode;
+ }
+}
+
+
+
template <class NodeType>
void
doAppendSiblingToChild(
@@ -332,7 +432,16 @@
theNewSibling->setParentElement(theOwnerElement);
}
- append(theFirstChildSlot, theNewSibling);
+ if (theFirstChildSlot == 0)
+ {
+ append(theFirstChildSlot, theNewSibling);
+ }
+ else
+ {
+ XalanNode* const theLastSibling = doGetLastSibling(theFirstChildSlot);
+
+ doAppendSibling(theLastSibling, theNewSibling);
+ }
}
@@ -385,21 +494,5 @@
XalanNode*
XalanSourceTreeHelper::getLastSibling(XalanNode* theNode)
{
- if (theNode == 0)
- {
- return 0;
- }
- else
- {
- XalanNode* theNextSibling = theNode->getNextSibling();
-
- while(theNextSibling != 0)
- {
- theNode = theNextSibling;
-
- theNextSibling = theNode->getNextSibling();
- }
-
- return theNode;
- }
+ return doGetLastSibling(theNode);
}
1.3 +23 -8 xml-xalan/c/src/XalanSourceTree/XalanSourceTreeHelper.hpp
Index: XalanSourceTreeHelper.hpp
===================================================================
RCS file: /home/cvs/xml-xalan/c/src/XalanSourceTree/XalanSourceTreeHelper.hpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- XalanSourceTreeHelper.hpp 2000/12/17 22:26:59 1.2
+++ XalanSourceTreeHelper.hpp 2001/01/16 02:52:35 1.3
@@ -80,17 +80,9 @@
{
public:
- friend class XalanSourceTreeComment;
- friend class XalanSourceTreeDocument;
- friend class XalanSourceTreeElement;
- friend class XalanSourceTreeProcessingInstruction;
- friend class XalanSourceTreeText;
-
static XalanNode*
getLastSibling(XalanNode* theNode);
-private:
-
static void
appendSibling(
XalanSourceTreeDocument* theDocument,
@@ -121,11 +113,34 @@
XalanNode*& theNextSiblingSlot,
XalanNode* theNewSibling);
+ // New appendSibling interfaces...
+ static void
+ appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeComment* theNewLastSibling);
+
+ static void
+ appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeElement* theNewLastSibling);
+
static void
+ appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeProcessingInstruction* theNewLastSibling);
+
+ static void
+ appendSibling(
+ XalanNode* theLastSibling,
+ XalanSourceTreeText* theNewLastSibling);
+
+
+ static void
appendSiblingToChild(
XalanSourceTreeElement* theOwnerElement,
XalanNode*& theChildSlot,
XalanSourceTreeComment* theNewSibling);
+
static void
appendSiblingToChild(