Commit 7777ea84e7117a305a74450ae37ed3ecb7739583

Authored by m-holger
1 parent 4badc78a

Add new method ObjTable::emplace_back

libqpdf/qpdf/ObjTable.hh
@@ -28,6 +28,7 @@ template <class T> @@ -28,6 +28,7 @@ template <class T>
28 class ObjTable: public std::vector<T> 28 class ObjTable: public std::vector<T>
29 { 29 {
30 public: 30 public:
  31 + using reference = T&;
31 ObjTable() = default; 32 ObjTable() = default;
32 ObjTable(const ObjTable&) = delete; 33 ObjTable(const ObjTable&) = delete;
33 ObjTable(ObjTable&&) = delete; 34 ObjTable(ObjTable&&) = delete;
@@ -99,6 +100,18 @@ class ObjTable: public std::vector&lt;T&gt; @@ -99,6 +100,18 @@ class ObjTable: public std::vector&lt;T&gt;
99 return element(id); 100 return element(id);
100 } 101 }
101 102
  103 + // emplace_back to the end of the vector. If there are any conflicting sparse elements, emplace
  104 + // them to the back of the vector before adding the current element.
  105 + template <class... Args>
  106 + inline T&
  107 + emplace_back(Args&&... args)
  108 + {
  109 + if (min_sparse == std::vector<T>::size()) {
  110 + return emplace_back_large(std::forward<Args&&...>(args...));
  111 + }
  112 + return std::vector<T>::emplace_back(std::forward<Args&&...>(args...));
  113 + }
  114 +
102 void 115 void
103 resize(size_t a_size) 116 resize(size_t a_size)
104 { 117 {
@@ -168,6 +181,22 @@ class ObjTable: public std::vector&lt;T&gt; @@ -168,6 +181,22 @@ class ObjTable: public std::vector&lt;T&gt;
168 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable"); 181 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable");
169 return element(0); // doesn't return 182 return element(0); // doesn't return
170 } 183 }
  184 +
  185 + // Must only be called by emplace_back. Separated out from emplace_back to keep inlined code
  186 + // tight.
  187 + template <class... Args>
  188 + T&
  189 + emplace_back_large(Args&&... args)
  190 + {
  191 + auto it = sparse_elements.begin();
  192 + auto end = sparse_elements.end();
  193 + while (it != end && it->first == std::vector<T>::size()) {
  194 + std::vector<T>::emplace_back(std::move(it->second));
  195 + it = sparse_elements.erase(it);
  196 + }
  197 + min_sparse = (it == end) ? std::numeric_limits<size_t>::max() : it->first;
  198 + return std::vector<T>::emplace_back(std::forward<Args&&...>(args...));
  199 + }
171 }; 200 };
172 201
173 #endif // OBJTABLE_HH 202 #endif // OBJTABLE_HH
libtests/obj_table.cc
@@ -2,6 +2,11 @@ @@ -2,6 +2,11 @@
2 2
3 struct Test 3 struct Test
4 { 4 {
  5 + Test() = default;
  6 + Test(int value) :
  7 + value(value)
  8 + {
  9 + }
5 int value{0}; 10 int value{0};
6 }; 11 };
7 12
@@ -24,11 +29,15 @@ class Table: public ObjTable&lt;Test&gt; @@ -24,11 +29,15 @@ class Table: public ObjTable&lt;Test&gt;
24 (*this)[i].value = 2 * i; 29 (*this)[i].value = 2 * i;
25 } 30 }
26 resize(100); 31 resize(100);
27 - for (int i: {1, 99, 100, 105, 110, 120, 220}) { 32 + for (int i: {1, 99, 100, 105, 110, 120, 205, 206, 207, 210}) {
28 (*this)[i].value = 3 * i; 33 (*this)[i].value = 3 * i;
29 } 34 }
30 resize(200); 35 resize(200);
31 36
  37 + for (int i = 1; i < 10; ++i) {
  38 + emplace_back(i);
  39 + }
  40 +
32 forEach([](auto i, auto const& item) -> void { 41 forEach([](auto i, auto const& item) -> void {
33 if (item.value) { 42 if (item.value) {
34 std::cout << std::to_string(i) << " : " << std::to_string(item.value) << "\n"; 43 std::cout << std::to_string(i) << " : " << std::to_string(item.value) << "\n";
libtests/qtest/obj_table/obj_table.out
@@ -22,7 +22,19 @@ @@ -22,7 +22,19 @@
22 199 : 398 22 199 : 398
23 200 : 400 23 200 : 400
24 201 : 402 24 201 : 402
25 -220 : 660 25 +202 : 1
  26 +203 : 2
  27 +204 : 3
  28 +205 : 615
  29 +206 : 618
  30 +207 : 621
  31 +208 : 4
  32 +209 : 5
  33 +210 : 630
  34 +211 : 6
  35 +212 : 7
  36 +213 : 8
  37 +214 : 9
26 1000 : 2000 38 1000 : 2000
27 1001 : 2002 39 1001 : 2002
28 1002 : 2004 40 1002 : 2004