From 3d6615b2764da759c5b9354c40cd1a32b84ee039 Mon Sep 17 00:00:00 2001 From: Jay Berkenbilt Date: Sun, 12 Aug 2018 17:26:40 -0400 Subject: Pl_Buffer: reduce memory growth (fixes #228) Rather than keeping a list of buffers for every write, accumulate bytes in a single buffer, doubling the size of the buffer when needed to accommodate new data. This is not the best possible implementation, but the change was implemented in this way to avoid changing the shape of Pl_Buffer and thus breaking backward compatibility. --- libqpdf/Pl_Buffer.cc | 43 ++++++++++++++++++++++++++++++------------- 1 file changed, 30 insertions(+), 13 deletions(-) (limited to 'libqpdf/Pl_Buffer.cc') diff --git a/libqpdf/Pl_Buffer.cc b/libqpdf/Pl_Buffer.cc index 45c0c862..1ca9292d 100644 --- a/libqpdf/Pl_Buffer.cc +++ b/libqpdf/Pl_Buffer.cc @@ -17,11 +17,32 @@ Pl_Buffer::~Pl_Buffer() void Pl_Buffer::write(unsigned char* buf, size_t len) { - Buffer* b = new Buffer(len); - memcpy(b->getBuffer(), buf, len); - this->data.push_back(b); + PointerHolder cur_buf; + size_t cur_size = 0; + if (! this->data.empty()) + { + cur_buf = this->data.back(); + cur_size = cur_buf->getSize(); + } + size_t left = cur_size - this->total_size; + if (left < len) + { + size_t new_size = std::max(this->total_size + len, 2 * cur_size); + Buffer* b = new Buffer(new_size); + if (cur_buf.getPointer()) + { + memcpy(b->getBuffer(), cur_buf->getBuffer(), this->total_size); + } + this->data.clear(); + cur_buf = b; + this->data.push_back(cur_buf); + } + if (len) + { + memcpy(cur_buf->getBuffer() + this->total_size, buf, len); + this->total_size += len; + } this->ready = false; - this->total_size += len; if (getNext(true)) { @@ -49,17 +70,13 @@ Pl_Buffer::getBuffer() Buffer* b = new Buffer(this->total_size); unsigned char* p = b->getBuffer(); - while (! this->data.empty()) + if (! this->data.empty()) { - PointerHolder bp = this->data.front(); - this->data.pop_front(); - size_t bytes = bp->getSize(); - memcpy(p, bp->getBuffer(), bytes); - p += bytes; - this->total_size -= bytes; + PointerHolder bp = this->data.back(); + this->data.clear(); + memcpy(p, bp->getBuffer(), this->total_size); } - - assert(this->total_size == 0); + this->total_size = 0; this->ready = false; return b; -- cgit v1.2.3-70-g09d2