From 7777ea84e7117a305a74450ae37ed3ecb7739583 Mon Sep 17 00:00:00 2001 From: m-holger Date: Sat, 31 Aug 2024 20:15:19 +0100 Subject: [PATCH] Add new method ObjTable::emplace_back --- libqpdf/qpdf/ObjTable.hh | 29 ++++++++++++++++++++++++++ libtests/obj_table.cc | 11 +++++++++- libtests/qtest/obj_table/obj_table.out | 14 ++++++++++++- 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/libqpdf/qpdf/ObjTable.hh b/libqpdf/qpdf/ObjTable.hh index dd762214..3a36208d 100644 --- a/libqpdf/qpdf/ObjTable.hh +++ b/libqpdf/qpdf/ObjTable.hh @@ -28,6 +28,7 @@ template class ObjTable: public std::vector { public: + using reference = T&; ObjTable() = default; ObjTable(const ObjTable&) = delete; ObjTable(ObjTable&&) = delete; @@ -99,6 +100,18 @@ class ObjTable: public std::vector return element(id); } + // emplace_back to the end of the vector. If there are any conflicting sparse elements, emplace + // them to the back of the vector before adding the current element. + template + inline T& + emplace_back(Args&&... args) + { + if (min_sparse == std::vector::size()) { + return emplace_back_large(std::forward(args...)); + } + return std::vector::emplace_back(std::forward(args...)); + } + void resize(size_t a_size) { @@ -168,6 +181,22 @@ class ObjTable: public std::vector throw std::runtime_error("Impossibly large object id encountered accessing ObjTable"); return element(0); // doesn't return } + + // Must only be called by emplace_back. Separated out from emplace_back to keep inlined code + // tight. + template + T& + emplace_back_large(Args&&... args) + { + auto it = sparse_elements.begin(); + auto end = sparse_elements.end(); + while (it != end && it->first == std::vector::size()) { + std::vector::emplace_back(std::move(it->second)); + it = sparse_elements.erase(it); + } + min_sparse = (it == end) ? std::numeric_limits::max() : it->first; + return std::vector::emplace_back(std::forward(args...)); + } }; #endif // OBJTABLE_HH diff --git a/libtests/obj_table.cc b/libtests/obj_table.cc index 96ca9fb1..2b58eca7 100644 --- a/libtests/obj_table.cc +++ b/libtests/obj_table.cc @@ -2,6 +2,11 @@ struct Test { + Test() = default; + Test(int value) : + value(value) + { + } int value{0}; }; @@ -24,11 +29,15 @@ class Table: public ObjTable (*this)[i].value = 2 * i; } resize(100); - for (int i: {1, 99, 100, 105, 110, 120, 220}) { + for (int i: {1, 99, 100, 105, 110, 120, 205, 206, 207, 210}) { (*this)[i].value = 3 * i; } resize(200); + for (int i = 1; i < 10; ++i) { + emplace_back(i); + } + forEach([](auto i, auto const& item) -> void { if (item.value) { std::cout << std::to_string(i) << " : " << std::to_string(item.value) << "\n"; diff --git a/libtests/qtest/obj_table/obj_table.out b/libtests/qtest/obj_table/obj_table.out index 6454c26b..c5642855 100644 --- a/libtests/qtest/obj_table/obj_table.out +++ b/libtests/qtest/obj_table/obj_table.out @@ -22,7 +22,19 @@ 199 : 398 200 : 400 201 : 402 -220 : 660 +202 : 1 +203 : 2 +204 : 3 +205 : 615 +206 : 618 +207 : 621 +208 : 4 +209 : 5 +210 : 630 +211 : 6 +212 : 7 +213 : 8 +214 : 9 1000 : 2000 1001 : 2002 1002 : 2004