@@ -196,9 +196,9 @@ void goto_next_line(char* mapped_file, size_t& pos, size_t& current_line, const
196196}
197197
198198MT_KAHYPAR_ATTRIBUTE_ALWAYS_INLINE
199- void goto_next_line_unrolled (char * mapped_file, size_t & pos, size_t & current_line, const size_t length) {
199+ void goto_next_line_unchecked (char * mapped_file, size_t & pos, size_t & current_line, const size_t length) {
200200 std::string_view sv (mapped_file + pos, length - pos);
201- size_t offset = sv.find (' \n ' );
201+ size_t offset = sv.find (' \n ' ); // compiles to memchr
202202
203203 if (offset != std::string_view::npos) {
204204 ASSERT (is_line_ending (mapped_file, pos + offset));
@@ -251,38 +251,26 @@ vec<LineRange> split_lines(char* mapped_file,
251251 vec<std::pair<size_t , size_t >> line_positions;
252252 line_positions.reserve (expected_num_lines + 1 );
253253
254- // speed up bulk of processing via loop unrolling
255- while ( line_positions.size () + 1 < expected_num_lines &&
256- 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 ) {
257257 // skip comments
258258 while ( mapped_file[pos] == ' %' && pos < length ) {
259- goto_next_line (mapped_file, pos, current_line, length);
259+ goto_next_line_unchecked (mapped_file, pos, current_line, length);
260260 }
261261
262+ goto_next_line_unchecked (mapped_file, pos, current_line, length);
262263 line_positions.emplace_back (pos, current_line);
263- goto_next_line_unrolled (mapped_file, pos, current_line, length);
264264 }
265-
266- // handle remainder without unrolling
267- if ( mapped_file[pos - 1 ] != ' \n ' || (!line_positions.empty () && pos == line_positions.back ().first ) ) {
268- // if the unrolled loop stopped at a weird position, fix it
269- size_t dummy_line = current_line;
270- 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);
271268 }
272- while ( line_positions.size () < expected_num_lines ) {
273- // skip comments
274- while ( mapped_file[pos] == ' %' && pos < length ) {
275- goto_next_line (mapped_file, pos, current_line, length);
276- }
277269
278- if ( mapped_file[pos - 1 ] != ' \n ' || (!line_positions.empty () && pos == line_positions.back ().first ) ) {
279- parsing_exception (" expected " + STR (expected_num_lines + 1 ) + " lines, but there are only " +
280- STR (line_positions.size ()) + " lines (excluding comments)" );
281- }
282- line_positions.emplace_back (pos, current_line);
283- 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)" );
284273 }
285- line_positions.emplace_back (pos, current_line);
286274
287275 // split the lines into ranges that can be processed in parallel
288276 const size_t num_ranges = num_parallel_ranges ();
0 commit comments