Commit 8ed3e8c79b5cbccfeccee865e555b68025ee2c1f
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.
Showing
8 changed files
with
228 additions
and
111 deletions
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& impl) : | @@ -50,6 +50,57 @@ NNTreeIterator::NNTreeIterator(NNTreeImpl& 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& other) const | @@ -660,7 +708,7 @@ NNTreeIterator::operator==(NNTreeIterator const& 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& node, int n) | @@ -679,6 +727,7 @@ NNTreeIterator::setItemNumber(QPDFObjectHandle const& 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& | @@ -79,6 +79,7 @@ QPDFNameTreeObjectHelper::iterator& | ||
| 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& | @@ -86,14 +87,38 @@ QPDFNameTreeObjectHelper::iterator& | ||
| 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& | @@ -75,6 +75,7 @@ QPDFNumberTreeObjectHelper::iterator& | ||
| 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& | @@ -82,14 +83,38 @@ QPDFNumberTreeObjectHelper::iterator& | ||
| 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< | @@ -41,6 +39,7 @@ class NNTreeIterator: public std::iterator< | ||
| 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< | @@ -63,6 +62,7 @@ class NNTreeIterator: public std::iterator< | ||
| 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< | @@ -79,6 +79,7 @@ class NNTreeIterator: public std::iterator< | ||
| 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); |