Commit 0d08f65cb8a106ef13f0677e46f0d01ae2743147

Authored by m-holger
1 parent 68ac2179

Add new method ObjTable::resize

Showing 1 changed file with 33 additions and 10 deletions
libqpdf/qpdf/ObjTable.hh
... ... @@ -102,17 +102,26 @@ class ObjTable: public std::vector<T>
102 102 void
103 103 initialize(size_t idx)
104 104 {
105   - if (std::vector<T>::size() > 0 || sparse_elements.size() > 0) {
  105 + if (std::vector<T>::size() > 0 || !sparse_elements.empty()) {
106 106 throw ::std::logic_error("ObjTable accessed before initialization");
107   - } else if (
108   - idx >= static_cast<size_t>(std::numeric_limits<int>::max()) ||
109   - idx >= std::vector<T>::max_size()) {
110   - throw std::runtime_error("Invalid maximum object id initializing ObjTable.");
111   - } else {
112   - std::vector<T>::resize(++idx);
113 107 }
  108 + resize(++idx);
114 109 }
115 110  
  111 + void
  112 + resize(size_t a_size)
  113 + {
  114 + std::vector<T>::resize(a_size);
  115 + if (a_size > min_sparse) {
  116 + auto it = sparse_elements.begin();
  117 + auto end = sparse_elements.end();
  118 + while (it != end && it->first < a_size) {
  119 + std::vector<T>::operator[](it->first) = std::move(it->second);
  120 + it = sparse_elements.erase(it);
  121 + }
  122 + min_sparse = (it == end) ? std::numeric_limits<size_t>::max() : it->first;
  123 + }
  124 + }
116 125  
117 126 inline void
118 127 forEach(std::function<void(int, const T&)> fn)
... ... @@ -128,14 +137,27 @@ class ObjTable: public std::vector&lt;T&gt;
128 137  
129 138 private:
130 139 std::map<size_t, T> sparse_elements;
  140 + // Smallest id present in sparse_elements.
  141 + size_t min_sparse{std::numeric_limits<size_t>::max()};
131 142  
132 143 inline T&
133 144 element(size_t idx)
134 145 {
135   - static const size_t max_size = std::vector<T>::max_size();
136 146 if (idx < std::vector<T>::size()) {
137 147 return std::vector<T>::operator[](idx);
138   - } else if (idx < max_size) {
  148 + }
  149 + return large_element(idx);
  150 + }
  151 +
  152 + // Must only be called by element. Separated out from element to keep inlined code tight.
  153 + T&
  154 + large_element(size_t idx)
  155 + {
  156 + static const size_t max_size = std::vector<T>::max_size();
  157 + if (idx < min_sparse) {
  158 + min_sparse = idx;
  159 + }
  160 + if (idx < max_size) {
139 161 return sparse_elements[idx];
140 162 }
141 163 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable");
... ... @@ -148,7 +170,8 @@ class ObjTable: public std::vector&lt;T&gt;
148 170 static const size_t max_size = std::vector<T>::max_size();
149 171 if (idx < std::vector<T>::size()) {
150 172 return std::vector<T>::operator[](idx);
151   - } else if (idx < max_size) {
  173 + }
  174 + if (idx < max_size) {
152 175 return sparse_elements.at(idx);
153 176 }
154 177 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable");
... ...