Commit 5816fb44b8ce24e8bb58cb30792e1c763d6cb163

Authored by Jay Berkenbilt
1 parent 16a9bb3f

name/number trees: insertAfter

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&amp; 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&amp; 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
... ... @@ -552,3 +552,4 @@ NNTree bad node during find 0
552 552 NNTree node is not a dictionary 0
553 553 NNTree limits didn't change 0
554 554 NNTree increment end() 0
  555 +NNTree insertAfter inserts first 0
... ...
qpdf/qtest/qpdf/name-tree.out
... ... @@ -16,6 +16,9 @@
16 16 20 twenty -> twenty.
17 17 22 twenty-two -> twenty-two!
18 18 29 twenty-nine -> twenty-nine!
  19 +insertAfter
  20 +3 (3!)
  21 +4 (4!)
19 22 /Empty1
20 23 /Empty2
21 24 /Bad1: deprecated API
... ...
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 {
... ...