Better attribute system. Removes redundant list searching of LinkAttribute. Faster parsing on initial read. Added badly needed missing test cases.
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 4ce9b32..fbeca4e 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -1092,34 +1092,33 @@
 }

 

 

-

 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )

 {

-	XMLAttribute* attrib = FindAttribute( name );

+	XMLAttribute* last = 0;

+	XMLAttribute* attrib = 0;

+	for( attrib = rootAttribute;

+		 attrib;

+		 last = attrib, attrib = attrib->next )

+	{		 

+		if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {

+			break;

+		}

+	}

 	if ( !attrib ) {

 		attrib = new (document->attributePool.Alloc() ) XMLAttribute();

 		attrib->memPool = &document->attributePool;

-		LinkAttribute( attrib );

+		if ( last ) {

+			last->next = attrib;

+		}

+		else {

+			rootAttribute = attrib;

+		}

 		attrib->SetName( name );

 	}

 	return attrib;

 }

 

 

-void XMLElement::LinkAttribute( XMLAttribute* attrib )

-{

-	if ( rootAttribute ) {

-		XMLAttribute* end = rootAttribute;

-		while ( end->next )

-			end = end->next;

-		end->next = attrib;

-	}

-	else {

-		rootAttribute = attrib;

-	}

-}

-

-

 void XMLElement::DeleteAttribute( const char* name )

 {

 	XMLAttribute* prev = 0;

@@ -1142,6 +1141,7 @@
 char* XMLElement::ParseAttributes( char* p )

 {

 	const char* start = p;

+	XMLAttribute* prevAttribute = 0;

 

 	// Read the attributes.

 	while( p ) {

@@ -1162,7 +1162,19 @@
 				document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );

 				return 0;

 			}

-			LinkAttribute( attrib );

+			// There is a minor bug here: if the attribute in the source xml

+			// document is duplicated, it will not be detected and the

+			// attribute will be doubly added. However, tracking the 'prevAttribute'

+			// avoids re-scanning the attribute list. Preferring performance for

+			// now, may reconsider in the future.

+			if ( prevAttribute ) { 

+				prevAttribute->next = attrib;

+				prevAttribute = attrib;

+			}

+			else {

+				rootAttribute = attrib;

+				prevAttribute = rootAttribute;

+			}	

 		}

 		// end of the tag

 		else if ( *p == '/' && *(p+1) == '>' ) {

diff --git a/tinyxml2.h b/tinyxml2.h
index 76e47ac..4ebb87f 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -24,25 +24,13 @@
 #ifndef TINYXML2_INCLUDED

 #define TINYXML2_INCLUDED

 

-#if 1

-	#include <cctype>

-	#include <climits>

-	#include <cstdio>

-	#include <cstring>

-	#include <cstdarg>

-#else

-	// Not completely sure all the interesting systems

-	// can handle the new headers; can switch this if

-	// there is an include problem.

-	#include <limits.h>

-	#include <ctype.h>

-	#include <stdio.h>

-	#include <memory.h>		// Needed by mac.

-#endif

-

+#include <cctype>

+#include <climits>

+#include <cstdio>

+#include <cstring>

+#include <cstdarg>

 

 /* 

-   TODO: add 'lastAttribute' for faster parsing.

    TODO: intern strings instead of allocation.

 */

 /*

@@ -978,10 +966,13 @@
 

 	XMLAttribute* FindAttribute( const char* name );

 	XMLAttribute* FindOrCreateAttribute( const char* name );

-	void LinkAttribute( XMLAttribute* attrib );

+	//void LinkAttribute( XMLAttribute* attrib );

 	char* ParseAttributes( char* p );

 

 	int closingType;

+	// The attribute list is ordered; there is no 'lastAttribute'

+	// because the list needs to be scanned for dupes before adding

+	// a new attribute.

 	XMLAttribute* rootAttribute;

 };

 

diff --git a/xmltest.cpp b/xmltest.cpp
index 0991e2d..a88d1bc 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -760,6 +760,32 @@
 		}

 		XMLTest( "Error in snprinf handling.", true, doc.Error() );

 	}

+	

+	{

+		// Attribute ordering.

+		static const char* xml = "<element attrib1=\"1\" attrib2=\"2\" attrib3=\"3\" />";

+		XMLDocument doc;

+		doc.Parse( xml );

+		XMLElement* ele = doc.FirstChildElement();

+		

+		const XMLAttribute* a = ele->FirstAttribute();

+		XMLTest( "Attribute order", "1", a->Value() );

+		a = a->Next();

+		XMLTest( "Attribute order", "2", a->Value() );

+		a = a->Next();

+		XMLTest( "Attribute order", "3", a->Value() );

+		XMLTest( "Attribute order", "attrib3", a->Name() );

+		

+		ele->DeleteAttribute( "attrib2" );

+		a = ele->FirstAttribute();

+		XMLTest( "Attribute order", "1", a->Value() );

+		a = a->Next();

+		XMLTest( "Attribute order", "3", a->Value() );

+		

+		ele->DeleteAttribute( "attrib1" );

+		ele->DeleteAttribute( "attrib3" );

+		XMLTest( "Attribute order (empty)", false, ele->FirstAttribute() ? true : false );

+	}

 

 	// -------- Handles ------------

 	{