|
31 | 31 |
|
32 | 32 | #include "pcre2pp.hh" |
33 | 33 |
|
| 34 | +#include <algorithm> |
| 35 | + |
34 | 36 | #include "config.h" |
35 | 37 | #include "ww898/cp_utf8.hpp" |
36 | 38 |
|
@@ -136,28 +138,55 @@ code::find_in(string_fragment in, uint32_t options) const |
136 | 138 | size_t |
137 | 139 | code::match_partial(string_fragment in) const |
138 | 140 | { |
| 141 | + // This function is used for error reporting to show where a line |
| 142 | + // diverges from the expected pattern. Cap the input length to |
| 143 | + // avoid excessive work on very large (e.g. multi-MB binary) lines. |
| 144 | + static constexpr size_t MAX_PARTIAL_LEN = 8192; |
| 145 | + |
139 | 146 | auto md = this->create_match_data(); |
140 | | - auto length = in.length(); |
| 147 | + auto length = std::min((size_t) in.length(), MAX_PARTIAL_LEN); |
| 148 | + |
| 149 | + // Try the full (capped) length first -- if it partially matches, |
| 150 | + // we're done. |
| 151 | + auto rc = pcre2_match(this->p_code.in(), |
| 152 | + in.udata(), |
| 153 | + length, |
| 154 | + 0, |
| 155 | + PCRE2_PARTIAL_HARD, |
| 156 | + md.md_data.in(), |
| 157 | + nullptr); |
141 | 158 |
|
142 | | - do { |
143 | | - auto rc = pcre2_match(this->p_code.in(), |
144 | | - in.udata(), |
145 | | - length, |
146 | | - 0, |
147 | | - PCRE2_PARTIAL_HARD, |
148 | | - md.md_data.in(), |
149 | | - nullptr); |
| 159 | + if (rc == PCRE2_ERROR_PARTIAL) { |
| 160 | + return md.md_ovector[1]; |
| 161 | + } |
150 | 162 |
|
151 | | - if (rc == PCRE2_ERROR_PARTIAL) { |
152 | | - return md.md_ovector[1]; |
153 | | - } |
| 163 | + // Binary search for the largest length that yields a partial match. |
| 164 | + // For anchored patterns (the primary use case), partial-match is |
| 165 | + // monotonic over length. |
| 166 | + size_t lo = 1; |
| 167 | + size_t hi = length; |
| 168 | + size_t best = 0; |
154 | 169 |
|
155 | | - if (length > 0) { |
156 | | - length -= 1; |
| 170 | + while (lo <= hi) { |
| 171 | + auto mid = lo + (hi - lo) / 2; |
| 172 | + |
| 173 | + rc = pcre2_match(this->p_code.in(), |
| 174 | + in.udata(), |
| 175 | + mid, |
| 176 | + 0, |
| 177 | + PCRE2_PARTIAL_HARD, |
| 178 | + md.md_data.in(), |
| 179 | + nullptr); |
| 180 | + |
| 181 | + if (rc == PCRE2_ERROR_PARTIAL) { |
| 182 | + best = md.md_ovector[1]; |
| 183 | + lo = mid + 1; |
| 184 | + } else { |
| 185 | + hi = mid - 1; |
157 | 186 | } |
158 | | - } while (length > 0); |
| 187 | + } |
159 | 188 |
|
160 | | - return 0; |
| 189 | + return best; |
161 | 190 | } |
162 | 191 |
|
163 | 192 | const char* |
|
0 commit comments