aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorm-holger <m-holger@kubitscheck.org>2023-01-05 12:09:44 +0100
committerm-holger <m-holger@kubitscheck.org>2023-05-19 13:27:53 +0200
commit9b0801721710093102c64068b6c643c8fcd7f5db (patch)
tree631fd26fc674aee7fe54280f56597f94cf97679b
parenta6d7b79e65941238871c0c3d7d06b9bf246213ba (diff)
downloadqpdf-9b0801721710093102c64068b6c643c8fcd7f5db.tar.zst
Add new convenience class QPDFObjGen::set
-rw-r--r--include/qpdf/QPDFObjGen.hh69
-rw-r--r--libqpdf/QPDFObjGen.cc56
2 files changed, 121 insertions, 4 deletions
diff --git a/include/qpdf/QPDFObjGen.hh b/include/qpdf/QPDFObjGen.hh
index ccab4ba2..0d14efaf 100644
--- a/include/qpdf/QPDFObjGen.hh
+++ b/include/qpdf/QPDFObjGen.hh
@@ -24,6 +24,10 @@
#include <qpdf/DLL.h>
#include <iostream>
+#include <set>
+
+class QPDFObjectHandle;
+class QPDFObjectHelper;
// This class represents an object ID and generation pair. It is
// suitable to use as a key in a map or set.
@@ -31,6 +35,7 @@
class QPDFObjGen
{
public:
+ // ABI: change to default.
QPDF_DLL
QPDFObjGen() :
obj(0),
@@ -84,12 +89,72 @@ class QPDFObjGen
QPDF_DLL
friend std::ostream& operator<<(std::ostream& os, const QPDFObjGen& og);
+ // Convenience class for loop detection when processing objects.
+ //
+ // The class adds 'add' methods to a std::set<QPDFObjGen> which allows
+ // to test whether an QPDFObjGen is present in the set and to insert it in
+ // a single operation. The 'add' method is overloaded to take a QPDFObjGen,
+ // QPDFObjectHandle or an QPDFObjectHelper as parameter.
+ //
+ // The erase method is modified to ignore requests to erase
+ // QPDFObjGen(0, 0).
+ //
+ // Usage example:
+ //
+ // void process_object(QPDFObjectHandle oh, QPDFObjGen::Tracker& seen)
+ // {
+ // if (seen.add(oh)) {
+ // // handle first encounter of oh
+ // } else {
+ // // handle loop / subsequent encounter of oh
+ // }
+ // }
+ class QPDF_DLL_CLASS set: public std::set<QPDFObjGen>
+ {
+ public:
+ // Add 'og' to the set. Return false if 'og' is already present in
+ // the set. Attempts to insert QPDFObjGen(0, 0) are ignored.
+ QPDF_DLL
+ bool
+ add(QPDFObjGen og)
+ {
+ if (og.isIndirect()) {
+ if (count(og) > 0) {
+ return false;
+ }
+ emplace(og);
+ }
+ return true;
+ }
+
+ QPDF_DLL
+ bool add(QPDFObjectHandle const& oh);
+
+ QPDF_DLL
+ bool add(QPDFObjectHelper const& oh);
+
+ QPDF_DLL
+ void
+ erase(QPDFObjGen og)
+ {
+ if (og.isIndirect()) {
+ std::set<QPDFObjGen>::erase(og);
+ }
+ }
+
+ QPDF_DLL
+ void erase(QPDFObjectHandle const& oh);
+
+ QPDF_DLL
+ void erase(QPDFObjectHelper const& oh);
+ };
+
private:
// This class does not use the Members pattern to avoid a memory
// allocation for every one of these. A lot of these get created
// and destroyed.
- int obj;
- int gen;
+ int obj{0};
+ int gen{0};
};
#endif // QPDFOBJGEN_HH
diff --git a/libqpdf/QPDFObjGen.cc b/libqpdf/QPDFObjGen.cc
index 7cce84d8..8e5bd178 100644
--- a/libqpdf/QPDFObjGen.cc
+++ b/libqpdf/QPDFObjGen.cc
@@ -1,7 +1,12 @@
#include <qpdf/QPDFObjGen.hh>
-#include <qpdf/QUtil.hh>
+#include <qpdf/QPDFObjectHandle.hh>
+#include <qpdf/QPDFObjectHelper.hh>
+#include <qpdf/QPDFObject_private.hh>
+#include <stdexcept>
+
+// ABI: inline and pass og by value
std::ostream&
operator<<(std::ostream& os, const QPDFObjGen& og)
{
@@ -9,8 +14,55 @@ operator<<(std::ostream& os, const QPDFObjGen& og)
return os;
}
+// ABI: inline
std::string
QPDFObjGen::unparse(char separator) const
{
- return std::to_string(this->obj) + separator + std::to_string(this->gen);
+ return std::to_string(obj) + separator + std::to_string(gen);
+}
+
+bool
+QPDFObjGen::set::add(QPDFObjectHandle const& oh)
+{
+ if (auto* ptr = oh.getObjectPtr()) {
+ return add(ptr->getObjGen());
+ } else {
+ throw std::logic_error("attempt to retrieve QPDFObjGen from "
+ "uninitialized QPDFObjectHandle");
+ return false;
+ }
+}
+
+bool
+QPDFObjGen::set::add(QPDFObjectHelper const& helper)
+{
+ if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
+ return add(ptr->getObjGen());
+ } else {
+ throw std::logic_error("attempt to retrieve QPDFObjGen from "
+ "uninitialized QPDFObjectHandle");
+ return false;
+ }
+}
+
+void
+QPDFObjGen::set::erase(QPDFObjectHandle const& oh)
+{
+ if (auto* ptr = oh.getObjectPtr()) {
+ erase(ptr->getObjGen());
+ } else {
+ throw std::logic_error("attempt to retrieve QPDFObjGen from "
+ "uninitialized QPDFObjectHandle");
+ }
+}
+
+void
+QPDFObjGen::set::erase(QPDFObjectHelper const& helper)
+{
+ if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
+ erase(ptr->getObjGen());
+ } else {
+ throw std::logic_error("attempt to retrieve QPDFObjGen from "
+ "uninitialized QPDFObjectHandle");
+ }
}