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
This commit is contained in:
parent
9ec7db4c0c
commit
bc5901dd28
@ -1327,12 +1327,40 @@ namespace
|
|||||||
}
|
}
|
||||||
#endif
|
#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)
|
bool strcpy_insitu(char_t*& dest, uintptr_t& header, uintptr_t header_mask, const char_t* source)
|
||||||
{
|
{
|
||||||
size_t source_length = impl::strlen(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));
|
memcpy(dest, source, (source_length + 1) * sizeof(char_t));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1341,13 +1369,17 @@ namespace
|
|||||||
{
|
{
|
||||||
xml_allocator* alloc = reinterpret_cast<xml_memory_page*>(header & xml_memory_page_pointer_mask)->allocator;
|
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);
|
char_t* buf = alloc->allocate_string(source_length + 1);
|
||||||
if (!buf) return false;
|
if (!buf) return false;
|
||||||
|
|
||||||
|
// copy the string (including zero terminator)
|
||||||
memcpy(buf, source, (source_length + 1) * sizeof(char_t));
|
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);
|
if (header & header_mask) alloc->deallocate_string(dest);
|
||||||
|
|
||||||
|
// the string is now allocated, so set the flag
|
||||||
dest = buf;
|
dest = buf;
|
||||||
header |= header_mask;
|
header |= header_mask;
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user