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,17 +102,26 @@ class ObjTable: public std::vector<T>
102 void 102 void
103 initialize(size_t idx) 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 throw ::std::logic_error("ObjTable accessed before initialization"); 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 inline void 126 inline void
118 forEach(std::function<void(int, const T&)> fn) 127 forEach(std::function<void(int, const T&)> fn)
@@ -128,14 +137,27 @@ class ObjTable: public std::vector&lt;T&gt; @@ -128,14 +137,27 @@ class ObjTable: public std::vector&lt;T&gt;
128 137
129 private: 138 private:
130 std::map<size_t, T> sparse_elements; 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 inline T& 143 inline T&
133 element(size_t idx) 144 element(size_t idx)
134 { 145 {
135 - static const size_t max_size = std::vector<T>::max_size();  
136 if (idx < std::vector<T>::size()) { 146 if (idx < std::vector<T>::size()) {
137 return std::vector<T>::operator[](idx); 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 return sparse_elements[idx]; 161 return sparse_elements[idx];
140 } 162 }
141 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable"); 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,7 +170,8 @@ class ObjTable: public std::vector&lt;T&gt;
148 static const size_t max_size = std::vector<T>::max_size(); 170 static const size_t max_size = std::vector<T>::max_size();
149 if (idx < std::vector<T>::size()) { 171 if (idx < std::vector<T>::size()) {
150 return std::vector<T>::operator[](idx); 172 return std::vector<T>::operator[](idx);
151 - } else if (idx < max_size) { 173 + }
  174 + if (idx < max_size) {
152 return sparse_elements.at(idx); 175 return sparse_elements.at(idx);
153 } 176 }
154 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable"); 177 throw std::runtime_error("Impossibly large object id encountered accessing ObjTable");