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 | 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<T> |
| 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<T> |
| 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"); | ... | ... |