|
29 | 29 |
|
30 | 30 | #include <fcntl.h> |
31 | 31 | #include <string> |
| 32 | +#include <string_view> |
32 | 33 | #include <thread> |
33 | 34 | #include <sys/stat.h> |
34 | 35 |
|
@@ -195,19 +196,16 @@ void goto_next_line(char* mapped_file, size_t& pos, size_t& current_line, const |
195 | 196 | } |
196 | 197 |
|
197 | 198 | MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE |
198 | | -void goto_next_line_unrolled(char* mapped_file, size_t& pos, size_t& current_line, const size_t length) { |
199 | | - for ( ; pos + LOOP_UNROLLING_VALUE <= length; pos += LOOP_UNROLLING_VALUE ) { |
200 | | - uint32_t flags = 0; |
201 | | - for (size_t i = 0; i < LOOP_UNROLLING_VALUE; ++i) { |
202 | | - flags |= static_cast<uint32_t>(mapped_file[pos + i] == '\n') << i; |
203 | | - } |
204 | | - if (flags == 0) continue; |
| 199 | +void goto_next_line_unchecked(char* mapped_file, size_t& pos, size_t& current_line, const size_t length) { |
| 200 | + std::string_view sv(mapped_file + pos, length - pos); |
| 201 | + size_t offset = sv.find('\n'); // compiles to memchr |
205 | 202 |
|
206 | | - int offset = utils::lowest_set_bit_32(flags); |
| 203 | + if (offset != std::string_view::npos) { |
207 | 204 | ASSERT(is_line_ending(mapped_file, pos + offset)); |
208 | 205 | pos += (offset + 1); |
209 | 206 | ++current_line; |
210 | | - break; |
| 207 | + } else { |
| 208 | + pos = length; |
211 | 209 | } |
212 | 210 | } |
213 | 211 |
|
@@ -253,38 +251,26 @@ vec<LineRange> split_lines(char* mapped_file, |
253 | 251 | vec<std::pair<size_t, size_t>> line_positions; |
254 | 252 | line_positions.reserve(expected_num_lines + 1); |
255 | 253 |
|
256 | | - // speed up bulk of processing via loop unrolling |
257 | | - while ( line_positions.size() + 1 < expected_num_lines && |
258 | | - pos + LOOP_UNROLLING_VALUE <= length ) { |
| 254 | + // find line endings very fast |
| 255 | + line_positions.emplace_back(pos, current_line); |
| 256 | + while ( line_positions.size() < expected_num_lines + 1 && pos < length ) { |
259 | 257 | // skip comments |
260 | 258 | while ( mapped_file[pos] == '%' && pos < length ) { |
261 | | - goto_next_line(mapped_file, pos, current_line, length); |
| 259 | + goto_next_line_unchecked(mapped_file, pos, current_line, length); |
262 | 260 | } |
263 | 261 |
|
| 262 | + goto_next_line_unchecked(mapped_file, pos, current_line, length); |
264 | 263 | line_positions.emplace_back(pos, current_line); |
265 | | - goto_next_line_unrolled(mapped_file, pos, current_line, length); |
266 | 264 | } |
267 | | - |
268 | | - // handle remainder without unrolling |
269 | | - if ( mapped_file[pos - 1] != '\n' || (!line_positions.empty() && pos == line_positions.back().first) ) { |
270 | | - // if the unrolled loop stopped at a weird position, fix it |
271 | | - size_t dummy_line = current_line; |
272 | | - goto_next_line(mapped_file, pos, dummy_line, length); |
| 265 | + if ( line_positions.size() < expected_num_lines + 1 && mapped_file[pos - 1] == '\n' ) { |
| 266 | + // special case for last line that is not terminated by a newline (might be end of file or empty line) |
| 267 | + line_positions.emplace_back(pos, current_line); |
273 | 268 | } |
274 | | - while ( line_positions.size() < expected_num_lines ) { |
275 | | - // skip comments |
276 | | - while ( mapped_file[pos] == '%' && pos < length ) { |
277 | | - goto_next_line(mapped_file, pos, current_line, length); |
278 | | - } |
279 | 269 |
|
280 | | - if ( mapped_file[pos - 1] != '\n' || (!line_positions.empty() && pos == line_positions.back().first) ) { |
281 | | - parsing_exception("expected " + STR(expected_num_lines + 1) + " lines, but there are only " + |
282 | | - STR(line_positions.size()) + " lines (excluding comments)"); |
283 | | - } |
284 | | - line_positions.emplace_back(pos, current_line); |
285 | | - goto_next_line(mapped_file, pos, current_line, length); |
| 270 | + if ( line_positions.size() < expected_num_lines + 1 ) { // note: +1 for header line |
| 271 | + parsing_exception("expected " + STR(expected_num_lines + 1) + " lines, but there are only " + |
| 272 | + STR(line_positions.size()) + " lines (excluding comments)"); |
286 | 273 | } |
287 | | - line_positions.emplace_back(pos, current_line); |
288 | 274 |
|
289 | 275 | // split the lines into ranges that can be processed in parallel |
290 | 276 | const size_t num_ranges = num_parallel_ranges(); |
|
0 commit comments