diff options
author | arseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640> | 2010-08-29 15:19:22 +0000 |
---|---|---|
committer | arseny.kapoulkine <arseny.kapoulkine@99668b35-9821-0410-8761-19e4c4f06640> | 2010-08-29 15:19:22 +0000 |
commit | bc5901dd28b9a277d20c640bed519457c67beb5c (patch) | |
tree | 8f33fa21e4ac0fd3a661831796cf3a0d1bbd31d7 | |
parent | 9ec7db4c0cdf945eddb30a1630dcc96fd3763b1c (diff) |
strcpy_insitu improvements: empty string forces deallocation, memory is reclaimed if waste is too great (small string is copied to the large buffer)
git-svn-id: http://pugixml.googlecode.com/svn/trunk@654 99668b35-9821-0410-8761-19e4c4f06640
-rw-r--r-- | src/pugixml.cpp | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp index c9b0046..c6f74e7 100644 --- a/src/pugixml.cpp +++ b/src/pugixml.cpp @@ -1327,12 +1327,40 @@ namespace } #endif + inline bool strcpy_insitu_allow(size_t length, uintptr_t allocated, char_t* target) + { + assert(target); + size_t target_length = impl::strlen(target); + + // always reuse document buffer memory if possible + if (!allocated) return target_length >= length; + + // reuse heap memory if waste is not too great + const size_t reuse_threshold = 32; + + return target_length >= length && (target_length < reuse_threshold || target_length - length < target_length / 2); + } + bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source) { size_t source_length = impl::strlen(source); - if (dest && impl::strlen(dest) >= source_length) + if (source_length == 0) + { + // empty string and null pointer are equivalent, so just deallocate old memory + xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; + + if (header & header_mask) alloc->deallocate_string(dest); + + // mark the string as not allocated + dest = 0; + header &= ~header_mask; + + return true; + } + else if (dest && strcpy_insitu_allow(source_length, header & header_mask, dest)) { + // we can reuse old buffer, so just copy the new data (including zero terminator) memcpy(dest, source, (source_length + 1) * sizeof(char_t)); return true; @@ -1341,13 +1369,17 @@ namespace { xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator; + // allocate new buffer char_t* buf = alloc->allocate_string(source_length + 1); if (!buf) return false; + // copy the string (including zero terminator) memcpy(buf, source, (source_length + 1) * sizeof(char_t)); + // deallocate old buffer (*after* the above to protect against overlapping memory and/or allocation failures) if (header & header_mask) alloc->deallocate_string(dest); + // the string is now allocated, so set the flag dest = buf; header |= header_mask; |