more refactoring. cleaning out container classes.

This commit is contained in:
Lee Thomason 2012-01-31 08:24:24 -08:00
parent 1270ae58e4
commit 2c85a711f1
3 changed files with 236 additions and 109 deletions

View File

@ -95,6 +95,32 @@ const char* StrPair::GetStr()
return start; return start;
} }
/*
const char* StringPool::Intern( const char* str )
{
// Treat the array as a linear, inplace hash table.
// Nothing can get deleted, so that's handy.
if ( size > pool.Size()*3/4 ) {
DynArray< const char*, 20 > store;
for( int i=0; i<pool.Size(); ++i ) {
if ( pool[i] != 0 ) {
store.Push( pool[i] );
}
}
int newSize = pool.Size() * 2;
pool.PopArr( pool.Size() );
const char** mem = pool.PushArr( newSize );
memset( (void*)mem, 0, sizeof(char)*newSize );
while ( !store.Empty() ) {
Intern( store.Pop() );
}
}
}
*/
// --------- XMLBase ----------- // // --------- XMLBase ----------- //
// fixme: should take in the entity/newline flags as param // fixme: should take in the entity/newline flags as param
@ -279,6 +305,20 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
} }
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 ) ) {
return element;
}
}
}
return 0;
}
void XMLNode::Print( XMLStreamer* streamer ) void XMLNode::Print( XMLStreamer* streamer )
{ {
for( XMLNode* node = firstChild; node; node=node->next ) { for( XMLNode* node = firstChild; node; node=node->next ) {
@ -530,6 +570,14 @@ void XMLDocument::InitDocument()
} }
XMLElement* XMLDocument::NewElement( const char* name )
{
XMLElement* ele = new XMLElement( this );
ele->SetName( name );
return ele;
}
int XMLDocument::Parse( const char* p ) int XMLDocument::Parse( const char* p )
{ {
ClearChildren(); ClearChildren();
@ -568,6 +616,7 @@ void XMLDocument::SetError( int error, const char* str1, const char* str2 )
} }
/*
StringStack::StringStack() StringStack::StringStack()
{ {
nPositive = 0; nPositive = 0;
@ -602,6 +651,7 @@ const char* StringStack::Pop() {
mem.PopArr( strlen(p)+1 ); mem.PopArr( strlen(p)+1 );
return p+1; return p+1;
} }
*/
XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false ) XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
@ -664,11 +714,11 @@ void XMLStreamer::OpenElement( const char* name, bool textParent )
if ( elementJustOpened ) { if ( elementJustOpened ) {
SealElement(); SealElement();
} }
if ( text.NumPositive() == 0 ) { if ( !TextOnStack() ) {
PrintSpace( depth ); PrintSpace( depth );
} }
stack.Push( name ); stack.Push( name );
text.Push( textParent ? "T" : "" ); text.Push( textParent ? 'T' : 'e' );
// fixme: can names have entities? // fixme: can names have entities?
fprintf( fp, "<%s", name ); fprintf( fp, "<%s", name );
@ -690,22 +740,22 @@ void XMLStreamer::CloseElement()
{ {
--depth; --depth;
const char* name = stack.Pop(); const char* name = stack.Pop();
int wasPositive = text.NumPositive(); bool wasText = TextOnStack();
text.Pop(); text.Pop();
if ( elementJustOpened ) { if ( elementJustOpened ) {
fprintf( fp, "/>" ); fprintf( fp, "/>" );
if ( text.NumPositive() == 0 ) { if ( !wasText ) {
fprintf( fp, "\n" ); fprintf( fp, "\n" );
} }
} }
else { else {
if ( wasPositive == 0 ) { if ( !wasText ) {
PrintSpace( depth ); PrintSpace( depth );
} }
// fixme can names have entities? // fixme can names have entities?
fprintf( fp, "</%s>", name ); fprintf( fp, "</%s>", name );
if ( text.NumPositive() == 0 ) { if ( !TextOnStack() ) {
fprintf( fp, "\n" ); fprintf( fp, "\n" );
} }
} }
@ -717,7 +767,7 @@ void XMLStreamer::SealElement()
{ {
elementJustOpened = false; elementJustOpened = false;
fprintf( fp, ">" ); fprintf( fp, ">" );
if ( text.NumPositive() == 0 ) { if ( !TextOnStack() ) {
fprintf( fp, "\n" ); fprintf( fp, "\n" );
} }
} }

View File

@ -1,9 +1,23 @@
#ifndef TINYXML2_INCLUDED #ifndef TINYXML2_INCLUDED
#define TINYXML2_INCLUDED #define TINYXML2_INCLUDED
/*
TODO
- const and non-const versions of API
- memory pool the class construction
- attribute accessors
- node navigation
- handles
- visit pattern - change streamer?
- make constructors protected
- hide copy constructor
- hide = operator
*/
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <memory.h>
#if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__) #if defined( _DEBUG ) || defined( DEBUG ) || defined (__DEBUG__)
#ifndef DEBUG #ifndef DEBUG
@ -38,18 +52,6 @@ class XMLText;
class XMLStreamer; class XMLStreamer;
/*
// internal - move to separate namespace
struct CharBuffer
{
size_t length;
char mem[1];
static CharBuffer* Construct( const char* in );
static void Free( CharBuffer* );
};
*/
class StrPair class StrPair
{ {
public: public:
@ -70,6 +72,8 @@ public:
const char* GetStr(); const char* GetStr();
bool Empty() const { return start == end; } bool Empty() const { return start == end; }
void SetInternedStr( const char* str ) { this->start = (char*) str; this->end = 0; this->flags = 0; }
private: private:
enum { enum {
NEEDS_FLUSH = 0x100 NEEDS_FLUSH = 0x100
@ -82,6 +86,121 @@ private:
}; };
template <class T, int INIT>
class DynArray
{
public:
DynArray< T, INIT >()
{
mem = pool;
allocated = INIT;
size = 0;
}
~DynArray()
{
if ( mem != pool ) {
delete mem;
}
}
void Push( T t )
{
EnsureCapacity( size+1 );
mem[size++] = t;
}
T* PushArr( int count )
{
EnsureCapacity( size+count );
T* ret = &mem[size];
size += count;
return ret;
}
T Pop() {
return mem[--size];
}
void PopArr( int count )
{
TIXMLASSERT( size >= count );
size -= count;
}
bool Empty() const { return size == 0; }
T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
int Size() const { return size; }
const T* Mem() const { return mem; }
T* Mem() { return mem; }
private:
void EnsureCapacity( int cap ) {
if ( cap > allocated ) {
int newAllocated = cap * 2;
T* newMem = new T[newAllocated];
memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
if ( mem != pool ) delete [] mem;
mem = newMem;
allocated = newAllocated;
}
}
T* mem;
T pool[INIT];
int allocated; // objects allocated
int size; // number objects in use
};
/*
class StringStack
{
public:
StringStack();
virtual ~StringStack();
void Push( const char* str );
const char* Pop();
int NumPositive() const { return nPositive; }
private:
DynArray< char, 50 > mem;
int nPositive; // number of strings with len > 0
};
*/
/*
class StringPool
{
public:
enum { INIT_SIZE=20 };
StringPool() : size( 0 ) {
const char** mem = pool.PushArr( INIT_SIZE );
memset( (void*)mem, 0, sizeof(char)*INIT_SIZE );
}
~StringPool() {}
const char* Intern( const char* str );
private:
// FNV hash
int Hash( const char* s ) {
#define FNV_32_PRIME ((int)0x01000193)
int hval = 0;
while (*s) {
hval *= FNV_32_PRIME;
hval ^= (int)*s++;
}
return hval;
}
int size;
DynArray< const char*, INIT_SIZE > pool; // the hash table
StringStack store; // memory for the interned strings
};
*/
class XMLBase class XMLBase
{ {
public: public:
@ -125,10 +244,16 @@ public:
XMLNode* InsertEndChild( XMLNode* addThis ); XMLNode* InsertEndChild( XMLNode* addThis );
virtual void Print( XMLStreamer* streamer ); virtual void Print( XMLStreamer* streamer );
const char* Value() const { return value.GetStr(); }
void SetValue( const char* val ) { value.SetInternedStr( val ); }
virtual XMLElement* ToElement() { return 0; } virtual XMLElement* ToElement() { return 0; }
virtual XMLText* ToText() { return 0; } virtual XMLText* ToText() { return 0; }
virtual XMLComment* ToComment() { return 0; } virtual XMLComment* ToComment() { return 0; }
XMLNode* FirstChild() { return firstChild; }
XMLElement* FirstChildElement( const char* value=0 );
// fixme: guarentee null terminator to avoid internal checks // fixme: guarentee null terminator to avoid internal checks
virtual char* ParseDeep( char* ); virtual char* ParseDeep( char* );
@ -143,6 +268,7 @@ protected:
XMLDocument* document; XMLDocument* document;
XMLNode* parent; XMLNode* parent;
bool isTextParent; bool isTextParent;
mutable StrPair value;
XMLNode* firstChild; XMLNode* firstChild;
XMLNode* lastChild; XMLNode* lastChild;
@ -157,29 +283,31 @@ private:
class XMLText : public XMLNode class XMLText : public XMLNode
{ {
friend class XMLBase;
friend class XMLDocument;
public: public:
XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
virtual ~XMLText() {} virtual ~XMLText() {}
virtual void Print( XMLStreamer* streamer ); virtual void Print( XMLStreamer* streamer );
const char* Value() { return value.GetStr(); } const char* Value() { return value.GetStr(); }
void SetValue( const char* );
virtual XMLText* ToText() { return this; } virtual XMLText* ToText() { return this; }
char* ParseDeep( char* ); char* ParseDeep( char* );
protected: protected:
XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
private: private:
StrPair value;
}; };
class XMLComment : public XMLNode class XMLComment : public XMLNode
{ {
friend class XMLBase;
friend class XMLDocument;
public: public:
XMLComment( XMLDocument* doc );
virtual ~XMLComment(); virtual ~XMLComment();
virtual void Print( XMLStreamer* ); virtual void Print( XMLStreamer* );
virtual XMLComment* ToComment() { return this; } virtual XMLComment* ToComment() { return this; }
@ -188,9 +316,10 @@ public:
char* ParseDeep( char* ); char* ParseDeep( char* );
protected: protected:
XMLComment( XMLDocument* doc );
private: private:
StrPair value;
}; };
@ -213,24 +342,29 @@ private:
class XMLElement : public XMLNode class XMLElement : public XMLNode
{ {
friend class XMLBase;
friend class XMLDocument;
public: public:
XMLElement( XMLDocument* doc );
virtual ~XMLElement(); virtual ~XMLElement();
const char* Name() { return name.GetStr(); } const char* Name() const { return Value(); }
void SetName( const char* str ) { SetValue( str ); }
virtual void Print( XMLStreamer* ); virtual void Print( XMLStreamer* );
virtual XMLElement* ToElement() { return this; } virtual XMLElement* ToElement() { return this; }
virtual bool IsClosingElement() const { return closing; }
// internal:
virtual bool IsClosingElement() const { return closing; }
char* ParseDeep( char* p ); char* ParseDeep( char* p );
protected: protected:
XMLElement( XMLDocument* doc );
private: private:
char* ParseAttributes( char* p, bool *closedElement ); char* ParseAttributes( char* p, bool *closedElement );
StrPair name; mutable StrPair name;
bool closing; bool closing;
XMLAttribute* rootAttribute; XMLAttribute* rootAttribute;
XMLAttribute* lastAttribute; XMLAttribute* lastAttribute;
@ -249,6 +383,8 @@ public:
void Print( XMLStreamer* streamer=0 ); void Print( XMLStreamer* streamer=0 );
XMLElement* NewElement( const char* name );
enum { enum {
NO_ERROR = 0, NO_ERROR = 0,
ERROR_ELEMENT_MISMATCH, ERROR_ELEMENT_MISMATCH,
@ -262,6 +398,8 @@ public:
const char* GetErrorStr1() const { return errorStr1; } const char* GetErrorStr1() const { return errorStr1; }
const char* GetErrorStr2() const { return errorStr2; } const char* GetErrorStr2() const { return errorStr2; }
// const char* Intern( const char* );
private: private:
XMLDocument( const XMLDocument& ); // intentionally not implemented XMLDocument( const XMLDocument& ); // intentionally not implemented
void InitDocument(); void InitDocument();
@ -270,84 +408,7 @@ private:
const char* errorStr1; const char* errorStr1;
const char* errorStr2; const char* errorStr2;
char* charBuffer; char* charBuffer;
}; //StringStack stringPool;
template <class T, int INIT>
class DynArray
{
public:
DynArray< T, INIT >()
{
mem = pool;
allocated = INIT;
size = 0;
}
~DynArray()
{
if ( mem != pool ) {
delete mem;
}
}
void Push( T t )
{
EnsureCapacity( size+1 );
mem[size++] = t;
}
T* PushArr( int count )
{
EnsureCapacity( size+count );
T* ret = &mem[size];
size += count;
return ret;
}
T Pop() {
return mem[--size];
}
void PopArr( int count )
{
TIXMLASSERT( size >= count );
size -= count;
}
int Size() const { return size; }
const T* Mem() const { return mem; }
T* Mem() { return mem; }
private:
void EnsureCapacity( int cap ) {
if ( cap > allocated ) {
int newAllocated = cap * 2;
T* newMem = new T[newAllocated];
memcpy( newMem, mem, sizeof(T)*size ); // warning: not using constructors, only works for PODs
if ( mem != pool ) delete [] mem;
mem = newMem;
allocated = newAllocated;
}
}
T* mem;
T pool[INIT];
int allocated; // objects allocated
int size; // number objects in use
};
class StringStack
{
public:
StringStack();
virtual ~StringStack();
void Push( const char* str );
const char* Pop();
int NumPositive() const { return nPositive; }
private:
DynArray< char, 50 > mem;
int nPositive; // number of strings with len > 0
}; };
@ -368,6 +429,13 @@ private:
void SealElement(); void SealElement();
void PrintSpace( int depth ); void PrintSpace( int depth );
void PrintString( const char* ); // prints out, after detecting entities. void PrintString( const char* ); // prints out, after detecting entities.
bool TextOnStack() const {
for( int i=0; i<text.Size(); ++i ) {
if ( text[i] == 'T' )
return true;
}
return false;
}
FILE* fp; FILE* fp;
int depth; int depth;
@ -377,8 +445,8 @@ private:
}; };
bool entityFlag[ENTITY_RANGE]; bool entityFlag[ENTITY_RANGE];
DynArray< const char*, 40 > stack; DynArray< const char*, 10 > stack;
StringStack text; DynArray< char, 10 > text;
}; };

View File

@ -52,5 +52,14 @@ int main( int argc, const char* argv )
printf( "----------------------------------------------\n" ); printf( "----------------------------------------------\n" );
} }
} }
{
static const char* test = "<element>Text before.</element>";
XMLDocument doc;
doc.Parse( test );
XMLElement* root = doc.FirstChildElement();
XMLElement* newElement = doc.NewElement( "Subelement" );
root->InsertEndChild( newElement );
doc.Print();
}
return 0; return 0;
} }