Просмотр исходного кода

Merge branch 'master' into clone

Lee Thomason 8 лет назад
Родитель
Сommit
1bbc66b193
4 измененных файлов с 130 добавлено и 15 удалено
  1. 50 12
      CMakeLists.txt
  2. 31 3
      tinyxml2.cpp
  3. 20 0
      tinyxml2.h
  4. 29 0
      xmltest.cpp

+ 50 - 12
CMakeLists.txt

@@ -23,19 +23,9 @@ include(GNUInstallDirs)
 set(GENERIC_LIB_VERSION "4.0.1")
 set(GENERIC_LIB_SOVERSION "4")
 
-
-################################
-# Add common source
-
-include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")
-
 ################################
 # Add definitions
 
-if(MSVC)
-	add_definitions(-D_CRT_SECURE_NO_WARNINGS)
-endif(MSVC)
-
 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
 
 ################################
@@ -65,11 +55,29 @@ set_target_properties(tinyxml2 PROPERTIES
 	VERSION "${GENERIC_LIB_VERSION}"
 	SOVERSION "${GENERIC_LIB_SOVERSION}")
 
+
 if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
-    target_include_directories(tinyxml2 INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")
+    target_include_directories(tinyxml2 PUBLIC 
+                          $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
+                          $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
+
+    if(MSVC)
+      target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)
+    endif(MSVC)
+else()
+    include_directories(${PROJECT_SOURCE_DIR})
+
+    if(MSVC)
+      add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+    endif(MSVC)
 endif()
 
+# export targets for find_package config mode
+export(TARGETS tinyxml2
+      FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
+
 install(TARGETS tinyxml2
+        EXPORT ${CMAKE_PROJECT_NAME}Targets
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
@@ -83,11 +91,30 @@ set_target_properties(tinyxml2_static PROPERTIES
         SOVERSION "${GENERIC_LIB_SOVERSION}")
 set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 )
 
+target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)
+
 if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
-    target_include_directories(tinyxml2_static INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/.")
+    target_include_directories(tinyxml2_static PUBLIC 
+                          $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>
+                          $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>)
+
+    if(MSVC)
+      target_compile_definitions(tinyxml2 PUBLIC -D_CRT_SECURE_NO_WARNINGS)
+    endif(MSVC)
+else()
+    include_directories(${PROJECT_SOURCE_DIR})
+
+    if(MSVC)
+      add_definitions(-D_CRT_SECURE_NO_WARNINGS)
+    endif(MSVC)
 endif()
 
+# export targets for find_package config mode
+export(TARGETS tinyxml2_static
+      FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
+
 install(TARGETS tinyxml2_static
+        EXPORT ${CMAKE_PROJECT_NAME}Targets
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
         LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
         ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
@@ -131,3 +158,14 @@ configure_file(
 
 add_custom_target(uninstall
     COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
+
+file(WRITE
+    ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
+    "include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")
+
+install(FILES
+        ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
+        DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
+
+install(EXPORT ${CMAKE_PROJECT_NAME}Targets
+        DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})

+ 31 - 3
tinyxml2.cpp

@@ -809,9 +809,11 @@ void XMLNode::Unlink( XMLNode* child )
 
     if ( child->_prev ) {
         child->_prev->_next = child->_next;
+        child->_prev = 0;
     }
     if ( child->_next ) {
         child->_next->_prev = child->_prev;
+        child->_next = 0;
     }
 	child->_parent = 0;
 }
@@ -823,6 +825,9 @@ void XMLNode::DeleteChild( XMLNode* node )
     TIXMLASSERT( node->_document == _document );
     TIXMLASSERT( node->_parent == this );
     Unlink( node );
+	TIXMLASSERT(node->_prev == 0);
+	TIXMLASSERT(node->_next == 0);
+	TIXMLASSERT(node->_parent == 0);
     DeleteNode( node );
 }
 
@@ -1067,11 +1072,16 @@ char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
     return 0;
 }
 
-void XMLNode::DeleteNode( XMLNode* node )
+/*static*/ void XMLNode::DeleteNode( XMLNode* node )
 {
     if ( node == 0 ) {
         return;
     }
+	TIXMLASSERT(node->_document);
+	if (!node->ToDocument()) {
+		node->_document->MarkInUse(node);
+	}
+
     MemPool* pool = node->_memPool;
     node->~XMLNode();
     pool->Free( node );
@@ -1082,10 +1092,13 @@ void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
     TIXMLASSERT( insertThis );
     TIXMLASSERT( insertThis->_document == _document );
 
-    if ( insertThis->_parent )
+	if (insertThis->_parent) {
         insertThis->_parent->Unlink( insertThis );
-    else
+	}
+	else {
+		insertThis->_document->MarkInUse(insertThis);
         insertThis->_memPool->SetTracked();
+	}
 }
 
 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
@@ -1991,9 +2004,24 @@ XMLDocument::~XMLDocument()
 }
 
 
+void XMLDocument::MarkInUse(XMLNode* node)
+{
+	TIXMLASSERT(node->_parent == 0);
+
+	for (int i = 0; i < _unlinked.Size(); ++i) {
+		if (node == _unlinked[i]) {
+			_unlinked.SwapRemove(i);
+			break;
+		}
+	}
+}
+
 void XMLDocument::Clear()
 {
     DeleteChildren();
+	while( _unlinked.Size()) {
+		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.
+	}
 
 #ifdef DEBUG
     const bool hadError = Error();

+ 20 - 0
tinyxml2.h

@@ -264,6 +264,13 @@ public:
         return _allocated;
     }
 
+	void SwapRemove(int i) {
+        TIXMLASSERT(i >= 0);
+		TIXMLASSERT(i < _size);
+		_mem[i] = _mem[_size - 1];
+		--_size;
+	}
+
     const T* Mem() const				{
         TIXMLASSERT( _mem );
         return _mem;
@@ -1826,6 +1833,9 @@ public:
 	// internal
     char* Identify( char* p, XMLNode** node );
 
+	// internal
+	void MarkInUse(XMLNode*);
+
     virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const	{
         return 0;
     }
@@ -1846,6 +1856,13 @@ private:
     int             _errorLineNum;
     char*			_charBuffer;
     int				_parseCurLineNum;
+	// Memory tracking does add some overhead.
+	// However, the code assumes that you don't
+	// have a bunch of unlinked nodes around.
+	// Therefore it takes less memory to track
+	// in the document vs. a linked list in the XMLNode,
+	// and the performance is the same.
+	DynArray<XMLNode*, 10> _unlinked;
 
     MemPoolT< sizeof(XMLElement) >	 _elementPool;
     MemPoolT< sizeof(XMLAttribute) > _attributePool;
@@ -1868,6 +1885,8 @@ inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& poo
     NodeType* returnNode = new (pool.Alloc()) NodeType( this );
     TIXMLASSERT( returnNode );
     returnNode->_memPool = &pool;
+
+	_unlinked.Push(returnNode);
     return returnNode;
 }
 
@@ -2201,6 +2220,7 @@ public:
     void ClearBuffer() {
         _buffer.Clear();
         _buffer.Push(0);
+		_firstElement = true;
     }
 
 protected:

+ 29 - 0
xmltest.cpp

@@ -1721,6 +1721,35 @@ int main( int argc, const char ** argv )
 		}
 	}
 
+	{
+		// Evil memory leaks. 
+		// If an XMLElement (etc) is allocated via NewElement() (etc.)
+		// and NOT added to the XMLDocument, what happens?
+		//
+		// Previously (buggy):
+		//		The memory would be free'd when the XMLDocument is
+		//      destructed. But the destructor wasn't called, so that
+		//      memory allocated by the XMLElement would not be free'd.
+		//      In practice this meant strings allocated by the XMLElement
+		//      would leak. An edge case, but annoying.
+		// Now:
+		//      The destructor is called. But the list of unlinked nodes
+		//      has to be tracked. This has a minor performance impact
+		//   	that can become significant if you have a lot. (But why
+		//      would you do that?)
+		// The only way to see this bug is in a leak tracker. This
+		// is compiled in by default on Windows Debug.
+		{
+			XMLDocument doc;
+			doc.NewElement("LEAK 1");
+		}
+		{
+			XMLDocument doc;
+			XMLElement* ele = doc.NewElement("LEAK 2");
+			doc.DeleteNode(ele);
+		}
+	}
+
     // ----------- Line Number Tracking --------------
     {
         struct TestUtil: XMLVisitor