Commit 7777ea84e7117a305a74450ae37ed3ecb7739583
1 parent
4badc78a
Add new method ObjTable::emplace_back
Showing
3 changed files
with
52 additions
and
2 deletions
libqpdf/qpdf/ObjTable.hh
| ... | ... | @@ -28,6 +28,7 @@ template <class T> |
| 28 | 28 | class ObjTable: public std::vector<T> |
| 29 | 29 | { |
| 30 | 30 | public: |
| 31 | + using reference = T&; | |
| 31 | 32 | ObjTable() = default; |
| 32 | 33 | ObjTable(const ObjTable&) = delete; |
| 33 | 34 | ObjTable(ObjTable&&) = delete; |
| ... | ... | @@ -99,6 +100,18 @@ class ObjTable: public std::vector<T> |
| 99 | 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 | 115 | void |
| 103 | 116 | resize(size_t a_size) |
| 104 | 117 | { |
| ... | ... | @@ -168,6 +181,22 @@ class ObjTable: public std::vector<T> |
| 168 | 181 | throw std::runtime_error("Impossibly large object id encountered accessing ObjTable"); |
| 169 | 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 | 202 | #endif // OBJTABLE_HH | ... | ... |
libtests/obj_table.cc
| ... | ... | @@ -2,6 +2,11 @@ |
| 2 | 2 | |
| 3 | 3 | struct Test |
| 4 | 4 | { |
| 5 | + Test() = default; | |
| 6 | + Test(int value) : | |
| 7 | + value(value) | |
| 8 | + { | |
| 9 | + } | |
| 5 | 10 | int value{0}; |
| 6 | 11 | }; |
| 7 | 12 | |
| ... | ... | @@ -24,11 +29,15 @@ class Table: public ObjTable<Test> |
| 24 | 29 | (*this)[i].value = 2 * i; |
| 25 | 30 | } |
| 26 | 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 | 33 | (*this)[i].value = 3 * i; |
| 29 | 34 | } |
| 30 | 35 | resize(200); |
| 31 | 36 | |
| 37 | + for (int i = 1; i < 10; ++i) { | |
| 38 | + emplace_back(i); | |
| 39 | + } | |
| 40 | + | |
| 32 | 41 | forEach([](auto i, auto const& item) -> void { |
| 33 | 42 | if (item.value) { |
| 34 | 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 | 22 | 199 : 398 |
| 23 | 23 | 200 : 400 |
| 24 | 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 | 38 | 1000 : 2000 |
| 27 | 39 | 1001 : 2002 |
| 28 | 40 | 1002 : 2004 | ... | ... |