summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArseny Kapoulkine <arseny.kapoulkine@gmail.com>2017-01-30 22:10:13 -0800
committerArseny Kapoulkine <arseny.kapoulkine@gmail.com>2017-01-30 22:10:13 -0800
commitc370d1190d3c1ac5ea59f0824db500f32a8594bd (patch)
treebeec0734f8ed616b74351319ba715131a860dc88
parent1a2e4b88ee091613d2978fb2d23ce146416d3413 (diff)
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.
-rw-r--r--src/pugixml.cpp26
1 files changed, 14 insertions, 12 deletions
diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 56cd941..7a44105 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -7456,33 +7456,35 @@ PUGI__NS_BEGIN
// we can only reallocate the last object
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
- bool only_object = (_root_size == old_size);
-
- if (ptr) _root_size -= old_size;
+ // try to reallocate the object inplace
+ if (ptr && _root_size - old_size + new_size <= _root->capacity)
+ {
+ _root_size = _root_size - old_size + new_size;
+ return ptr;
+ }
- // allocate a new version (this will obviously reuse the memory if possible)
+ // allocate a new block
void* result = allocate_nothrow(new_size);
if (!result) return 0;
// 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);
memcpy(result, ptr, old_size);
// free the previous page if it had no other objects
- if (only_object)
- {
- assert(_root->data == result);
- assert(_root->next);
+ assert(_root->data == result);
+ 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;
if (next)
{
- // deallocate the whole page, unless it was the first one
xml_memory::deallocate(_root->next);
_root->next = next;
}