XPath: Fix reallocate_nothrow to preserve existing state

Instead of rolling back the allocation and trying to allocate again,
explicitly handle inplace reallocate if possible, and allocate a new
block otherwise.

This is going to be important once we use reallocate_nothrow from a
non-throwing context.
This commit is contained in:
Arseny Kapoulkine 2017-01-30 22:10:13 -08:00
parent 1a2e4b88ee
commit c370d1190d

View File

@ -7456,33 +7456,35 @@ PUGI__NS_BEGIN
// we can only reallocate the last object // we can only reallocate the last object
assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size); assert(ptr == 0 || static_cast<char*>(ptr) + old_size == &_root->data[0] + _root_size);
// adjust root size so that we have not allocated the object at all // try to reallocate the object inplace
bool only_object = (_root_size == old_size); if (ptr && _root_size - old_size + new_size <= _root->capacity)
{
_root_size = _root_size - old_size + new_size;
return ptr;
}
if (ptr) _root_size -= old_size; // allocate a new block
// allocate a new version (this will obviously reuse the memory if possible)
void* result = allocate_nothrow(new_size); void* result = allocate_nothrow(new_size);
if (!result) return 0; if (!result) return 0;
// we have a new block // we have a new block
if (result != ptr && ptr) if (ptr)
{ {
// copy old data // copy old data (we only support growing)
assert(new_size >= old_size); assert(new_size >= old_size);
memcpy(result, ptr, old_size); memcpy(result, ptr, old_size);
// free the previous page if it had no other objects // free the previous page if it had no other objects
if (only_object)
{
assert(_root->data == result); assert(_root->data == result);
assert(_root->next); assert(_root->next);
if (_root->next->data == ptr)
{
// deallocate the whole page, unless it was the first one
xpath_memory_block* next = _root->next->next; xpath_memory_block* next = _root->next->next;
if (next) if (next)
{ {
// deallocate the whole page, unless it was the first one
xml_memory::deallocate(_root->next); xml_memory::deallocate(_root->next);
_root->next = next; _root->next = next;
} }