Commit afb09d2eaaed64af03021b56f2ef3923dd6fccde

Authored by m-holger
Committed by GitHub
2 parents 88a62f78 82c178b0

Merge pull request #1551 from m-holger/buffer

Refactor Buffer
include/qpdf/Buffer.hh
@@ -25,6 +25,7 @@ @@ -25,6 +25,7 @@
25 #include <cstddef> 25 #include <cstddef>
26 #include <memory> 26 #include <memory>
27 #include <string> 27 #include <string>
  28 +#include <string_view>
28 29
29 class Buffer 30 class Buffer
30 { 31 {
@@ -66,11 +67,34 @@ class Buffer @@ -66,11 +67,34 @@ class Buffer
66 QPDF_DLL 67 QPDF_DLL
67 Buffer copy() const; 68 Buffer copy() const;
68 69
  70 + // Move the content of the Buffer. After calling this method, the Buffer will be empty if the
  71 + // buffer owns its memory. Otherwise, the Buffer will be unchanged.
  72 + QPDF_DLL
  73 + std::string move();
  74 +
  75 + // Return a string_view to the data.
  76 + QPDF_DLL
  77 + std::string_view view() const;
  78 +
  79 + // Return a pointer to the data. NB: Unlike getBuffer, this method returns a valid pointer even
  80 + // if the Buffer is empty.
  81 + QPDF_DLL
  82 + char const* data() const;
  83 +
  84 + // Return a pointer to the data. NB: Unlike getBuffer, this method returns a valid pointer even
  85 + // if the Buffer is empty.
  86 + QPDF_DLL
  87 + char* data();
  88 +
  89 + QPDF_DLL
  90 + bool empty() const;
  91 +
  92 + QPDF_DLL
  93 + size_t size() const;
  94 +
69 private: 95 private:
70 class Members; 96 class Members;
71 97
72 - void copy(Buffer const&);  
73 -  
74 std::unique_ptr<Members> m; 98 std::unique_ptr<Members> m;
75 }; 99 };
76 100
libqpdf/Buffer.cc
@@ -2,75 +2,55 @@ @@ -2,75 +2,55 @@
2 2
3 #include <qpdf/Buffer.hh> 3 #include <qpdf/Buffer.hh>
4 4
5 -#include <cstring>  
6 -  
7 class Buffer::Members 5 class Buffer::Members
8 { 6 {
9 friend class Buffer; 7 friend class Buffer;
10 8
11 public: 9 public:
12 - ~Members();  
13 -  
14 - private:  
15 - Members(size_t size, unsigned char* buf, bool own_memory);  
16 - Members(std::string&& content); 10 + Members() = default;
  11 + // Constructor for Buffers that don't own the memory.
  12 + Members(size_t size, char* buf) :
  13 + size(size),
  14 + buf(buf)
  15 + {
  16 + }
  17 + Members(std::string&& content) :
  18 + str(std::move(content)),
  19 + size(str.size()),
  20 + buf(str.data())
  21 + {
  22 + }
17 Members(Members const&) = delete; 23 Members(Members const&) = delete;
  24 + ~Members() = default;
18 25
  26 + private:
19 std::string str; 27 std::string str;
20 - bool own_memory;  
21 size_t size; 28 size_t size;
22 - unsigned char* buf; 29 + char* buf;
23 }; 30 };
24 31
25 -Buffer::Members::Members(size_t size, unsigned char* buf, bool own_memory) :  
26 - own_memory(own_memory),  
27 - size(size),  
28 - buf(nullptr)  
29 -{  
30 - if (own_memory) {  
31 - this->buf = (size ? new unsigned char[size] : nullptr);  
32 - } else {  
33 - this->buf = buf;  
34 - }  
35 -}  
36 -  
37 -Buffer::Members::Members(std::string&& content) :  
38 - str(std::move(content)),  
39 - own_memory(false),  
40 - size(str.size()),  
41 - buf(reinterpret_cast<unsigned char*>(str.data()))  
42 -{  
43 -}  
44 -  
45 -Buffer::Members::~Members()  
46 -{  
47 - if (this->own_memory) {  
48 - delete[] this->buf;  
49 - }  
50 -}  
51 -  
52 Buffer::Buffer() : 32 Buffer::Buffer() :
53 - m(new Members(0, nullptr, true)) 33 + m(std::make_unique<Members>())
54 { 34 {
55 } 35 }
56 36
57 Buffer::Buffer(size_t size) : 37 Buffer::Buffer(size_t size) :
58 - m(new Members(size, nullptr, true)) 38 + m(std::make_unique<Members>(std::string(size, '\0')))
59 { 39 {
60 } 40 }
61 41
62 Buffer::Buffer(std::string&& content) : 42 Buffer::Buffer(std::string&& content) :
63 - m(new Members(std::move(content))) 43 + m(std::make_unique<Members>(std::move(content)))
64 { 44 {
65 } 45 }
66 46
67 Buffer::Buffer(unsigned char* buf, size_t size) : 47 Buffer::Buffer(unsigned char* buf, size_t size) :
68 - m(new Members(size, buf, false)) 48 + m(std::make_unique<Members>(size, reinterpret_cast<char*>(buf)))
69 { 49 {
70 } 50 }
71 51
72 Buffer::Buffer(std::string& content) : 52 Buffer::Buffer(std::string& content) :
73 - m(new Members(content.size(), reinterpret_cast<unsigned char*>(content.data()), false)) 53 + m(std::make_unique<Members>(content.size(), content.data()))
74 { 54 {
75 } 55 }
76 56
@@ -88,17 +68,6 @@ Buffer::operator=(Buffer&amp;&amp; rhs) noexcept @@ -88,17 +68,6 @@ Buffer::operator=(Buffer&amp;&amp; rhs) noexcept
88 68
89 Buffer::~Buffer() = default; 69 Buffer::~Buffer() = default;
90 70
91 -void  
92 -Buffer::copy(Buffer const& rhs)  
93 -{  
94 - if (this != &rhs) {  
95 - m = std::unique_ptr<Members>(new Members(rhs.m->size, nullptr, true));  
96 - if (m->size) {  
97 - memcpy(m->buf, rhs.m->buf, m->size);  
98 - }  
99 - }  
100 -}  
101 -  
102 size_t 71 size_t
103 Buffer::getSize() const 72 Buffer::getSize() const
104 { 73 {
@@ -108,21 +77,67 @@ Buffer::getSize() const @@ -108,21 +77,67 @@ Buffer::getSize() const
108 unsigned char const* 77 unsigned char const*
109 Buffer::getBuffer() const 78 Buffer::getBuffer() const
110 { 79 {
111 - return m->buf; 80 + return reinterpret_cast<unsigned char*>(m->buf);
112 } 81 }
113 82
114 unsigned char* 83 unsigned char*
115 Buffer::getBuffer() 84 Buffer::getBuffer()
116 { 85 {
117 - return m->buf; 86 + return reinterpret_cast<unsigned char*>(m->buf);
118 } 87 }
119 88
120 Buffer 89 Buffer
121 Buffer::copy() const 90 Buffer::copy() const
122 { 91 {
123 - auto result = Buffer(m->size);  
124 - if (m->size) {  
125 - memcpy(result.m->buf, m->buf, m->size); 92 + if (m->size == 0) {
  93 + return {};
  94 + }
  95 + return {std::string(m->buf, m->size)};
  96 +}
  97 +
  98 +std::string
  99 +Buffer::move()
  100 +{
  101 + if (m->size == 0) {
  102 + return {};
126 } 103 }
127 - return result; 104 + if (!m->str.empty()) {
  105 + m->size = 0;
  106 + m->buf = nullptr;
  107 + return std::move(m->str);
  108 + }
  109 + return {m->buf, m->size};
  110 +}
  111 +
  112 +std::string_view
  113 +Buffer::view() const
  114 +{
  115 + if (!m->buf) {
  116 + return {};
  117 + }
  118 + return {m->buf, m->size};
  119 +}
  120 +
  121 +char const*
  122 +Buffer::data() const
  123 +{
  124 + return m->buf ? m->buf : m->str.data();
  125 +}
  126 +
  127 +char*
  128 +Buffer::data()
  129 +{
  130 + return m->buf ? m->buf : m->str.data();
  131 +}
  132 +
  133 +bool
  134 +Buffer::empty() const
  135 +{
  136 + return m->size == 0;
  137 +}
  138 +
  139 +size_t
  140 +Buffer::size() const
  141 +{
  142 + return m->size;
128 } 143 }
libtests/buffer.cc
@@ -35,6 +35,37 @@ main() @@ -35,6 +35,37 @@ main()
35 assert(bc2p[0] == 'R'); 35 assert(bc2p[0] == 'R');
36 assert(bc2p[1] == 'W'); 36 assert(bc2p[1] == 'W');
37 37
  38 + // Test move, view, data, empty and size methods
  39 + assert(bc1.view() == "RW");
  40 + assert(std::string_view(bc1.data(), bc1.getSize()) == "RW");
  41 + *bc1.data() = 'Z';
  42 + assert(!bc1.empty());
  43 + assert(bc1.size() == 2);
  44 + auto s1 = bc1.move();
  45 + assert(bc1.empty());
  46 + assert(bc1.size() == 0);
  47 + assert(!bc1.getBuffer());
  48 + assert(bc1.getSize() == 0);
  49 + assert(s1 == "ZW");
  50 + assert(bc1.view().empty());
  51 + assert(bc1.data());
  52 + assert(Buffer(s1).move() == "ZW");
  53 + assert(s1 == "ZW");
  54 +
  55 + // Test const methods
  56 + const Buffer cb(s1);
  57 + assert(*cb.data() == 'Z');
  58 + assert(*(cb.getBuffer() + 1) == 'W');
  59 +
  60 + // Test constructors
  61 + assert(Buffer().empty());
  62 + assert(Buffer().copy().empty());
  63 + assert(!Buffer().getBuffer());
  64 + assert(Buffer().data());
  65 + assert(Buffer().move().empty());
  66 + assert(Buffer(s1).size() == 2);
  67 + assert(*Buffer(s1).data() == 'Z');
  68 +
38 // Test Buffer(std:string&&) 69 // Test Buffer(std:string&&)
39 Buffer bc3("QW"); 70 Buffer bc3("QW");
40 unsigned char* bc3p = bc3.getBuffer(); 71 unsigned char* bc3p = bc3.getBuffer();
manual/release-notes.rst
@@ -38,9 +38,15 @@ more detail. @@ -38,9 +38,15 @@ more detail.
38 overhead of repeatedly validating the underlying document structure 38 overhead of repeatedly validating the underlying document structure
39 and/or building internal caches. If the underlying document structure 39 and/or building internal caches. If the underlying document structure
40 is directly modified (without the use of DocumentHelpers), the 40 is directly modified (without the use of DocumentHelpers), the
41 - ``validate`` methods revalidates the structure and resynchronizes any 41 + ``validate`` methods revalidate the structure and resynchronize any
42 internal caches. 42 internal caches.
43 43
  44 + - Add new ``Buffer`` methods ``move``, ``view``, ``data``, ``size`` and
  45 + ``empty``. The new methods present the ``Buffer`` as a ``char`` (rather
  46 + than ``unsigned char``) container and facilitate the efficient moving
  47 + of its content into a `std::string``.
  48 +
  49 +
44 - CLI Enhancements 50 - CLI Enhancements
45 51
46 - Disallow option :qpdf:ref:`--deterministic-id` to be used together 52 - Disallow option :qpdf:ref:`--deterministic-id` to be used together