Przeglądaj źródła

finally have the placement new working as desired.

Lee Thomason 14 lat temu
rodzic
commit
d198322032
3 zmienionych plików z 155 dodań i 40 usunięć
  1. 47 25
      tinyxml2.cpp
  2. 102 15
      tinyxml2.h
  3. 6 0
      xmltest.cpp

+ 47 - 25
tinyxml2.cpp

@@ -4,6 +4,9 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <new.h>
+
+//#pragma warning ( disable : 4291 )
 
 using namespace tinyxml2;
 
@@ -123,7 +126,7 @@ const char* StringPool::Intern( const char* str )
 
 
 // --------- XMLBase ----------- //
-// fixme: should take in the entity/newline flags as param
+
 char* XMLBase::ParseText( char* p, StrPair* pair, const char* endTag, int strFlags )
 {
 	TIXMLASSERT( endTag && *endTag );
@@ -175,11 +178,11 @@ char* XMLBase::ParseName( char* p, StrPair* pair )
 }
 
 
-char* XMLBase::Identify( XMLDocument* document, char* p, XMLNode** node ) 
+char* XMLDocument::Identify( char* p, XMLNode** node ) 
 {
 	XMLNode* returnNode = 0;
 	char* start = p;
-	p = XMLNode::SkipWhiteSpace( p );
+	p = XMLBase::SkipWhiteSpace( p );
 	if( !p || !*p )
 	{
 		return 0;
@@ -204,18 +207,20 @@ char* XMLBase::Identify( XMLDocument* document, char* p, XMLNode** node )
 	static const int cdataHeaderLen		= 9;
 	static const int elementHeaderLen	= 1;
 
-	if ( StringEqual( p, commentHeader, commentHeaderLen ) ) {
-		returnNode = new XMLComment( document );
+	if ( XMLBase::StringEqual( p, commentHeader, commentHeaderLen ) ) {
+		returnNode = new (commentPool.Alloc()) XMLComment( this );
+		returnNode->memPool = &commentPool;
 		p += commentHeaderLen;
 	}
-	else if ( StringEqual( p, elementHeader, elementHeaderLen ) ) {
-		returnNode = new XMLElement( document );
+	else if ( XMLBase::StringEqual( p, elementHeader, elementHeaderLen ) ) {
+		returnNode = new (elementPool.Alloc()) XMLElement( this );
+		returnNode->memPool = &elementPool;
 		p += elementHeaderLen;
 	}
 	// fixme: better text detection
-	else if ( (*p != '<') && IsAlphaNum( *p ) ) {
-		// fixme: this is filtering out empty text...should it?
-		returnNode = new XMLText( document );
+	else if ( (*p != '<') && XMLBase::IsAlphaNum( *p ) ) {
+		returnNode = new (textPool.Alloc()) XMLText( this );
+		returnNode->memPool = &textPool;
 		p = start;	// Back it up, all the text counts.
 	}
 	else {
@@ -254,7 +259,13 @@ void XMLNode::ClearChildren()
 	while( firstChild ) {
 		XMLNode* node = firstChild;
 		Unlink( node );
-		delete node;
+		
+		//delete node;
+		// placement new!
+		MemPool* pool = node->memPool;
+		node->~XMLNode();
+		pool->Free( node );
+		// fixme: memory never free'd. 
 	}
 	firstChild = lastChild = 0;
 }
@@ -310,7 +321,7 @@ XMLElement* XMLNode::FirstChildElement( const char* value )
 	for( XMLNode* node=firstChild; node; node=node->next ) {
 		XMLElement* element = node->ToElement();
 		if ( element ) {
-			if ( !value || StringEqual( element->Name(), value ) ) {
+			if ( !value || XMLBase::StringEqual( element->Name(), value ) ) {
 				return element;
 			}
 		}
@@ -331,12 +342,15 @@ char* XMLNode::ParseDeep( char* p )
 {
 	while( p && *p ) {
 		XMLNode* node = 0;
-		p = Identify( document, p, &node );
+		p = document->Identify( p, &node );
 		if ( p && node ) {
 			p = node->ParseDeep( p );
 			// FIXME: is it the correct closing element?
 			if ( node->IsClosingElement() ) {
-				delete node;
+				//delete node;
+				MemPool* pool = node->memPool;
+				node->~XMLNode();	// fixme linked list memory not free
+				pool->Free( node );
 				return p;
 			}
 			this->InsertEndChild( node );
@@ -348,7 +362,7 @@ char* XMLNode::ParseDeep( char* p )
 // --------- XMLText ---------- //
 char* XMLText::ParseDeep( char* p )
 {
-	p = ParseText( p, &value, "<", StrPair::TEXT_ELEMENT );
+	p = XMLBase::ParseText( p, &value, "<", StrPair::TEXT_ELEMENT );
 	// consumes the end tag.
 	if ( p && *p ) {
 		return p-1;
@@ -388,19 +402,19 @@ void XMLComment::Print( XMLStreamer* streamer )
 char* XMLComment::ParseDeep( char* p )
 {
 	// Comment parses as text.
-	return ParseText( p, &value, "-->", StrPair::COMMENT );
+	return XMLBase::ParseText( p, &value, "-->", StrPair::COMMENT );
 }
 
 
 // --------- XMLAttribute ---------- //
 char* XMLAttribute::ParseDeep( char* p )
 {
-	p = ParseText( p, &name, "=", StrPair::ATTRIBUTE_NAME );
+	p = XMLBase::ParseText( p, &name, "=", StrPair::ATTRIBUTE_NAME );
 	if ( !p || !*p ) return 0;
 
 	char endTag[2] = { *p, 0 };
 	++p;
-	p = ParseText( p, &value, endTag, StrPair::ATTRIBUTE_VALUE );
+	p = XMLBase::ParseText( p, &value, endTag, StrPair::ATTRIBUTE_VALUE );
 	if ( value.Empty() ) return 0;
 	return p;
 }
@@ -443,15 +457,16 @@ char* XMLElement::ParseAttributes( char* p, bool* closedElement )
 
 	// Read the attributes.
 	while( p ) {
-		p = SkipWhiteSpace( p );
+		p = XMLBase::SkipWhiteSpace( p );
 		if ( !p || !(*p) ) {
-			document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, name.GetStr() );
+			document->SetError( XMLDocument::ERROR_PARSING_ELEMENT, start, Name() );
 			return 0;
 		}
 
 		// attribute.
-		if ( IsAlpha( *p ) ) {
+		if ( XMLBase::IsAlpha( *p ) ) {
 			XMLAttribute* attrib = new XMLAttribute( this );
+
 			p = attrib->ParseDeep( p );
 			if ( !p ) {
 				delete attrib;
@@ -497,7 +512,7 @@ char* XMLElement::ParseAttributes( char* p, bool* closedElement )
 char* XMLElement::ParseDeep( char* p )
 {
 	// Read the element name.
-	p = SkipWhiteSpace( p );
+	p = XMLBase::SkipWhiteSpace( p );
 	if ( !p ) return 0;
 	const char* start = p;
 
@@ -509,8 +524,8 @@ char* XMLElement::ParseDeep( char* p )
 		++p;
 	}
 
-	p = ParseName( p, &name );
-	if ( name.Empty() ) return 0;
+	p = XMLBase::ParseName( p, &value );
+	if ( value.Empty() ) return 0;
 
 	bool elementClosed=false;
 	p = ParseAttributes( p, &elementClosed );
@@ -554,7 +569,13 @@ XMLDocument::XMLDocument() :
 
 XMLDocument::~XMLDocument()
 {
+	ClearChildren();
 	delete [] charBuffer;
+
+	TIXMLASSERT( textPool.NAlloc() == 0 );
+	TIXMLASSERT( elementPool.NAlloc() == 0 );
+	TIXMLASSERT( commentPool.NAlloc() == 0 );
+	TIXMLASSERT( attributePool.NAlloc() == 0 );
 }
 
 
@@ -572,7 +593,8 @@ void XMLDocument::InitDocument()
 
 XMLElement* XMLDocument::NewElement( const char* name )
 {
-	XMLElement* ele = new XMLElement( this );
+	XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
+	ele->memPool = &elementPool;
 	ele->SetName( name );
 	return ele;
 }

+ 102 - 15
tinyxml2.h

@@ -12,6 +12,17 @@
 	- make constructors protected
 	- hide copy constructor
 	- hide = operator
+	- #define to remove mem-pooling, and make thread safe
+	- UTF8 support: isAlpha, etc.
+
+	(No reason to ever cast to base)
+	XMLBase -> Utility
+
+	XMLNode
+		Document
+		Pooled
+			Element
+			Text
 */
 
 #include <limits.h>
@@ -150,6 +161,72 @@ private:
 	int size;			// number objects in use
 };
 
+class MemPool
+{
+public:
+	MemPool() {}
+	virtual ~MemPool() {}
+
+	virtual int ItemSize() const = 0;
+	virtual void* Alloc() = 0;
+	virtual void Free( void* ) = 0; 
+};
+
+template< int SIZE >
+class MemPoolT : public MemPool
+{
+public:
+	MemPoolT() : root( 0 ), nAlloc( 0 )	{}
+	~MemPoolT() {
+		// Delete the blocks.
+		for( int i=0; i<blockPtrs.Size(); ++i ) {
+			delete blockPtrs[i];
+		}
+	}
+
+	virtual int ItemSize() const	{ return SIZE; }
+	int NAlloc() const				{ return nAlloc; }
+
+	virtual void* Alloc() {
+		if ( !root ) {
+			// Need a new block.
+			Block* block = new Block();
+			blockPtrs.Push( block );
+
+			for( int i=0; i<COUNT-1; ++i ) {
+				block->chunk[i].next = &block->chunk[i+1];
+			}
+			block->chunk[COUNT-1].next = 0;
+			root = block->chunk;
+		}
+		void* result = root;
+		root = root->next;
+		++nAlloc;
+		return result;
+	}
+	virtual void Free( void* mem ) {
+		if ( !mem ) return;
+		--nAlloc;
+		Chunk* chunk = (Chunk*)mem;
+		memset( chunk, 0xfe, sizeof(Chunk) );
+		chunk->next = root;
+		root = chunk;
+	}
+
+private:
+	enum { COUNT = 1024/SIZE };
+	union Chunk {
+		Chunk* next;
+		char mem[SIZE];
+	};
+	struct Block {
+		Chunk chunk[COUNT];
+	};
+	DynArray< Block*, 10 > blockPtrs;
+	Chunk* root;
+	int nAlloc;
+};
+
 
 /*
 class StringStack
@@ -203,11 +280,12 @@ private:
 
 class XMLBase
 {
+public:
+
 public:
 	XMLBase() {}
 	virtual ~XMLBase() {}
 
-protected:
 	static const char* SkipWhiteSpace( const char* p )	{ while( isspace( *p ) ) { ++p; } return p; }
 	static char* SkipWhiteSpace( char* p )				{ while( isspace( *p ) ) { ++p; } return p; }
 
@@ -228,18 +306,20 @@ protected:
 	inline static int IsAlphaNum( unsigned char anyByte )	{ return ( anyByte <= 127 ) ? isalnum( anyByte ) : 1; }
 	inline static int IsAlpha( unsigned char anyByte )		{ return ( anyByte <= 127 ) ? isalpha( anyByte ) : 1; }
 
-	char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );
-	char* ParseName( char* in, StrPair* pair );
-	char* Identify( XMLDocument* document, char* p, XMLNode** node );
+	static char* ParseText( char* in, StrPair* pair, const char* endTag, int strFlags );
+	static char* ParseName( char* in, StrPair* pair );
+
+private:
 };
 
 
-class XMLNode : public XMLBase
+class XMLNode
 {
 	friend class XMLDocument;
 	friend class XMLElement;
 public:
-	virtual ~XMLNode();
+	//void* operator new( size_t size, MemPool* pool );
+	//void operator delete( void* mem, MemPool* pool );
 
 	XMLNode* InsertEndChild( XMLNode* addThis );
 	virtual void Print( XMLStreamer* streamer );
@@ -263,6 +343,8 @@ public:
 
 protected:
 	XMLNode( XMLDocument* );
+	virtual ~XMLNode();
+	
 	void ClearChildren();
 
 	XMLDocument*	document;
@@ -277,6 +359,7 @@ protected:
 	XMLNode*		next;
 
 private:
+	MemPool*		memPool;
 	void Unlink( XMLNode* child );
 };
 
@@ -286,7 +369,6 @@ class XMLText : public XMLNode
 	friend class XMLBase;
 	friend class XMLDocument;
 public:
-	virtual ~XMLText()								{}
 	virtual void Print( XMLStreamer* streamer );
 	const char* Value() { return value.GetStr(); }
 	void SetValue( const char* );
@@ -297,6 +379,7 @@ public:
 
 protected:
 	XMLText( XMLDocument* doc )	: XMLNode( doc )	{}
+	virtual ~XMLText()								{}
 
 private:
 };
@@ -307,7 +390,6 @@ class XMLComment : public XMLNode
 	friend class XMLBase;
 	friend class XMLDocument;
 public:
-	virtual ~XMLComment();
 	virtual void Print( XMLStreamer* );
 	virtual XMLComment*	ToComment()		{ return this; }
 
@@ -317,7 +399,7 @@ public:
 
 protected:
 	XMLComment( XMLDocument* doc );
-
+	virtual ~XMLComment();
 
 private:
 };
@@ -327,11 +409,11 @@ class XMLAttribute : public XMLBase
 {
 	friend class XMLElement;
 public:
-	XMLAttribute( XMLElement* element ) : next( 0 ) {}
-	virtual ~XMLAttribute()	{}
 	virtual void Print( XMLStreamer* streamer );
 
 private:
+	XMLAttribute( XMLElement* element ) : next( 0 ) {}
+	virtual ~XMLAttribute()	{}
 	char* ParseDeep( char* p );
 
 	StrPair name;
@@ -345,8 +427,6 @@ class XMLElement : public XMLNode
 	friend class XMLBase;
 	friend class XMLDocument;
 public:
-	virtual ~XMLElement();
-
 	const char* Name() const		{ return Value(); }
 	void SetName( const char* str )	{ SetValue( str ); }
 
@@ -360,11 +440,11 @@ public:
 
 protected:
 	XMLElement( XMLDocument* doc );
+	virtual ~XMLElement();
 
 private:
 	char* ParseAttributes( char* p, bool *closedElement );
 
-	mutable StrPair name;
 	bool closing;
 	XMLAttribute* rootAttribute;
 	XMLAttribute* lastAttribute;
@@ -373,6 +453,7 @@ private:
 
 class XMLDocument : public XMLNode
 {
+	friend class XMLElement;
 public:
 	XMLDocument(); 
 	~XMLDocument();
@@ -398,9 +479,10 @@ public:
 	const char* GetErrorStr1() const { return errorStr1; }
 	const char* GetErrorStr2() const { return errorStr2; }
 
-//	const char* Intern( const char* );
+	char* Identify( char* p, XMLNode** node );
 
 private:
+
 	XMLDocument( const XMLDocument& );	// intentionally not implemented
 	void InitDocument();
 
@@ -409,6 +491,11 @@ private:
 	const char* errorStr2;
 	char* charBuffer;
 	//StringStack stringPool;
+
+	MemPoolT< sizeof(XMLElement) >	elementPool;
+	MemPoolT< sizeof(XMLAttribute) > attributePool;
+	MemPoolT< sizeof(XMLText) >		textPool;
+	MemPoolT< sizeof(XMLComment) >	commentPool;
 };
 
 

+ 6 - 0
xmltest.cpp

@@ -61,5 +61,11 @@ int main( int argc, const char* argv )
 		root->InsertEndChild( newElement );
 		doc.Print();
 	}
+	{
+		XMLDocument* doc = new XMLDocument();
+		static const char* test = "<element><sub/></element>";
+		doc->Parse( test );
+		delete doc;
+	}
 	return 0;
 }