Commit 0d08f65cb8a106ef13f0677e46f0d01ae2743147
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<T> | @@ -128,14 +137,27 @@ class ObjTable: public std::vector<T> | ||
| 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<T> | @@ -148,7 +170,8 @@ class ObjTable: public std::vector<T> | ||
| 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"); |