Commit 5e9de5cd509310bb5f954bb6c767cfec2b2bbeb7

Authored by m-holger
1 parent 452e1f5c

Tune handling of sparse arrays in QPDF_Array

Sparse arrays are rare. Dynamically create the variables needed to manage
them only when needed.
libqpdf/QPDF_Array.cc
@@ -30,10 +30,7 @@ QPDF_Array::QPDF_Array() : @@ -30,10 +30,7 @@ QPDF_Array::QPDF_Array() :
30 30
31 QPDF_Array::QPDF_Array(QPDF_Array const& other) : 31 QPDF_Array::QPDF_Array(QPDF_Array const& other) :
32 QPDFValue(::ot_array, "array"), 32 QPDFValue(::ot_array, "array"),
33 - sparse(other.sparse),  
34 - sp_size(other.sp_size),  
35 - sp_elements(other.sp_elements),  
36 - elements(other.elements) 33 + sp(other.sp ? std::make_unique<Sparse>(*other.sp) : nullptr)
37 { 34 {
38 } 35 }
39 36
@@ -44,15 +41,15 @@ QPDF_Array::QPDF_Array(std::vector&lt;QPDFObjectHandle&gt; const&amp; v) : @@ -44,15 +41,15 @@ QPDF_Array::QPDF_Array(std::vector&lt;QPDFObjectHandle&gt; const&amp; v) :
44 } 41 }
45 42
46 QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) : 43 QPDF_Array::QPDF_Array(std::vector<std::shared_ptr<QPDFObject>>&& v, bool sparse) :
47 - QPDFValue(::ot_array, "array"),  
48 - sparse(sparse) 44 + QPDFValue(::ot_array, "array")
49 { 45 {
50 if (sparse) { 46 if (sparse) {
  47 + sp = std::make_unique<Sparse>();
51 for (auto&& item: v) { 48 for (auto&& item: v) {
52 if (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect()) { 49 if (item->getTypeCode() != ::ot_null || item->getObjGen().isIndirect()) {
53 - sp_elements[sp_size] = std::move(item); 50 + sp->elements[sp->size] = std::move(item);
54 } 51 }
55 - ++sp_size; 52 + ++sp->size;
56 } 53 }
57 } else { 54 } else {
58 elements = std::move(v); 55 elements = std::move(v);
@@ -77,12 +74,12 @@ QPDF_Array::copy(bool shallow) @@ -77,12 +74,12 @@ QPDF_Array::copy(bool shallow)
77 if (shallow) { 74 if (shallow) {
78 return do_create(new QPDF_Array(*this)); 75 return do_create(new QPDF_Array(*this));
79 } else { 76 } else {
80 - if (sparse) { 77 + if (sp) {
81 auto* result = new QPDF_Array(); 78 auto* result = new QPDF_Array();
82 - result->sp_size = sp_size;  
83 - for (auto const& element: sp_elements) { 79 + result->sp->size = sp->size;
  80 + for (auto const& element: sp->elements) {
84 auto const& obj = element.second; 81 auto const& obj = element.second;
85 - result->sp_elements[element.first] = 82 + result->sp->elements[element.first] =
86 obj->getObjGen().isIndirect() ? obj : obj->copy(); 83 obj->getObjGen().isIndirect() ? obj : obj->copy();
87 } 84 }
88 return do_create(result); 85 return do_create(result);
@@ -102,8 +99,8 @@ QPDF_Array::copy(bool shallow) @@ -102,8 +99,8 @@ QPDF_Array::copy(bool shallow)
102 void 99 void
103 QPDF_Array::disconnect() 100 QPDF_Array::disconnect()
104 { 101 {
105 - if (sparse) {  
106 - for (auto& item: sp_elements) { 102 + if (sp) {
  103 + for (auto& item: sp->elements) {
107 auto& obj = item.second; 104 auto& obj = item.second;
108 if (!obj->getObjGen().isIndirect()) { 105 if (!obj->getObjGen().isIndirect()) {
109 obj->disconnect(); 106 obj->disconnect();
@@ -122,9 +119,9 @@ std::string @@ -122,9 +119,9 @@ std::string
122 QPDF_Array::unparse() 119 QPDF_Array::unparse()
123 { 120 {
124 std::string result = "[ "; 121 std::string result = "[ ";
125 - if (sparse) { 122 + if (sp) {
126 int next = 0; 123 int next = 0;
127 - for (auto& item: sp_elements) { 124 + for (auto& item: sp->elements) {
128 int key = item.first; 125 int key = item.first;
129 for (int j = next; j < key; ++j) { 126 for (int j = next; j < key; ++j) {
130 result += "null "; 127 result += "null ";
@@ -134,7 +131,7 @@ QPDF_Array::unparse() @@ -134,7 +131,7 @@ QPDF_Array::unparse()
134 result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " "; 131 result += og.isIndirect() ? og.unparse(' ') + " R " : item.second->unparse() + " ";
135 next = ++key; 132 next = ++key;
136 } 133 }
137 - for (int j = next; j < sp_size; ++j) { 134 + for (int j = next; j < sp->size; ++j) {
138 result += "null "; 135 result += "null ";
139 } 136 }
140 } else { 137 } else {
@@ -153,9 +150,9 @@ QPDF_Array::getJSON(int json_version) @@ -153,9 +150,9 @@ QPDF_Array::getJSON(int json_version)
153 { 150 {
154 static const JSON j_null = JSON::makeNull(); 151 static const JSON j_null = JSON::makeNull();
155 JSON j_array = JSON::makeArray(); 152 JSON j_array = JSON::makeArray();
156 - if (sparse) { 153 + if (sp) {
157 int next = 0; 154 int next = 0;
158 - for (auto& item: sp_elements) { 155 + for (auto& item: sp->elements) {
159 int key = item.first; 156 int key = item.first;
160 for (int j = next; j < key; ++j) { 157 for (int j = next; j < key; ++j) {
161 j_array.addArrayElement(j_null); 158 j_array.addArrayElement(j_null);
@@ -166,7 +163,7 @@ QPDF_Array::getJSON(int json_version) @@ -166,7 +163,7 @@ QPDF_Array::getJSON(int json_version)
166 : item.second->getJSON(json_version)); 163 : item.second->getJSON(json_version));
167 next = ++key; 164 next = ++key;
168 } 165 }
169 - for (int j = next; j < sp_size; ++j) { 166 + for (int j = next; j < sp->size; ++j) {
170 j_array.addArrayElement(j_null); 167 j_array.addArrayElement(j_null);
171 } 168 }
172 } else { 169 } else {
@@ -185,9 +182,9 @@ QPDF_Array::at(int n) const noexcept @@ -185,9 +182,9 @@ QPDF_Array::at(int n) const noexcept
185 { 182 {
186 if (n < 0 || n >= size()) { 183 if (n < 0 || n >= size()) {
187 return {}; 184 return {};
188 - } else if (sparse) {  
189 - auto const& iter = sp_elements.find(n);  
190 - return iter == sp_elements.end() ? null_oh : (*iter).second; 185 + } else if (sp) {
  186 + auto const& iter = sp->elements.find(n);
  187 + return iter == sp->elements.end() ? null_oh : (*iter).second;
191 } else { 188 } else {
192 return elements[size_t(n)]; 189 return elements[size_t(n)];
193 } 190 }
@@ -196,10 +193,10 @@ QPDF_Array::at(int n) const noexcept @@ -196,10 +193,10 @@ QPDF_Array::at(int n) const noexcept
196 std::vector<QPDFObjectHandle> 193 std::vector<QPDFObjectHandle>
197 QPDF_Array::getAsVector() const 194 QPDF_Array::getAsVector() const
198 { 195 {
199 - if (sparse) { 196 + if (sp) {
200 std::vector<QPDFObjectHandle> v; 197 std::vector<QPDFObjectHandle> v;
201 v.reserve(size_t(size())); 198 v.reserve(size_t(size()));
202 - for (auto const& item: sp_elements) { 199 + for (auto const& item: sp->elements) {
203 v.resize(size_t(item.first), null_oh); 200 v.resize(size_t(item.first), null_oh);
204 v.emplace_back(item.second); 201 v.emplace_back(item.second);
205 } 202 }
@@ -217,8 +214,8 @@ QPDF_Array::setAt(int at, QPDFObjectHandle const&amp; oh) @@ -217,8 +214,8 @@ QPDF_Array::setAt(int at, QPDFObjectHandle const&amp; oh)
217 return false; 214 return false;
218 } 215 }
219 checkOwnership(oh); 216 checkOwnership(oh);
220 - if (sparse) {  
221 - sp_elements[at] = oh.getObj(); 217 + if (sp) {
  218 + sp->elements[at] = oh.getObj();
222 } else { 219 } else {
223 elements[size_t(at)] = oh.getObj(); 220 elements[size_t(at)] = oh.getObj();
224 } 221 }
@@ -247,20 +244,20 @@ QPDF_Array::insert(int at, QPDFObjectHandle const&amp; item) @@ -247,20 +244,20 @@ QPDF_Array::insert(int at, QPDFObjectHandle const&amp; item)
247 push_back(item); 244 push_back(item);
248 } else { 245 } else {
249 checkOwnership(item); 246 checkOwnership(item);
250 - if (sparse) {  
251 - auto iter = sp_elements.crbegin();  
252 - while (iter != sp_elements.crend()) { 247 + if (sp) {
  248 + auto iter = sp->elements.crbegin();
  249 + while (iter != sp->elements.crend()) {
253 auto key = (iter++)->first; 250 auto key = (iter++)->first;
254 if (key >= at) { 251 if (key >= at) {
255 - auto nh = sp_elements.extract(key); 252 + auto nh = sp->elements.extract(key);
256 ++nh.key(); 253 ++nh.key();
257 - sp_elements.insert(std::move(nh)); 254 + sp->elements.insert(std::move(nh));
258 } else { 255 } else {
259 break; 256 break;
260 } 257 }
261 } 258 }
262 - sp_elements[at] = item.getObj();  
263 - ++sp_size; 259 + sp->elements[at] = item.getObj();
  260 + ++sp->size;
264 } else { 261 } else {
265 elements.insert(elements.cbegin() + at, item.getObj()); 262 elements.insert(elements.cbegin() + at, item.getObj());
266 } 263 }
@@ -272,8 +269,8 @@ void @@ -272,8 +269,8 @@ void
272 QPDF_Array::push_back(QPDFObjectHandle const& item) 269 QPDF_Array::push_back(QPDFObjectHandle const& item)
273 { 270 {
274 checkOwnership(item); 271 checkOwnership(item);
275 - if (sparse) {  
276 - sp_elements[sp_size++] = item.getObj(); 272 + if (sp) {
  273 + sp->elements[(sp->size)++] = item.getObj();
277 } else { 274 } else {
278 elements.push_back(item.getObj()); 275 elements.push_back(item.getObj());
279 } 276 }
@@ -285,21 +282,21 @@ QPDF_Array::erase(int at) @@ -285,21 +282,21 @@ QPDF_Array::erase(int at)
285 if (at < 0 || at >= size()) { 282 if (at < 0 || at >= size()) {
286 return false; 283 return false;
287 } 284 }
288 - if (sparse) {  
289 - auto end = sp_elements.end();  
290 - if (auto iter = sp_elements.lower_bound(at); iter != end) { 285 + if (sp) {
  286 + auto end = sp->elements.end();
  287 + if (auto iter = sp->elements.lower_bound(at); iter != end) {
291 if (iter->first == at) { 288 if (iter->first == at) {
292 iter++; 289 iter++;
293 - sp_elements.erase(at); 290 + sp->elements.erase(at);
294 } 291 }
295 292
296 while (iter != end) { 293 while (iter != end) {
297 - auto nh = sp_elements.extract(iter++); 294 + auto nh = sp->elements.extract(iter++);
298 --nh.key(); 295 --nh.key();
299 - sp_elements.insert(std::move(nh)); 296 + sp->elements.insert(std::move(nh));
300 } 297 }
301 } 298 }
302 - --sp_size; 299 + --(sp->size);
303 } else { 300 } else {
304 elements.erase(elements.cbegin() + at); 301 elements.erase(elements.cbegin() + at);
305 } 302 }
libqpdf/qpdf/QPDF_Array.hh
@@ -8,6 +8,13 @@ @@ -8,6 +8,13 @@
8 8
9 class QPDF_Array: public QPDFValue 9 class QPDF_Array: public QPDFValue
10 { 10 {
  11 + private:
  12 + struct Sparse
  13 + {
  14 + int size{0};
  15 + std::map<int, std::shared_ptr<QPDFObject>> elements;
  16 + };
  17 +
11 public: 18 public:
12 ~QPDF_Array() override = default; 19 ~QPDF_Array() override = default;
13 static std::shared_ptr<QPDFObject> create(std::vector<QPDFObjectHandle> const& items); 20 static std::shared_ptr<QPDFObject> create(std::vector<QPDFObjectHandle> const& items);
@@ -21,7 +28,7 @@ class QPDF_Array: public QPDFValue @@ -21,7 +28,7 @@ class QPDF_Array: public QPDFValue
21 int 28 int
22 size() const noexcept 29 size() const noexcept
23 { 30 {
24 - return sparse ? sp_size : int(elements.size()); 31 + return sp ? sp->size : int(elements.size());
25 } 32 }
26 QPDFObjectHandle at(int n) const noexcept; 33 QPDFObjectHandle at(int n) const noexcept;
27 bool setAt(int n, QPDFObjectHandle const& oh); 34 bool setAt(int n, QPDFObjectHandle const& oh);
@@ -39,9 +46,7 @@ class QPDF_Array: public QPDFValue @@ -39,9 +46,7 @@ class QPDF_Array: public QPDFValue
39 46
40 void checkOwnership(QPDFObjectHandle const& item) const; 47 void checkOwnership(QPDFObjectHandle const& item) const;
41 48
42 - bool sparse{false};  
43 - int sp_size{0};  
44 - std::map<int, std::shared_ptr<QPDFObject>> sp_elements; 49 + std::unique_ptr<Sparse> sp;
45 std::vector<std::shared_ptr<QPDFObject>> elements; 50 std::vector<std::shared_ptr<QPDFObject>> elements;
46 }; 51 };
47 52