Commit 5816fb44b8ce24e8bb58cb30792e1c763d6cb163
1 parent
16a9bb3f
name/number trees: insertAfter
Showing
9 changed files
with
82 additions
and
1 deletions
include/qpdf/QPDFNameTreeObjectHelper.hh
| ... | ... | @@ -112,6 +112,19 @@ class QPDFNameTreeObjectHelper: public QPDFObjectHelper |
| 112 | 112 | return ! operator==(other); |
| 113 | 113 | } |
| 114 | 114 | |
| 115 | + // DANGER: this method can create inconsistent trees if not | |
| 116 | + // used properly! Insert a new item immediately after the | |
| 117 | + // current iterator and increment so that it points to the new | |
| 118 | + // item. If the current iterator is end(), insert at the | |
| 119 | + // beginning. This method does not check for proper ordering, | |
| 120 | + // so if you use it, you must ensure that the item you are | |
| 121 | + // inserting belongs where you are putting it. The reason for | |
| 122 | + // this method is that it is more efficient than insert() and | |
| 123 | + // can be used safely when you are creating a new tree and | |
| 124 | + // inserting items in sorted order. | |
| 125 | + QPDF_DLL | |
| 126 | + void insertAfter(std::string const& key, QPDFObjectHandle value); | |
| 127 | + | |
| 115 | 128 | private: |
| 116 | 129 | iterator(std::shared_ptr<NNTreeIterator> const&); |
| 117 | 130 | std::shared_ptr<NNTreeIterator> impl; | ... | ... |
include/qpdf/QPDFNumberTreeObjectHelper.hh
| ... | ... | @@ -131,6 +131,19 @@ class QPDFNumberTreeObjectHelper: public QPDFObjectHelper |
| 131 | 131 | return ! operator==(other); |
| 132 | 132 | } |
| 133 | 133 | |
| 134 | + // DANGER: this method can create inconsistent trees if not | |
| 135 | + // used properly! Insert a new item immediately after the | |
| 136 | + // current iterator and increment so that it points to the new | |
| 137 | + // item. If the current iterator is end(), insert at the | |
| 138 | + // beginning. This method does not check for proper ordering, | |
| 139 | + // so if you use it, you must ensure that the item you are | |
| 140 | + // inserting belongs where you are putting it. The reason for | |
| 141 | + // this method is that it is more efficient than insert() and | |
| 142 | + // can be used safely when you are creating a new tree and | |
| 143 | + // inserting items in sorted order. | |
| 144 | + QPDF_DLL | |
| 145 | + void insertAfter(numtree_number key, QPDFObjectHandle value); | |
| 146 | + | |
| 134 | 147 | private: |
| 135 | 148 | iterator(std::shared_ptr<NNTreeIterator> const&); |
| 136 | 149 | std::shared_ptr<NNTreeIterator> impl; | ... | ... |
libqpdf/NNTree.cc
| ... | ... | @@ -444,6 +444,14 @@ NNTreeIterator::lastPathElement() |
| 444 | 444 | void |
| 445 | 445 | NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value) |
| 446 | 446 | { |
| 447 | + if (! valid()) | |
| 448 | + { | |
| 449 | + QTC::TC("qpdf", "NNTree insertAfter inserts first"); | |
| 450 | + impl.insertFirst(key, value); | |
| 451 | + deepen(impl.oh, true, false); | |
| 452 | + return; | |
| 453 | + } | |
| 454 | + | |
| 447 | 455 | auto items = this->node.getKey(impl.details.itemsKey()); |
| 448 | 456 | if (! items.isArray()) |
| 449 | 457 | { |
| ... | ... | @@ -457,6 +465,7 @@ NNTreeIterator::insertAfter(QPDFObjectHandle key, QPDFObjectHandle value) |
| 457 | 465 | items.insertItem(this->item_number + 3, value); |
| 458 | 466 | resetLimits(this->node, lastPathElement()); |
| 459 | 467 | split(this->node, lastPathElement()); |
| 468 | + increment(false); | |
| 460 | 469 | } |
| 461 | 470 | |
| 462 | 471 | NNTreeIterator& |
| ... | ... | @@ -968,7 +977,6 @@ NNTreeImpl::insert(QPDFObjectHandle key, QPDFObjectHandle value) |
| 968 | 977 | { |
| 969 | 978 | QTC::TC("qpdf", "NNTree insert inserts after"); |
| 970 | 979 | iter.insertAfter(key, value); |
| 971 | - ++iter; | |
| 972 | 980 | } |
| 973 | 981 | return iter; |
| 974 | 982 | } | ... | ... |
libqpdf/QPDFNameTreeObjectHelper.cc
| ... | ... | @@ -102,6 +102,13 @@ QPDFNameTreeObjectHelper::iterator::operator==(iterator const& other) const |
| 102 | 102 | return *(impl) == *(other.impl); |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | +void | |
| 106 | +QPDFNameTreeObjectHelper::iterator::insertAfter( | |
| 107 | + std::string const& key, QPDFObjectHandle value) | |
| 108 | +{ | |
| 109 | + impl->insertAfter(QPDFObjectHandle::newUnicodeString(key), value); | |
| 110 | +} | |
| 111 | + | |
| 105 | 112 | QPDFNameTreeObjectHelper::iterator |
| 106 | 113 | QPDFNameTreeObjectHelper::begin() const |
| 107 | 114 | { | ... | ... |
libqpdf/QPDFNumberTreeObjectHelper.cc
| ... | ... | @@ -98,6 +98,13 @@ QPDFNumberTreeObjectHelper::iterator::operator==(iterator const& other) const |
| 98 | 98 | return *(impl) == *(other.impl); |
| 99 | 99 | } |
| 100 | 100 | |
| 101 | +void | |
| 102 | +QPDFNumberTreeObjectHelper::iterator::insertAfter( | |
| 103 | + numtree_number key, QPDFObjectHandle value) | |
| 104 | +{ | |
| 105 | + impl->insertAfter(QPDFObjectHandle::newInteger(key), value); | |
| 106 | +} | |
| 107 | + | |
| 101 | 108 | QPDFNumberTreeObjectHelper::iterator |
| 102 | 109 | QPDFNumberTreeObjectHelper::begin() const |
| 103 | 110 | { | ... | ... |
qpdf/qpdf.testcov
qpdf/qtest/qpdf/name-tree.out
qpdf/qtest/qpdf/number-tree.out
| ... | ... | @@ -26,6 +26,9 @@ |
| 26 | 26 | 22 twenty-two |
| 27 | 27 | 23 twenty-three |
| 28 | 28 | 29 twenty-nine |
| 29 | +insertAfter | |
| 30 | +3 (3!) | |
| 31 | +4 (4!) | |
| 29 | 32 | /Bad1: deprecated API |
| 30 | 33 | /Bad1 |
| 31 | 34 | WARNING: number-tree.pdf (Name/Number tree node (object 14)): name/number tree node has neither non-empty /Nums nor /Kids | ... | ... |
qpdf/test_driver.cc
| ... | ... | @@ -1802,6 +1802,19 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1802 | 1802 | --iter1; |
| 1803 | 1803 | assert((*iter1).first == 2); |
| 1804 | 1804 | |
| 1805 | + std::cout << "insertAfter" << std::endl; | |
| 1806 | + auto new2 = QPDFNumberTreeObjectHelper::newEmpty(pdf); | |
| 1807 | + auto iter2 = new2.begin(); | |
| 1808 | + assert(iter2 == new2.end()); | |
| 1809 | + iter2.insertAfter(3, QPDFObjectHandle::newString("3!")); | |
| 1810 | + assert((*iter2).first == 3); | |
| 1811 | + iter2.insertAfter(4, QPDFObjectHandle::newString("4!")); | |
| 1812 | + assert((*iter2).first == 4); | |
| 1813 | + for (auto i: new2) | |
| 1814 | + { | |
| 1815 | + std::cout << i.first << " " << i.second.unparse() << std::endl; | |
| 1816 | + } | |
| 1817 | + | |
| 1805 | 1818 | // Exercise deprecated API until qpdf 11 |
| 1806 | 1819 | std::cout << "/Bad1: deprecated API" << std::endl; |
| 1807 | 1820 | auto bad1 = QPDFNumberTreeObjectHelper( |
| ... | ... | @@ -1961,6 +1974,19 @@ void runtest(int n, char const* filename1, char const* arg2) |
| 1961 | 1974 | --iter1; |
| 1962 | 1975 | assert((*iter1).first == "2"); |
| 1963 | 1976 | |
| 1977 | + std::cout << "insertAfter" << std::endl; | |
| 1978 | + auto new2 = QPDFNameTreeObjectHelper::newEmpty(pdf); | |
| 1979 | + auto iter2 = new2.begin(); | |
| 1980 | + assert(iter2 == new2.end()); | |
| 1981 | + iter2.insertAfter("3", QPDFObjectHandle::newString("3!")); | |
| 1982 | + assert((*iter2).first == "3"); | |
| 1983 | + iter2.insertAfter("4", QPDFObjectHandle::newString("4!")); | |
| 1984 | + assert((*iter2).first == "4"); | |
| 1985 | + for (auto i: new2) | |
| 1986 | + { | |
| 1987 | + std::cout << i.first << " " << i.second.unparse() << std::endl; | |
| 1988 | + } | |
| 1989 | + | |
| 1964 | 1990 | std::vector<std::string> empties = {"/Empty1", "/Empty2"}; |
| 1965 | 1991 | for (auto const& k: empties) |
| 1966 | 1992 | { | ... | ... |