Merge branch 'master' into clone

This commit is contained in:
Lee Thomason 2017-06-14 15:10:37 -07:00
commit 1bbc66b193
4 changed files with 130 additions and 15 deletions

View File

@ -23,19 +23,9 @@ include(GNUInstallDirs)
set(GENERIC_LIB_VERSION "4.0.1") set(GENERIC_LIB_VERSION "4.0.1")
set(GENERIC_LIB_SOVERSION "4") set(GENERIC_LIB_SOVERSION "4")
################################
# Add common source
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/.")
################################ ################################
# Add definitions # Add definitions
if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif(MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG")
################################ ################################
@ -65,11 +55,29 @@ set_target_properties(tinyxml2 PROPERTIES
VERSION "${GENERIC_LIB_VERSION}" VERSION "${GENERIC_LIB_VERSION}"
SOVERSION "${GENERIC_LIB_SOVERSION}") SOVERSION "${GENERIC_LIB_SOVERSION}")
if(DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") 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() endif()
# export targets for find_package config mode
export(TARGETS tinyxml2
FILE ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)
install(TARGETS tinyxml2 install(TARGETS tinyxml2
EXPORT ${CMAKE_PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
@ -83,11 +91,30 @@ set_target_properties(tinyxml2_static PROPERTIES
SOVERSION "${GENERIC_LIB_SOVERSION}") SOVERSION "${GENERIC_LIB_SOVERSION}")
set_target_properties( tinyxml2_static PROPERTIES OUTPUT_NAME tinyxml2 ) 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") 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() 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 install(TARGETS tinyxml2_static
EXPORT ${CMAKE_PROJECT_NAME}Targets
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
@ -131,3 +158,14 @@ configure_file(
add_custom_target(uninstall add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) 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})

View File

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

View File

@ -264,6 +264,13 @@ public:
return _allocated; return _allocated;
} }
void SwapRemove(int i) {
TIXMLASSERT(i >= 0);
TIXMLASSERT(i < _size);
_mem[i] = _mem[_size - 1];
--_size;
}
const T* Mem() const { const T* Mem() const {
TIXMLASSERT( _mem ); TIXMLASSERT( _mem );
return _mem; return _mem;
@ -1826,6 +1833,9 @@ public:
// internal // internal
char* Identify( char* p, XMLNode** node ); char* Identify( char* p, XMLNode** node );
// internal
void MarkInUse(XMLNode*);
virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const { virtual XMLNode* ShallowClone( XMLDocument* /*document*/ ) const {
return 0; return 0;
} }
@ -1846,6 +1856,13 @@ private:
int _errorLineNum; int _errorLineNum;
char* _charBuffer; char* _charBuffer;
int _parseCurLineNum; 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(XMLElement) > _elementPool;
MemPoolT< sizeof(XMLAttribute) > _attributePool; MemPoolT< sizeof(XMLAttribute) > _attributePool;
@ -1868,6 +1885,8 @@ inline NodeType* XMLDocument::CreateUnlinkedNode( MemPoolT<PoolElementSize>& poo
NodeType* returnNode = new (pool.Alloc()) NodeType( this ); NodeType* returnNode = new (pool.Alloc()) NodeType( this );
TIXMLASSERT( returnNode ); TIXMLASSERT( returnNode );
returnNode->_memPool = &pool; returnNode->_memPool = &pool;
_unlinked.Push(returnNode);
return returnNode; return returnNode;
} }
@ -2201,6 +2220,7 @@ public:
void ClearBuffer() { void ClearBuffer() {
_buffer.Clear(); _buffer.Clear();
_buffer.Push(0); _buffer.Push(0);
_firstElement = true;
} }
protected: protected:

View File

@ -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 -------------- // ----------- Line Number Tracking --------------
{ {
struct TestUtil: XMLVisitor struct TestUtil: XMLVisitor