Commit 8ed3e8c79b5cbccfeccee865e555b68025ee2c1f

Authored by Jay Berkenbilt
1 parent e7e20772

NNTree: rework iterators to be more memory efficient

Keep a std::pair internal to the iterators so that operator* can
return a reference and operator-> can work, and each can work without
copying pairs of objects around.
include/qpdf/QPDFNameTreeObjectHelper.hh
@@ -75,9 +75,6 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -75,9 +75,6 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
75 75
76 class iterator: public std::iterator< 76 class iterator: public std::iterator<
77 std::bidirectional_iterator_tag, 77 std::bidirectional_iterator_tag,
78 - std::pair<std::string, QPDFObjectHandle>,  
79 - void,  
80 - std::pair<std::string, QPDFObjectHandle>*,  
81 std::pair<std::string, QPDFObjectHandle>> 78 std::pair<std::string, QPDFObjectHandle>>
82 { 79 {
83 friend class QPDFNameTreeObjectHelper; 80 friend class QPDFNameTreeObjectHelper;
@@ -105,6 +102,8 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -105,6 +102,8 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
105 QPDF_DLL 102 QPDF_DLL
106 reference operator*(); 103 reference operator*();
107 QPDF_DLL 104 QPDF_DLL
  105 + pointer operator->();
  106 + QPDF_DLL
108 bool operator==(iterator const& other) const; 107 bool operator==(iterator const& other) const;
109 QPDF_DLL 108 QPDF_DLL
110 bool operator!=(iterator const& other) const 109 bool operator!=(iterator const& other) const
@@ -131,8 +130,11 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper @@ -131,8 +130,11 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper
131 void remove(); 130 void remove();
132 131
133 private: 132 private:
  133 + void updateIValue();
  134 +
134 iterator(std::shared_ptr<NNTreeIterator> const&); 135 iterator(std::shared_ptr<NNTreeIterator> const&);
135 std::shared_ptr<NNTreeIterator> impl; 136 std::shared_ptr<NNTreeIterator> impl;
  137 + value_type ivalue;
136 }; 138 };
137 139
138 // The iterator looks like map iterator, so i.first is a string 140 // The iterator looks like map iterator, so i.first is a string
include/qpdf/QPDFNumberTreeObjectHelper.hh
@@ -94,9 +94,6 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -94,9 +94,6 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
94 94
95 class iterator: public std::iterator< 95 class iterator: public std::iterator<
96 std::bidirectional_iterator_tag, 96 std::bidirectional_iterator_tag,
97 - std::pair<numtree_number, QPDFObjectHandle>,  
98 - void,  
99 - std::pair<numtree_number, QPDFObjectHandle>*,  
100 std::pair<numtree_number, QPDFObjectHandle>> 97 std::pair<numtree_number, QPDFObjectHandle>>
101 { 98 {
102 friend class QPDFNumberTreeObjectHelper; 99 friend class QPDFNumberTreeObjectHelper;
@@ -124,6 +121,8 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -124,6 +121,8 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
124 QPDF_DLL 121 QPDF_DLL
125 reference operator*(); 122 reference operator*();
126 QPDF_DLL 123 QPDF_DLL
  124 + pointer operator->();
  125 + QPDF_DLL
127 bool operator==(iterator const& other) const; 126 bool operator==(iterator const& other) const;
128 QPDF_DLL 127 QPDF_DLL
129 bool operator!=(iterator const& other) const 128 bool operator!=(iterator const& other) const
@@ -150,8 +149,11 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper @@ -150,8 +149,11 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper
150 void remove(); 149 void remove();
151 150
152 private: 151 private:
  152 + void updateIValue();
  153 +
153 iterator(std::shared_ptr<NNTreeIterator> const&); 154 iterator(std::shared_ptr<NNTreeIterator> const&);
154 std::shared_ptr<NNTreeIterator> impl; 155 std::shared_ptr<NNTreeIterator> impl;
  156 + value_type ivalue;
155 }; 157 };
156 158
157 // The iterator looks like map iterator, so i.first is a string 159 // The iterator looks like map iterator, so i.first is a string
libqpdf/NNTree.cc
@@ -50,6 +50,57 @@ NNTreeIterator::NNTreeIterator(NNTreeImpl&amp; impl) : @@ -50,6 +50,57 @@ NNTreeIterator::NNTreeIterator(NNTreeImpl&amp; impl) :
50 { 50 {
51 } 51 }
52 52
  53 +void
  54 +NNTreeIterator::updateIValue(bool allow_invalid)
  55 +{
  56 + // ivalue should never be used inside the class since we return a
  57 + // pointer/reference to it. Every bit of code that ever changes
  58 + // what object the iterator points to should take care to call
  59 + // updateIValue. Failure to do this means that any old references
  60 + // to *iter will point to incorrect objects, though the next
  61 + // dereference of the iterator will fix it. This isn't necessarily
  62 + // catastrophic, but it would be confusing. The test suite
  63 + // attempts to exercise various cases to ensure we don't introduce
  64 + // that bug in the future, but sadly it's tricky to verify by
  65 + // reasoning about the code that this constraint is always
  66 + // satisfied. Whenever we update what the iterator points to, we
  67 + // should call setItemNumber, which calls this. If we change what
  68 + // the iterator in some other way, such as replacing a value or
  69 + // removing an item and making the iterator point at a different
  70 + // item in potentially the same position, we must call
  71 + // updateIValue as well. These cases are handled, and for good
  72 + // measure, we also call updateIValue in operator* and operator->.
  73 +
  74 + bool okay = false;
  75 + if ((item_number >= 0) &&
  76 + this->node.isInitialized() &&
  77 + this->node.isDictionary())
  78 + {
  79 + auto items = this->node.getKey(impl.details.itemsKey());
  80 + if (this->item_number + 1 < items.getArrayNItems())
  81 + {
  82 + okay = true;
  83 + this->ivalue.first = items.getArrayItem(this->item_number);
  84 + this->ivalue.second = items.getArrayItem(1+this->item_number);
  85 + }
  86 + else
  87 + {
  88 + error(impl.qpdf, node, "update ivalue: items array is too short");
  89 + }
  90 + }
  91 + if (! okay)
  92 + {
  93 + if (! allow_invalid)
  94 + {
  95 + throw std::logic_error(
  96 + "attempt made to dereference an invalid"
  97 + " name/number tree iterator");
  98 + }
  99 + this->ivalue.first = QPDFObjectHandle();
  100 + this->ivalue.second = QPDFObjectHandle();
  101 + }
  102 +}
  103 +
53 NNTreeIterator::PathElement::PathElement( 104 NNTreeIterator::PathElement::PathElement(
54 QPDFObjectHandle const& node, int kid_number) : 105 QPDFObjectHandle const& node, int kid_number) :
55 node(node), 106 node(node),
@@ -522,6 +573,7 @@ NNTreeIterator::remove() @@ -522,6 +573,7 @@ NNTreeIterator::remove()
522 // We don't have to do anything since the removed item's 573 // We don't have to do anything since the removed item's
523 // successor now occupies its former location. 574 // successor now occupies its former location.
524 QTC::TC("qpdf", "NNTree erased non-last item"); 575 QTC::TC("qpdf", "NNTree erased non-last item");
  576 + updateIValue();
525 } 577 }
526 else 578 else
527 { 579 {
@@ -630,19 +682,15 @@ NNTreeIterator::operator--() @@ -630,19 +682,15 @@ NNTreeIterator::operator--()
630 NNTreeIterator::reference 682 NNTreeIterator::reference
631 NNTreeIterator::operator*() 683 NNTreeIterator::operator*()
632 { 684 {
633 - if (this->item_number < 0)  
634 - {  
635 - throw std::logic_error(  
636 - "attempt made to dereference an invalid"  
637 - " name/number tree iterator");  
638 - }  
639 - auto items = this->node.getKey(impl.details.itemsKey());  
640 - if (items.getArrayNItems() < this->item_number + 2)  
641 - {  
642 - error(impl.qpdf, node, "operator*: items array is too short");  
643 - }  
644 - return std::make_pair(items.getArrayItem(this->item_number),  
645 - items.getArrayItem(1+this->item_number)); 685 + updateIValue(false);
  686 + return this->ivalue;
  687 +}
  688 +
  689 +NNTreeIterator::pointer
  690 +NNTreeIterator::operator->()
  691 +{
  692 + updateIValue(false);
  693 + return &(this->ivalue);
646 } 694 }
647 695
648 bool 696 bool
@@ -660,7 +708,7 @@ NNTreeIterator::operator==(NNTreeIterator const&amp; other) const @@ -660,7 +708,7 @@ NNTreeIterator::operator==(NNTreeIterator const&amp; other) const
660 auto opi = other.path.begin(); 708 auto opi = other.path.begin();
661 while (tpi != this->path.end()) 709 while (tpi != this->path.end())
662 { 710 {
663 - if ((*tpi).kid_number != (*opi).kid_number) 711 + if (tpi->kid_number != opi->kid_number)
664 { 712 {
665 return false; 713 return false;
666 } 714 }
@@ -679,6 +727,7 @@ NNTreeIterator::setItemNumber(QPDFObjectHandle const&amp; node, int n) @@ -679,6 +727,7 @@ NNTreeIterator::setItemNumber(QPDFObjectHandle const&amp; node, int n)
679 { 727 {
680 this->node = node; 728 this->node = node;
681 this->item_number = n; 729 this->item_number = n;
  730 + updateIValue();
682 } 731 }
683 732
684 void 733 void
@@ -961,7 +1010,7 @@ NNTreeImpl::repair() @@ -961,7 +1010,7 @@ NNTreeImpl::repair()
961 auto new_node = QPDFObjectHandle::newDictionary(); 1010 auto new_node = QPDFObjectHandle::newDictionary();
962 new_node.replaceKey(details.itemsKey(), QPDFObjectHandle::newArray()); 1011 new_node.replaceKey(details.itemsKey(), QPDFObjectHandle::newArray());
963 NNTreeImpl repl(details, qpdf, new_node, false); 1012 NNTreeImpl repl(details, qpdf, new_node, false);
964 - for (auto i: *this) 1013 + for (auto const& i: *this)
965 { 1014 {
966 repl.insert(i.first, i.second); 1015 repl.insert(i.first, i.second);
967 } 1016 }
@@ -1005,15 +1054,15 @@ NNTreeImpl::findInternal(QPDFObjectHandle key, bool return_prev_if_not_found) @@ -1005,15 +1054,15 @@ NNTreeImpl::findInternal(QPDFObjectHandle key, bool return_prev_if_not_found)
1005 return end(); 1054 return end();
1006 } 1055 }
1007 else if (first_item.valid() && 1056 else if (first_item.valid() &&
1008 - details.keyValid((*first_item).first) &&  
1009 - details.compareKeys(key, (*first_item).first) < 0) 1057 + details.keyValid(first_item->first) &&
  1058 + details.compareKeys(key, first_item->first) < 0)
1010 { 1059 {
1011 // Before the first key 1060 // Before the first key
1012 return end(); 1061 return end();
1013 } 1062 }
1014 else if (last_item.valid() && 1063 else if (last_item.valid() &&
1015 - details.keyValid((*last_item).first) &&  
1016 - details.compareKeys(key, (*last_item).first) > 0) 1064 + details.keyValid(last_item->first) &&
  1065 + details.compareKeys(key, last_item->first) > 0)
1017 { 1066 {
1018 // After the last key 1067 // After the last key
1019 if (return_prev_if_not_found) 1068 if (return_prev_if_not_found)
@@ -1097,10 +1146,10 @@ NNTreeImpl::insertFirst(QPDFObjectHandle key, QPDFObjectHandle value) @@ -1097,10 +1146,10 @@ NNTreeImpl::insertFirst(QPDFObjectHandle key, QPDFObjectHandle value)
1097 } 1146 }
1098 items.insertItem(0, key); 1147 items.insertItem(0, key);
1099 items.insertItem(1, value); 1148 items.insertItem(1, value);
1100 - iter.item_number = 0; 1149 + iter.setItemNumber(iter.node, 0);
1101 iter.resetLimits(iter.node, iter.lastPathElement()); 1150 iter.resetLimits(iter.node, iter.lastPathElement());
1102 iter.split(iter.node, iter.lastPathElement()); 1151 iter.split(iter.node, iter.lastPathElement());
1103 - return begin(); 1152 + return iter;
1104 } 1153 }
1105 1154
1106 NNTreeImpl::iterator 1155 NNTreeImpl::iterator
@@ -1112,11 +1161,12 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value) @@ -1112,11 +1161,12 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value)
1112 QTC::TC("qpdf", "NNTree insert inserts first"); 1161 QTC::TC("qpdf", "NNTree insert inserts first");
1113 return insertFirst(key, value); 1162 return insertFirst(key, value);
1114 } 1163 }
1115 - else if (details.compareKeys(key, (*iter).first) == 0) 1164 + else if (details.compareKeys(key, iter->first) == 0)
1116 { 1165 {
1117 QTC::TC("qpdf", "NNTree insert replaces"); 1166 QTC::TC("qpdf", "NNTree insert replaces");
1118 auto items = iter.node.getKey(details.itemsKey()); 1167 auto items = iter.node.getKey(details.itemsKey());
1119 items.setArrayItem(iter.item_number + 1, value); 1168 items.setArrayItem(iter.item_number + 1, value);
  1169 + iter.updateIValue();
1120 } 1170 }
1121 else 1171 else
1122 { 1172 {
@@ -1137,7 +1187,7 @@ NNTreeImpl::remove(QPDFObjectHandle key, QPDFObjectHandle* value) @@ -1137,7 +1187,7 @@ NNTreeImpl::remove(QPDFObjectHandle key, QPDFObjectHandle* value)
1137 } 1187 }
1138 if (value) 1188 if (value)
1139 { 1189 {
1140 - *value = (*iter).second; 1190 + *value = iter->second;
1141 } 1191 }
1142 iter.remove(); 1192 iter.remove();
1143 return true; 1193 return true;
libqpdf/QPDF.cc
@@ -3011,7 +3011,7 @@ QPDF::findAttachmentStreams() @@ -3011,7 +3011,7 @@ QPDF::findAttachmentStreams()
3011 return; 3011 return;
3012 } 3012 }
3013 QPDFNameTreeObjectHelper ef_tree(embedded_files, *this); 3013 QPDFNameTreeObjectHelper ef_tree(embedded_files, *this);
3014 - for (auto i: ef_tree) 3014 + for (auto const& i: ef_tree)
3015 { 3015 {
3016 QPDFObjectHandle item = i.second; 3016 QPDFObjectHandle item = i.second;
3017 if (item.isDictionary() && 3017 if (item.isDictionary() &&
libqpdf/QPDFNameTreeObjectHelper.cc
@@ -79,6 +79,7 @@ QPDFNameTreeObjectHelper::iterator&amp; @@ -79,6 +79,7 @@ QPDFNameTreeObjectHelper::iterator&amp;
79 QPDFNameTreeObjectHelper::iterator::operator++() 79 QPDFNameTreeObjectHelper::iterator::operator++()
80 { 80 {
81 ++(*impl); 81 ++(*impl);
  82 + updateIValue();
82 return *this; 83 return *this;
83 } 84 }
84 85
@@ -86,14 +87,38 @@ QPDFNameTreeObjectHelper::iterator&amp; @@ -86,14 +87,38 @@ QPDFNameTreeObjectHelper::iterator&amp;
86 QPDFNameTreeObjectHelper::iterator::operator--() 87 QPDFNameTreeObjectHelper::iterator::operator--()
87 { 88 {
88 --(*impl); 89 --(*impl);
  90 + updateIValue();
89 return *this; 91 return *this;
90 } 92 }
91 93
  94 +void
  95 +QPDFNameTreeObjectHelper::iterator::updateIValue()
  96 +{
  97 + if (impl->valid())
  98 + {
  99 + auto p = *impl;
  100 + this->ivalue.first = p->first.getUTF8Value();
  101 + this->ivalue.second = p->second;
  102 + }
  103 + else
  104 + {
  105 + this->ivalue.first = "";
  106 + this->ivalue.second = QPDFObjectHandle();
  107 + }
  108 +}
  109 +
92 QPDFNameTreeObjectHelper::iterator::reference 110 QPDFNameTreeObjectHelper::iterator::reference
93 QPDFNameTreeObjectHelper::iterator::operator*() 111 QPDFNameTreeObjectHelper::iterator::operator*()
94 { 112 {
95 - auto p = **impl;  
96 - return std::make_pair(p.first.getUTF8Value(), p.second); 113 + updateIValue();
  114 + return this->ivalue;
  115 +}
  116 +
  117 +QPDFNameTreeObjectHelper::iterator::pointer
  118 +QPDFNameTreeObjectHelper::iterator::operator->()
  119 +{
  120 + updateIValue();
  121 + return &this->ivalue;
97 } 122 }
98 123
99 bool 124 bool
@@ -107,12 +132,14 @@ QPDFNameTreeObjectHelper::iterator::insertAfter( @@ -107,12 +132,14 @@ QPDFNameTreeObjectHelper::iterator::insertAfter(
107 std::string const& key, QPDFObjectHandle value) 132 std::string const& key, QPDFObjectHandle value)
108 { 133 {
109 impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value); 134 impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value);
  135 + updateIValue();
110 } 136 }
111 137
112 void 138 void
113 QPDFNameTreeObjectHelper::iterator::remove() 139 QPDFNameTreeObjectHelper::iterator::remove()
114 { 140 {
115 impl->remove(); 141 impl->remove();
  142 + updateIValue();
116 } 143 }
117 144
118 QPDFNameTreeObjectHelper::iterator 145 QPDFNameTreeObjectHelper::iterator
@@ -175,7 +202,7 @@ QPDFNameTreeObjectHelper::findObject( @@ -175,7 +202,7 @@ QPDFNameTreeObjectHelper::findObject(
175 { 202 {
176 return false; 203 return false;
177 } 204 }
178 - oh = (*i).second; 205 + oh = i->second;
179 return true; 206 return true;
180 } 207 }
181 208
libqpdf/QPDFNumberTreeObjectHelper.cc
@@ -75,6 +75,7 @@ QPDFNumberTreeObjectHelper::iterator&amp; @@ -75,6 +75,7 @@ QPDFNumberTreeObjectHelper::iterator&amp;
75 QPDFNumberTreeObjectHelper::iterator::operator++() 75 QPDFNumberTreeObjectHelper::iterator::operator++()
76 { 76 {
77 ++(*impl); 77 ++(*impl);
  78 + updateIValue();
78 return *this; 79 return *this;
79 } 80 }
80 81
@@ -82,14 +83,38 @@ QPDFNumberTreeObjectHelper::iterator&amp; @@ -82,14 +83,38 @@ QPDFNumberTreeObjectHelper::iterator&amp;
82 QPDFNumberTreeObjectHelper::iterator::operator--() 83 QPDFNumberTreeObjectHelper::iterator::operator--()
83 { 84 {
84 --(*impl); 85 --(*impl);
  86 + updateIValue();
85 return *this; 87 return *this;
86 } 88 }
87 89
  90 +void
  91 +QPDFNumberTreeObjectHelper::iterator::updateIValue()
  92 +{
  93 + if (impl->valid())
  94 + {
  95 + auto p = *impl;
  96 + this->ivalue.first = p->first.getIntValue();
  97 + this->ivalue.second = p->second;
  98 + }
  99 + else
  100 + {
  101 + this->ivalue.first = 0;
  102 + this->ivalue.second = QPDFObjectHandle();
  103 + }
  104 +}
  105 +
88 QPDFNumberTreeObjectHelper::iterator::reference 106 QPDFNumberTreeObjectHelper::iterator::reference
89 QPDFNumberTreeObjectHelper::iterator::operator*() 107 QPDFNumberTreeObjectHelper::iterator::operator*()
90 { 108 {
91 - auto p = **impl;  
92 - return std::make_pair(p.first.getIntValue(), p.second); 109 + updateIValue();
  110 + return this->ivalue;
  111 +}
  112 +
  113 +QPDFNumberTreeObjectHelper::iterator::pointer
  114 +QPDFNumberTreeObjectHelper::iterator::operator->()
  115 +{
  116 + updateIValue();
  117 + return &this->ivalue;
93 } 118 }
94 119
95 bool 120 bool
@@ -103,12 +128,14 @@ QPDFNumberTreeObjectHelper::iterator::insertAfter( @@ -103,12 +128,14 @@ QPDFNumberTreeObjectHelper::iterator::insertAfter(
103 numtree_number key, QPDFObjectHandle value) 128 numtree_number key, QPDFObjectHandle value)
104 { 129 {
105 impl->insertAfter(QPDFObjectHandle::newInteger(key), value); 130 impl->insertAfter(QPDFObjectHandle::newInteger(key), value);
  131 + updateIValue();
106 } 132 }
107 133
108 void 134 void
109 QPDFNumberTreeObjectHelper::iterator::remove() 135 QPDFNumberTreeObjectHelper::iterator::remove()
110 { 136 {
111 impl->remove(); 137 impl->remove();
  138 + updateIValue();
112 } 139 }
113 140
114 QPDFNumberTreeObjectHelper::iterator 141 QPDFNumberTreeObjectHelper::iterator
@@ -162,7 +189,7 @@ QPDFNumberTreeObjectHelper::getMin() @@ -162,7 +189,7 @@ QPDFNumberTreeObjectHelper::getMin()
162 { 189 {
163 return 0; 190 return 0;
164 } 191 }
165 - return (*i).first; 192 + return i->first;
166 } 193 }
167 194
168 QPDFNumberTreeObjectHelper::numtree_number 195 QPDFNumberTreeObjectHelper::numtree_number
@@ -173,7 +200,7 @@ QPDFNumberTreeObjectHelper::getMax() @@ -173,7 +200,7 @@ QPDFNumberTreeObjectHelper::getMax()
173 { 200 {
174 return 0; 201 return 0;
175 } 202 }
176 - return (*i).first; 203 + return i->first;
177 } 204 }
178 205
179 bool 206 bool
@@ -192,7 +219,7 @@ QPDFNumberTreeObjectHelper::findObject( @@ -192,7 +219,7 @@ QPDFNumberTreeObjectHelper::findObject(
192 { 219 {
193 return false; 220 return false;
194 } 221 }
195 - oh = (*i).second; 222 + oh = i->second;
196 return true; 223 return true;
197 } 224 }
198 225
@@ -206,8 +233,8 @@ QPDFNumberTreeObjectHelper::findObjectAtOrBelow( @@ -206,8 +233,8 @@ QPDFNumberTreeObjectHelper::findObjectAtOrBelow(
206 { 233 {
207 return false; 234 return false;
208 } 235 }
209 - oh = (*i).second;  
210 - offset = idx - (*i).first; 236 + oh = i->second;
  237 + offset = idx - i->first;
211 return true; 238 return true;
212 } 239 }
213 240
libqpdf/qpdf/NNTree.hh
@@ -6,6 +6,7 @@ @@ -6,6 +6,7 @@
6 6
7 #include <iterator> 7 #include <iterator>
8 #include <list> 8 #include <list>
  9 +#include <memory>
9 10
10 class NNTreeDetails 11 class NNTreeDetails
11 { 12 {
@@ -18,9 +19,6 @@ class NNTreeDetails @@ -18,9 +19,6 @@ class NNTreeDetails
18 class NNTreeImpl; 19 class NNTreeImpl;
19 class NNTreeIterator: public std::iterator< 20 class NNTreeIterator: public std::iterator<
20 std::bidirectional_iterator_tag, 21 std::bidirectional_iterator_tag,
21 - std::pair<QPDFObjectHandle, QPDFObjectHandle>,  
22 - void,  
23 - std::pair<QPDFObjectHandle, QPDFObjectHandle>*,  
24 std::pair<QPDFObjectHandle, QPDFObjectHandle>> 22 std::pair<QPDFObjectHandle, QPDFObjectHandle>>
25 { 23 {
26 friend class NNTreeImpl; 24 friend class NNTreeImpl;
@@ -41,6 +39,7 @@ class NNTreeIterator: public std::iterator&lt; @@ -41,6 +39,7 @@ class NNTreeIterator: public std::iterator&lt;
41 return t; 39 return t;
42 } 40 }
43 reference operator*(); 41 reference operator*();
  42 + pointer operator->();
44 bool operator==(NNTreeIterator const& other) const; 43 bool operator==(NNTreeIterator const& other) const;
45 bool operator!=(NNTreeIterator const& other) const 44 bool operator!=(NNTreeIterator const& other) const
46 { 45 {
@@ -63,6 +62,7 @@ class NNTreeIterator: public std::iterator&lt; @@ -63,6 +62,7 @@ class NNTreeIterator: public std::iterator&lt;
63 62
64 // ABI: for qpdf 11, make qpdf a reference 63 // ABI: for qpdf 11, make qpdf a reference
65 NNTreeIterator(NNTreeImpl& impl); 64 NNTreeIterator(NNTreeImpl& impl);
  65 + void updateIValue(bool allow_invalid = true);
66 bool deepen(QPDFObjectHandle node, bool first, bool allow_empty); 66 bool deepen(QPDFObjectHandle node, bool first, bool allow_empty);
67 void setItemNumber(QPDFObjectHandle const& node, int); 67 void setItemNumber(QPDFObjectHandle const& node, int);
68 void addPathElement(QPDFObjectHandle const& node, int kid_number); 68 void addPathElement(QPDFObjectHandle const& node, int kid_number);
@@ -79,6 +79,7 @@ class NNTreeIterator: public std::iterator&lt; @@ -79,6 +79,7 @@ class NNTreeIterator: public std::iterator&lt;
79 std::list<PathElement> path; 79 std::list<PathElement> path;
80 QPDFObjectHandle node; 80 QPDFObjectHandle node;
81 int item_number; 81 int item_number;
  82 + value_type ivalue;
82 }; 83 };
83 84
84 class NNTreeImpl 85 class NNTreeImpl
qpdf/test_driver.cc
@@ -1749,7 +1749,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1749,7 +1749,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1749 // number-tree.pdf 1749 // number-tree.pdf
1750 QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); 1750 QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest");
1751 QPDFNumberTreeObjectHelper ntoh(qtest, pdf); 1751 QPDFNumberTreeObjectHelper ntoh(qtest, pdf);
1752 - for (auto iter: ntoh) 1752 + for (auto& iter: ntoh)
1753 { 1753 {
1754 std::cout << iter.first << " " 1754 std::cout << iter.first << " "
1755 << iter.second.getStringValue() 1755 << iter.second.getStringValue()
@@ -1785,32 +1785,36 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1785,32 +1785,36 @@ void runtest(int n, char const* filename1, char const* arg2)
1785 assert(iter1 == new1.end()); 1785 assert(iter1 == new1.end());
1786 new1.insert(1, QPDFObjectHandle::newString("1")); 1786 new1.insert(1, QPDFObjectHandle::newString("1"));
1787 ++iter1; 1787 ++iter1;
1788 - assert((*iter1).first == 1); 1788 + assert((*iter1).first == 1); // exercise operator* explicitly
  1789 + auto& iter1_val = *iter1;
1789 --iter1; 1790 --iter1;
1790 assert(iter1 == new1.end()); 1791 assert(iter1 == new1.end());
1791 --iter1; 1792 --iter1;
1792 - assert((*iter1).first == 1); 1793 + assert(iter1->first == 1);
  1794 + assert(iter1_val.first == 1);
1793 new1.insert(2, QPDFObjectHandle::newString("2")); 1795 new1.insert(2, QPDFObjectHandle::newString("2"));
1794 ++iter1; 1796 ++iter1;
1795 - assert((*iter1).first == 2); 1797 + assert(iter1->first == 2);
  1798 + assert(iter1_val.first == 2);
1796 ++iter1; 1799 ++iter1;
1797 assert(iter1 == new1.end()); 1800 assert(iter1 == new1.end());
  1801 + assert(! iter1_val.second.isInitialized());
1798 ++iter1; 1802 ++iter1;
1799 - assert((*iter1).first == 1); 1803 + assert(iter1->first == 1);
1800 --iter1; 1804 --iter1;
1801 assert(iter1 == new1.end()); 1805 assert(iter1 == new1.end());
1802 --iter1; 1806 --iter1;
1803 - assert((*iter1).first == 2); 1807 + assert(iter1->first == 2);
1804 1808
1805 std::cout << "insertAfter" << std::endl; 1809 std::cout << "insertAfter" << std::endl;
1806 auto new2 = QPDFNumberTreeObjectHelper::newEmpty(pdf); 1810 auto new2 = QPDFNumberTreeObjectHelper::newEmpty(pdf);
1807 auto iter2 = new2.begin(); 1811 auto iter2 = new2.begin();
1808 assert(iter2 == new2.end()); 1812 assert(iter2 == new2.end());
1809 iter2.insertAfter(3, QPDFObjectHandle::newString("3!")); 1813 iter2.insertAfter(3, QPDFObjectHandle::newString("3!"));
1810 - assert((*iter2).first == 3); 1814 + assert(iter2->first == 3);
1811 iter2.insertAfter(4, QPDFObjectHandle::newString("4!")); 1815 iter2.insertAfter(4, QPDFObjectHandle::newString("4!"));
1812 - assert((*iter2).first == 4);  
1813 - for (auto i: new2) 1816 + assert(iter2->first == 4);
  1817 + for (auto& i: new2)
1814 { 1818 {
1815 std::cout << i.first << " " << i.second.unparse() << std::endl; 1819 std::cout << i.first << " " << i.second.unparse() << std::endl;
1816 } 1820 }
@@ -1830,7 +1834,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1830,7 +1834,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1830 std::cout << "/Bad2" << std::endl; 1834 std::cout << "/Bad2" << std::endl;
1831 auto bad2 = QPDFNumberTreeObjectHelper( 1835 auto bad2 = QPDFNumberTreeObjectHelper(
1832 pdf.getTrailer().getKey("/Bad2"), pdf); 1836 pdf.getTrailer().getKey("/Bad2"), pdf);
1833 - for (auto i: bad2) 1837 + for (auto& i: bad2)
1834 { 1838 {
1835 std::cout << i.first << " " << i.second.unparse() << std::endl; 1839 std::cout << i.first << " " << i.second.unparse() << std::endl;
1836 } 1840 }
@@ -1844,21 +1848,21 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1844,21 +1848,21 @@ void runtest(int n, char const* filename1, char const* arg2)
1844 assert(empty.begin() == empty.end()); 1848 assert(empty.begin() == empty.end());
1845 assert(empty.last() == empty.end()); 1849 assert(empty.last() == empty.end());
1846 auto i = empty.insert(5, QPDFObjectHandle::newString("5")); 1850 auto i = empty.insert(5, QPDFObjectHandle::newString("5"));
1847 - assert((*i).first == 5);  
1848 - assert((*i).second.getStringValue() == "5");  
1849 - assert((*empty.begin()).first == 5);  
1850 - assert((*empty.last()).first == 5);  
1851 - assert((*empty.begin()).second.getStringValue() == "5"); 1851 + assert(i->first == 5);
  1852 + assert(i->second.getStringValue() == "5");
  1853 + assert(empty.begin()->first == 5);
  1854 + assert(empty.last()->first == 5);
  1855 + assert(empty.begin()->second.getStringValue() == "5");
1852 i = empty.insert(5, QPDFObjectHandle::newString("5+")); 1856 i = empty.insert(5, QPDFObjectHandle::newString("5+"));
1853 - assert((*i).first == 5);  
1854 - assert((*i).second.getStringValue() == "5+");  
1855 - assert((*empty.begin()).second.getStringValue() == "5+"); 1857 + assert(i->first == 5);
  1858 + assert(i->second.getStringValue() == "5+");
  1859 + assert(empty.begin()->second.getStringValue() == "5+");
1856 i = empty.insert(6, QPDFObjectHandle::newString("6")); 1860 i = empty.insert(6, QPDFObjectHandle::newString("6"));
1857 - assert((*i).first == 6);  
1858 - assert((*i).second.getStringValue() == "6");  
1859 - assert((*empty.begin()).second.getStringValue() == "5+");  
1860 - assert((*empty.last()).first == 6);  
1861 - assert((*empty.last()).second.getStringValue() == "6"); 1861 + assert(i->first == 6);
  1862 + assert(i->second.getStringValue() == "6");
  1863 + assert(empty.begin()->second.getStringValue() == "5+");
  1864 + assert(empty.last()->first == 6);
  1865 + assert(empty.last()->second.getStringValue() == "6");
1862 } 1866 }
1863 std::cout << "Insert into invalid" << std::endl; 1867 std::cout << "Insert into invalid" << std::endl;
1864 auto invalid1 = QPDFNumberTreeObjectHelper( 1868 auto invalid1 = QPDFNumberTreeObjectHelper(
@@ -1875,7 +1879,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1875,7 +1879,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1875 std::cout << "/Bad3, no repair" << std::endl; 1879 std::cout << "/Bad3, no repair" << std::endl;
1876 auto bad3_oh = pdf.getTrailer().getKey("/Bad3"); 1880 auto bad3_oh = pdf.getTrailer().getKey("/Bad3");
1877 auto bad3 = QPDFNumberTreeObjectHelper(bad3_oh, pdf, false); 1881 auto bad3 = QPDFNumberTreeObjectHelper(bad3_oh, pdf, false);
1878 - for (auto i: bad3) 1882 + for (auto& i: bad3)
1879 { 1883 {
1880 std::cout << i.first << " " << i.second.unparse() << std::endl; 1884 std::cout << i.first << " " << i.second.unparse() << std::endl;
1881 } 1885 }
@@ -1883,7 +1887,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1883,7 +1887,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1883 1887
1884 std::cout << "/Bad3, repair" << std::endl; 1888 std::cout << "/Bad3, repair" << std::endl;
1885 bad3 = QPDFNumberTreeObjectHelper(bad3_oh, pdf, true); 1889 bad3 = QPDFNumberTreeObjectHelper(bad3_oh, pdf, true);
1886 - for (auto i: bad3) 1890 + for (auto& i: bad3)
1887 { 1891 {
1888 std::cout << i.first << " " << i.second.unparse() << std::endl; 1892 std::cout << i.first << " " << i.second.unparse() << std::endl;
1889 } 1893 }
@@ -1893,7 +1897,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1893,7 +1897,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1893 auto bad4 = QPDFNumberTreeObjectHelper( 1897 auto bad4 = QPDFNumberTreeObjectHelper(
1894 pdf.getTrailer().getKey("/Bad4"), pdf); 1898 pdf.getTrailer().getKey("/Bad4"), pdf);
1895 bad4.insert(5, QPDFObjectHandle::newString("5")); 1899 bad4.insert(5, QPDFObjectHandle::newString("5"));
1896 - for (auto i: bad4) 1900 + for (auto& i: bad4)
1897 { 1901 {
1898 std::cout << i.first << " " << i.second.unparse() << std::endl; 1902 std::cout << i.first << " " << i.second.unparse() << std::endl;
1899 } 1903 }
@@ -1924,7 +1928,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1924,7 +1928,7 @@ void runtest(int n, char const* filename1, char const* arg2)
1924 // name-tree.pdf 1928 // name-tree.pdf
1925 QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest"); 1929 QPDFObjectHandle qtest = pdf.getTrailer().getKey("/QTest");
1926 QPDFNameTreeObjectHelper ntoh(qtest, pdf); 1930 QPDFNameTreeObjectHelper ntoh(qtest, pdf);
1927 - for (auto iter: ntoh) 1931 + for (auto& iter: ntoh)
1928 { 1932 {
1929 std::cout << iter.first << " -> " 1933 std::cout << iter.first << " -> "
1930 << iter.second.getStringValue() 1934 << iter.second.getStringValue()
@@ -1945,8 +1949,8 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1945,8 +1949,8 @@ void runtest(int n, char const* filename1, char const* arg2)
1945 assert(ntoh.findObject("07 sev\xe2\x80\xa2n", oh)); 1949 assert(ntoh.findObject("07 sev\xe2\x80\xa2n", oh));
1946 assert("seven!" == oh.getStringValue()); 1950 assert("seven!" == oh.getStringValue());
1947 auto last = ntoh.last(); 1951 auto last = ntoh.last();
1948 - assert((*last).first == "29 twenty-nine");  
1949 - assert((*last).second.getUTF8Value() == "twenty-nine!"); 1952 + assert(last->first == "29 twenty-nine");
  1953 + assert(last->second.getUTF8Value() == "twenty-nine!");
1950 1954
1951 auto new1 = QPDFNameTreeObjectHelper::newEmpty(pdf); 1955 auto new1 = QPDFNameTreeObjectHelper::newEmpty(pdf);
1952 auto iter1 = new1.begin(); 1956 auto iter1 = new1.begin();
@@ -1957,32 +1961,36 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1957,32 +1961,36 @@ void runtest(int n, char const* filename1, char const* arg2)
1957 assert(iter1 == new1.end()); 1961 assert(iter1 == new1.end());
1958 new1.insert("1", QPDFObjectHandle::newString("1")); 1962 new1.insert("1", QPDFObjectHandle::newString("1"));
1959 ++iter1; 1963 ++iter1;
1960 - assert((*iter1).first == "1"); 1964 + assert(iter1->first == "1");
  1965 + auto& iter1_val = *iter1;
1961 --iter1; 1966 --iter1;
1962 assert(iter1 == new1.end()); 1967 assert(iter1 == new1.end());
1963 --iter1; 1968 --iter1;
1964 - assert((*iter1).first == "1"); 1969 + assert(iter1->first == "1");
  1970 + assert(iter1_val.first == "1");
1965 new1.insert("2", QPDFObjectHandle::newString("2")); 1971 new1.insert("2", QPDFObjectHandle::newString("2"));
1966 ++iter1; 1972 ++iter1;
1967 - assert((*iter1).first == "2"); 1973 + assert(iter1->first == "2");
  1974 + assert(iter1_val.first == "2");
1968 ++iter1; 1975 ++iter1;
1969 assert(iter1 == new1.end()); 1976 assert(iter1 == new1.end());
  1977 + assert(! iter1_val.second.isInitialized());
1970 ++iter1; 1978 ++iter1;
1971 - assert((*iter1).first == "1"); 1979 + assert(iter1->first == "1");
1972 --iter1; 1980 --iter1;
1973 assert(iter1 == new1.end()); 1981 assert(iter1 == new1.end());
1974 --iter1; 1982 --iter1;
1975 - assert((*iter1).first == "2"); 1983 + assert(iter1->first == "2");
1976 1984
1977 std::cout << "insertAfter" << std::endl; 1985 std::cout << "insertAfter" << std::endl;
1978 auto new2 = QPDFNameTreeObjectHelper::newEmpty(pdf); 1986 auto new2 = QPDFNameTreeObjectHelper::newEmpty(pdf);
1979 auto iter2 = new2.begin(); 1987 auto iter2 = new2.begin();
1980 assert(iter2 == new2.end()); 1988 assert(iter2 == new2.end());
1981 iter2.insertAfter("3", QPDFObjectHandle::newString("3!")); 1989 iter2.insertAfter("3", QPDFObjectHandle::newString("3!"));
1982 - assert((*iter2).first == "3"); 1990 + assert(iter2->first == "3");
1983 iter2.insertAfter("4", QPDFObjectHandle::newString("4!")); 1991 iter2.insertAfter("4", QPDFObjectHandle::newString("4!"));
1984 - assert((*iter2).first == "4");  
1985 - for (auto i: new2) 1992 + assert(iter2->first == "4");
  1993 + for (auto& i: new2)
1986 { 1994 {
1987 std::cout << i.first << " " << i.second.unparse() << std::endl; 1995 std::cout << i.first << " " << i.second.unparse() << std::endl;
1988 } 1996 }
@@ -1996,21 +2004,21 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -1996,21 +2004,21 @@ void runtest(int n, char const* filename1, char const* arg2)
1996 assert(empty.begin() == empty.end()); 2004 assert(empty.begin() == empty.end());
1997 assert(empty.last() == empty.end()); 2005 assert(empty.last() == empty.end());
1998 auto i = empty.insert("five", QPDFObjectHandle::newString("5")); 2006 auto i = empty.insert("five", QPDFObjectHandle::newString("5"));
1999 - assert((*i).first == "five");  
2000 - assert((*i).second.getStringValue() == "5");  
2001 - assert((*empty.begin()).first == "five");  
2002 - assert((*empty.last()).first == "five");  
2003 - assert((*empty.begin()).second.getStringValue() == "5"); 2007 + assert(i->first == "five");
  2008 + assert(i->second.getStringValue() == "5");
  2009 + assert(empty.begin()->first == "five");
  2010 + assert(empty.last()->first == "five");
  2011 + assert(empty.begin()->second.getStringValue() == "5");
2004 i = empty.insert("five", QPDFObjectHandle::newString("5+")); 2012 i = empty.insert("five", QPDFObjectHandle::newString("5+"));
2005 - assert((*i).first == "five");  
2006 - assert((*i).second.getStringValue() == "5+");  
2007 - assert((*empty.begin()).second.getStringValue() == "5+"); 2013 + assert(i->first == "five");
  2014 + assert(i->second.getStringValue() == "5+");
  2015 + assert(empty.begin()->second.getStringValue() == "5+");
2008 i = empty.insert("six", QPDFObjectHandle::newString("6")); 2016 i = empty.insert("six", QPDFObjectHandle::newString("6"));
2009 - assert((*i).first == "six");  
2010 - assert((*i).second.getStringValue() == "6");  
2011 - assert((*empty.begin()).second.getStringValue() == "5+");  
2012 - assert((*empty.last()).first == "six");  
2013 - assert((*empty.last()).second.getStringValue() == "6"); 2017 + assert(i->first == "six");
  2018 + assert(i->second.getStringValue() == "6");
  2019 + assert(empty.begin()->second.getStringValue() == "5+");
  2020 + assert(empty.last()->first == "six");
  2021 + assert(empty.last()->second.getStringValue() == "6");
2014 } 2022 }
2015 2023
2016 // Exercise deprecated API until qpdf 11 2024 // Exercise deprecated API until qpdf 11
@@ -2030,8 +2038,8 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2030,8 +2038,8 @@ void runtest(int n, char const* filename1, char const* arg2)
2030 std::cout << "/Bad1 -- wrong key type" << std::endl; 2038 std::cout << "/Bad1 -- wrong key type" << std::endl;
2031 bad1 = QPDFNameTreeObjectHelper( 2039 bad1 = QPDFNameTreeObjectHelper(
2032 pdf.getTrailer().getKey("/Bad1"), pdf); 2040 pdf.getTrailer().getKey("/Bad1"), pdf);
2033 - assert((*bad1.find("G", true)).first == "A");  
2034 - for (auto i: bad1) 2041 + assert(bad1.find("G", true)->first == "A");
  2042 + for (auto const& i: bad1)
2035 { 2043 {
2036 std::cout << i.first << std::endl; 2044 std::cout << i.first << std::endl;
2037 } 2045 }
@@ -2039,8 +2047,8 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2039,8 +2047,8 @@ void runtest(int n, char const* filename1, char const* arg2)
2039 std::cout << "/Bad2 -- invalid kid" << std::endl; 2047 std::cout << "/Bad2 -- invalid kid" << std::endl;
2040 auto bad2 = QPDFNameTreeObjectHelper( 2048 auto bad2 = QPDFNameTreeObjectHelper(
2041 pdf.getTrailer().getKey("/Bad2"), pdf); 2049 pdf.getTrailer().getKey("/Bad2"), pdf);
2042 - assert((*bad2.find("G", true)).first == "B");  
2043 - for (auto i: bad2) 2050 + assert(bad2.find("G", true)->first == "B");
  2051 + for (auto const& i: bad2)
2044 { 2052 {
2045 std::cout << i.first << std::endl; 2053 std::cout << i.first << std::endl;
2046 } 2054 }
@@ -2053,8 +2061,8 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2053,8 +2061,8 @@ void runtest(int n, char const* filename1, char const* arg2)
2053 std::cout << "/Bad4 -- invalid kid" << std::endl; 2061 std::cout << "/Bad4 -- invalid kid" << std::endl;
2054 auto bad4 = QPDFNameTreeObjectHelper( 2062 auto bad4 = QPDFNameTreeObjectHelper(
2055 pdf.getTrailer().getKey("/Bad4"), pdf); 2063 pdf.getTrailer().getKey("/Bad4"), pdf);
2056 - assert((*bad4.find("F", true)).first == "C");  
2057 - for (auto i: bad4) 2064 + assert(bad4.find("F", true)->first == "C");
  2065 + for (auto const& i: bad4)
2058 { 2066 {
2059 std::cout << i.first << std::endl; 2067 std::cout << i.first << std::endl;
2060 } 2068 }
@@ -2062,12 +2070,12 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2062,12 +2070,12 @@ void runtest(int n, char const* filename1, char const* arg2)
2062 std::cout << "/Bad5 -- loop in find" << std::endl; 2070 std::cout << "/Bad5 -- loop in find" << std::endl;
2063 auto bad5 = QPDFNameTreeObjectHelper( 2071 auto bad5 = QPDFNameTreeObjectHelper(
2064 pdf.getTrailer().getKey("/Bad5"), pdf); 2072 pdf.getTrailer().getKey("/Bad5"), pdf);
2065 - assert((*bad5.find("F", true)).first == "D"); 2073 + assert(bad5.find("F", true)->first == "D");
2066 2074
2067 std::cout << "/Bad6 -- bad limits" << std::endl; 2075 std::cout << "/Bad6 -- bad limits" << std::endl;
2068 auto bad6 = QPDFNameTreeObjectHelper( 2076 auto bad6 = QPDFNameTreeObjectHelper(
2069 pdf.getTrailer().getKey("/Bad6"), pdf); 2077 pdf.getTrailer().getKey("/Bad6"), pdf);
2070 - assert((*bad6.insert("H", QPDFObjectHandle::newNull())).first == "H"); 2078 + assert(bad6.insert("H", QPDFObjectHandle::newNull())->first == "H");
2071 } 2079 }
2072 else if (n == 49) 2080 else if (n == 49)
2073 { 2081 {
@@ -2574,12 +2582,12 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2574,12 +2582,12 @@ void runtest(int n, char const* filename1, char const* arg2)
2574 auto check_split1 = [&split1](int k) { 2582 auto check_split1 = [&split1](int k) {
2575 auto i = split1.insert(k, QPDFObjectHandle::newString( 2583 auto i = split1.insert(k, QPDFObjectHandle::newString(
2576 QUtil::int_to_string(k))); 2584 QUtil::int_to_string(k)));
2577 - assert((*i).first == k); 2585 + assert(i->first == k);
2578 }; 2586 };
2579 check_split1(15); 2587 check_split1(15);
2580 check_split1(35); 2588 check_split1(35);
2581 check_split1(125); 2589 check_split1(125);
2582 - for (auto i: split1) 2590 + for (auto const& i: split1)
2583 { 2591 {
2584 std::cout << i.first << std::endl; 2592 std::cout << i.first << std::endl;
2585 } 2593 }
@@ -2591,10 +2599,10 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2591,10 +2599,10 @@ void runtest(int n, char const* filename1, char const* arg2)
2591 auto check_split2 = [](QPDFNameTreeObjectHelper& noh, 2599 auto check_split2 = [](QPDFNameTreeObjectHelper& noh,
2592 std::string const& k) { 2600 std::string const& k) {
2593 auto i = noh.insert(k, QPDFObjectHandle::newUnicodeString(k)); 2601 auto i = noh.insert(k, QPDFObjectHandle::newUnicodeString(k));
2594 - assert((*i).first == k); 2602 + assert(i->first == k);
2595 }; 2603 };
2596 check_split2(split2, "C"); 2604 check_split2(split2, "C");
2597 - for (auto i: split2) 2605 + for (auto const& i: split2)
2598 { 2606 {
2599 std::cout << i.first << std::endl; 2607 std::cout << i.first << std::endl;
2600 } 2608 }
@@ -2605,7 +2613,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2605,7 +2613,7 @@ void runtest(int n, char const* filename1, char const* arg2)
2605 split3.setSplitThreshold(4); 2613 split3.setSplitThreshold(4);
2606 check_split2(split3, "P"); 2614 check_split2(split3, "P");
2607 check_split2(split3, "\xcf\x80"); 2615 check_split2(split3, "\xcf\x80");
2608 - for (auto i: split3) 2616 + for (auto& i: split3)
2609 { 2617 {
2610 std::cout << i.first << " " << i.second.unparse() << std::endl; 2618 std::cout << i.first << " " << i.second.unparse() << std::endl;
2611 } 2619 }
@@ -2626,11 +2634,11 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2626,11 +2634,11 @@ void runtest(int n, char const* filename1, char const* arg2)
2626 assert(value.getUTF8Value() == "c"); 2634 assert(value.getUTF8Value() == "c");
2627 auto iter1 = erase1.find("1B"); 2635 auto iter1 = erase1.find("1B");
2628 iter1.remove(); 2636 iter1.remove();
2629 - assert((*iter1).first == "1D"); 2637 + assert(iter1->first == "1D");
2630 iter1.remove(); 2638 iter1.remove();
2631 assert(iter1 == erase1.end()); 2639 assert(iter1 == erase1.end());
2632 --iter1; 2640 --iter1;
2633 - assert((*iter1).first == "1A"); 2641 + assert(iter1->first == "1A");
2634 iter1.remove(); 2642 iter1.remove();
2635 assert(iter1 == erase1.end()); 2643 assert(iter1 == erase1.end());
2636 2644
@@ -2640,14 +2648,14 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2640,14 +2648,14 @@ void runtest(int n, char const* filename1, char const* arg2)
2640 iter2.remove(); 2648 iter2.remove();
2641 assert(iter2 == erase2.end()); 2649 assert(iter2 == erase2.end());
2642 --iter2; 2650 --iter2;
2643 - assert((*iter2).first == 240); 2651 + assert(iter2->first == 240);
2644 auto k1 = erase2_oh.getKey("/Kids").getArrayItem(1); 2652 auto k1 = erase2_oh.getKey("/Kids").getArrayItem(1);
2645 auto l1 = k1.getKey("/Limits"); 2653 auto l1 = k1.getKey("/Limits");
2646 assert(l1.getArrayItem(0).getIntValue() == 230); 2654 assert(l1.getArrayItem(0).getIntValue() == 230);
2647 assert(l1.getArrayItem(1).getIntValue() == 240); 2655 assert(l1.getArrayItem(1).getIntValue() == 240);
2648 iter2 = erase2.find(210); 2656 iter2 = erase2.find(210);
2649 iter2.remove(); 2657 iter2.remove();
2650 - assert((*iter2).first == 220); 2658 + assert(iter2->first == 220);
2651 k1 = erase2_oh.getKey("/Kids").getArrayItem(0); 2659 k1 = erase2_oh.getKey("/Kids").getArrayItem(0);
2652 l1 = k1.getKey("/Limits"); 2660 l1 = k1.getKey("/Limits");
2653 assert(l1.getArrayItem(0).getIntValue() == 220); 2661 assert(l1.getArrayItem(0).getIntValue() == 220);
@@ -2667,7 +2675,7 @@ void runtest(int n, char const* filename1, char const* arg2) @@ -2667,7 +2675,7 @@ void runtest(int n, char const* filename1, char const* arg2)
2667 pdf.getTrailer().getKey("/Erase4"), pdf); 2675 pdf.getTrailer().getKey("/Erase4"), pdf);
2668 iter2 = erase4.find(420); 2676 iter2 = erase4.find(420);
2669 iter2.remove(); 2677 iter2.remove();
2670 - assert((*iter2).first == 430); 2678 + assert(iter2->first == 430);
2671 2679
2672 QPDFWriter w(pdf, "a.pdf"); 2680 QPDFWriter w(pdf, "a.pdf");
2673 w.setStaticID(true); 2681 w.setStaticID(true);