Commit 9b0801721710093102c64068b6c643c8fcd7f5db

Authored by m-holger
1 parent a6d7b79e

Add new convenience class QPDFObjGen::set

include/qpdf/QPDFObjGen.hh
... ... @@ -24,6 +24,10 @@
24 24  
25 25 #include <qpdf/DLL.h>
26 26 #include <iostream>
  27 +#include <set>
  28 +
  29 +class QPDFObjectHandle;
  30 +class QPDFObjectHelper;
27 31  
28 32 // This class represents an object ID and generation pair. It is
29 33 // suitable to use as a key in a map or set.
... ... @@ -31,6 +35,7 @@
31 35 class QPDFObjGen
32 36 {
33 37 public:
  38 + // ABI: change to default.
34 39 QPDF_DLL
35 40 QPDFObjGen() :
36 41 obj(0),
... ... @@ -84,12 +89,72 @@ class QPDFObjGen
84 89 QPDF_DLL
85 90 friend std::ostream& operator<<(std::ostream& os, const QPDFObjGen& og);
86 91  
  92 + // Convenience class for loop detection when processing objects.
  93 + //
  94 + // The class adds 'add' methods to a std::set<QPDFObjGen> which allows
  95 + // to test whether an QPDFObjGen is present in the set and to insert it in
  96 + // a single operation. The 'add' method is overloaded to take a QPDFObjGen,
  97 + // QPDFObjectHandle or an QPDFObjectHelper as parameter.
  98 + //
  99 + // The erase method is modified to ignore requests to erase
  100 + // QPDFObjGen(0, 0).
  101 + //
  102 + // Usage example:
  103 + //
  104 + // void process_object(QPDFObjectHandle oh, QPDFObjGen::Tracker& seen)
  105 + // {
  106 + // if (seen.add(oh)) {
  107 + // // handle first encounter of oh
  108 + // } else {
  109 + // // handle loop / subsequent encounter of oh
  110 + // }
  111 + // }
  112 + class QPDF_DLL_CLASS set: public std::set<QPDFObjGen>
  113 + {
  114 + public:
  115 + // Add 'og' to the set. Return false if 'og' is already present in
  116 + // the set. Attempts to insert QPDFObjGen(0, 0) are ignored.
  117 + QPDF_DLL
  118 + bool
  119 + add(QPDFObjGen og)
  120 + {
  121 + if (og.isIndirect()) {
  122 + if (count(og) > 0) {
  123 + return false;
  124 + }
  125 + emplace(og);
  126 + }
  127 + return true;
  128 + }
  129 +
  130 + QPDF_DLL
  131 + bool add(QPDFObjectHandle const& oh);
  132 +
  133 + QPDF_DLL
  134 + bool add(QPDFObjectHelper const& oh);
  135 +
  136 + QPDF_DLL
  137 + void
  138 + erase(QPDFObjGen og)
  139 + {
  140 + if (og.isIndirect()) {
  141 + std::set<QPDFObjGen>::erase(og);
  142 + }
  143 + }
  144 +
  145 + QPDF_DLL
  146 + void erase(QPDFObjectHandle const& oh);
  147 +
  148 + QPDF_DLL
  149 + void erase(QPDFObjectHelper const& oh);
  150 + };
  151 +
87 152 private:
88 153 // This class does not use the Members pattern to avoid a memory
89 154 // allocation for every one of these. A lot of these get created
90 155 // and destroyed.
91   - int obj;
92   - int gen;
  156 + int obj{0};
  157 + int gen{0};
93 158 };
94 159  
95 160 #endif // QPDFOBJGEN_HH
... ...
libqpdf/QPDFObjGen.cc
1 1 #include <qpdf/QPDFObjGen.hh>
2 2  
3   -#include <qpdf/QUtil.hh>
  3 +#include <qpdf/QPDFObjectHandle.hh>
  4 +#include <qpdf/QPDFObjectHelper.hh>
  5 +#include <qpdf/QPDFObject_private.hh>
4 6  
  7 +#include <stdexcept>
  8 +
  9 +// ABI: inline and pass og by value
5 10 std::ostream&
6 11 operator<<(std::ostream& os, const QPDFObjGen& og)
7 12 {
... ... @@ -9,8 +14,55 @@ operator&lt;&lt;(std::ostream&amp; os, const QPDFObjGen&amp; og)
9 14 return os;
10 15 }
11 16  
  17 +// ABI: inline
12 18 std::string
13 19 QPDFObjGen::unparse(char separator) const
14 20 {
15   - return std::to_string(this->obj) + separator + std::to_string(this->gen);
  21 + return std::to_string(obj) + separator + std::to_string(gen);
  22 +}
  23 +
  24 +bool
  25 +QPDFObjGen::set::add(QPDFObjectHandle const& oh)
  26 +{
  27 + if (auto* ptr = oh.getObjectPtr()) {
  28 + return add(ptr->getObjGen());
  29 + } else {
  30 + throw std::logic_error("attempt to retrieve QPDFObjGen from "
  31 + "uninitialized QPDFObjectHandle");
  32 + return false;
  33 + }
  34 +}
  35 +
  36 +bool
  37 +QPDFObjGen::set::add(QPDFObjectHelper const& helper)
  38 +{
  39 + if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
  40 + return add(ptr->getObjGen());
  41 + } else {
  42 + throw std::logic_error("attempt to retrieve QPDFObjGen from "
  43 + "uninitialized QPDFObjectHandle");
  44 + return false;
  45 + }
  46 +}
  47 +
  48 +void
  49 +QPDFObjGen::set::erase(QPDFObjectHandle const& oh)
  50 +{
  51 + if (auto* ptr = oh.getObjectPtr()) {
  52 + erase(ptr->getObjGen());
  53 + } else {
  54 + throw std::logic_error("attempt to retrieve QPDFObjGen from "
  55 + "uninitialized QPDFObjectHandle");
  56 + }
  57 +}
  58 +
  59 +void
  60 +QPDFObjGen::set::erase(QPDFObjectHelper const& helper)
  61 +{
  62 + if (auto* ptr = helper.getObjectHandle().getObjectPtr()) {
  63 + erase(ptr->getObjGen());
  64 + } else {
  65 + throw std::logic_error("attempt to retrieve QPDFObjGen from "
  66 + "uninitialized QPDFObjectHandle");
  67 + }
16 68 }
... ...