39 #if defined(GENESIS_AVX) || defined(GENESIS_AVX2) || defined(GENESIS_AVX512)
41 #include <immintrin.h>
54 if(
this == &other ) {
58 input_reader_ = std::move( other.input_reader_ );
59 source_name_ = std::move( other.source_name_ );
67 buffer_ = other.buffer_;
68 data_pos_ = other.data_pos_;
69 data_end_ = other.data_end_;
70 current_ = other.current_;
72 column_ = other.column_;
75 other.buffer_ =
nullptr;
78 other.current_ =
'\0';
93 throw std::runtime_error(
95 "Expecting " +
char_to_hex( criterion ) +
" at " +
at() +
", " +
96 "but received " +
char_to_hex( current_ ) +
" instead."
99 assert(
good() && current_ == criterion );
108 throw std::runtime_error(
110 "Unexpected char " +
char_to_hex( current_ ) +
" at " +
at() +
"."
114 auto const chr = current_;
130 if( data_pos_ >= data_end_ ) {
141 auto const move_dist = update_and_move_to_line_or_buffer_end_();
143 data_pos_ == data_end_ ||
145 buffer_[ data_pos_ ] ==
'\n' ||
146 buffer_[ data_pos_ ] ==
'\r'
149 assert( move_dist <= data_pos_ );
152 target.append( buffer_ + data_pos_ - move_dist, move_dist );
166 assert( data_pos_ == data_end_ || buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
167 increment_to_next_line_();
168 assert( data_pos_ == data_end_ || column_ == 1 );
171 #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
177 std::string_view InputStream::get_line_view()
180 if( data_pos_ >= data_end_ ) {
181 return std::string_view();
186 auto const move_dist = update_and_move_to_line_or_buffer_end_();
188 data_pos_ == data_end_ ||
190 buffer_[ data_pos_ ] ==
'\n' ||
191 buffer_[ data_pos_ ] ==
'\r'
194 assert( move_dist <= data_pos_ );
198 throw std::runtime_error(
199 "Cannot call InputStream::get_line_view() on lines that are longer "
206 auto result = std::string_view( buffer_ + data_pos_ - move_dist, move_dist );
212 assert( data_pos_ == data_end_ || buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
213 increment_to_next_line_();
214 assert( data_pos_ == data_end_ || column_ == 1 );
224 void InputStream::fill_line_views_( std::string_view* str_views,
size_t n_lines )
227 if( data_pos_ >= data_end_ ) {
240 size_t const total_start_pos = data_pos_;
244 auto const stop_pos = std::min( data_end_, total_start_pos +
BlockLength );
247 for(
size_t i = 0; i < n_lines; ++i ) {
249 size_t const start_pos = data_pos_;
252 if( data_pos_ >= data_end_ ) {
253 throw std::runtime_error(
254 "Reached the end of input before reading " +
std::to_string( n_lines ) +
260 move_to_line_or_buffer_end_( stop_pos );
263 assert( data_pos_ >= start_pos );
264 assert( data_pos_ == stop_pos || buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
265 assert( stop_pos == data_end_ || stop_pos == total_start_pos +
BlockLength );
274 if( data_pos_ >= total_start_pos +
BlockLength - 2 ) {
275 throw std::runtime_error(
276 "Cannot call InputStream::get_line_views() on lines that are in sum longer "
282 str_views[i] = std::string_view( buffer_ + start_pos, data_pos_ - start_pos );
288 assert( data_pos_ == data_end_ || buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
289 increment_to_next_line_();
290 assert( data_pos_ == data_end_ || column_ == 1 );
294 #endif // ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
300 size_t InputStream::update_and_move_to_line_or_buffer_end_()
304 assert( data_pos_ < data_end_ );
313 size_t const start_pos = data_pos_;
317 auto const stop_pos = std::min( data_end_, data_pos_ +
BlockLength );
320 move_to_line_or_buffer_end_( stop_pos );
324 assert( data_pos_ >= start_pos );
325 assert( data_pos_ == stop_pos || buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
326 return data_pos_ - start_pos;
333 void InputStream::move_to_line_or_buffer_end_(
size_t const stop_pos )
337 #if defined(GENESIS_AVX512)
338 approach_line_or_buffer_end_avx512_( stop_pos );
339 #elif defined(GENESIS_AVX2)
340 approach_line_or_buffer_end_avx2_( stop_pos );
342 approach_line_or_buffer_end_unrolled_( stop_pos );
348 data_pos_ < stop_pos &&
349 buffer_[ data_pos_ ] !=
'\n' &&
350 buffer_[ data_pos_ ] !=
'\r'
360 #if defined(GENESIS_AVX512)
362 void InputStream::approach_line_or_buffer_end_avx512_(
size_t const stop_pos )
366 static auto const all_nl = _mm512_set1_epi8(
'\n');
367 static auto const all_cr = _mm512_set1_epi8(
'\r');
370 while( data_pos_ + 64 <= stop_pos ) {
371 auto data_64bytes = _mm512_loadu_si512(
372 reinterpret_cast<__m512i const*
>( buffer_ + data_pos_ )
376 auto nl_pos = _mm512_cmpeq_epi8_mask(data_64bytes, all_nl);
377 auto cr_pos = _mm512_cmpeq_epi8_mask(data_64bytes, all_cr);
381 auto nr_pos = nl_pos | cr_pos;
386 int offset = _tzcnt_u64(nr_pos);
395 #else // defined(GENESIS_AVX512)
397 void InputStream::approach_line_or_buffer_end_avx512_(
size_t const stop_pos )
404 #endif // defined(GENESIS_AVX512)
410 #if defined(GENESIS_AVX2)
412 void InputStream::approach_line_or_buffer_end_avx2_(
size_t const stop_pos )
415 static auto const all_nl = _mm256_set1_epi8(
'\n' );
416 static auto const all_cr = _mm256_set1_epi8(
'\r' );
421 bool aligned =
reinterpret_cast<uintptr_t
>( buffer_ + data_pos_ ) % 32 == 0;
422 while( data_pos_ + 32 <= stop_pos ) {
431 assert(
reinterpret_cast<uintptr_t
>( buffer_ + data_pos_ ) % 32 == 0 );
432 data_chunk = _mm256_load_si256(
433 reinterpret_cast<__m256i const*
>( buffer_ + data_pos_ )
436 data_chunk = _mm256_loadu_si256(
437 reinterpret_cast<__m256i const*
>( buffer_ + data_pos_ )
443 auto const nl_pos = _mm256_cmpeq_epi8( data_chunk, all_nl );
444 auto const cr_pos = _mm256_cmpeq_epi8( data_chunk, all_cr );
445 auto const nr_pos = _mm256_or_si256( nl_pos, cr_pos );
449 mask = _mm256_movemask_epi8( nr_pos );
456 auto const remainder =
reinterpret_cast<uintptr_t
>( buffer_ + data_pos_ ) % 32;
457 data_pos_ += 32 - remainder;
466 #if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
471 auto const offset = __builtin_ctz(mask);
473 assert( data_pos_ <= stop_pos );
474 assert( buffer_[ data_pos_ ] ==
'\n' || buffer_[ data_pos_ ] ==
'\r' );
476 assert( data_pos_ + 32 > stop_pos );
483 approach_line_or_buffer_end_unrolled_( stop_pos );
485 #endif // defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
488 #else // defined(GENESIS_AVX2)
490 void InputStream::approach_line_or_buffer_end_avx2_(
size_t const stop_pos )
497 #endif // defined(GENESIS_AVX2)
503 void InputStream::approach_line_or_buffer_end_unrolled_(
size_t const stop_pos )
510 data_pos_ + 7 < stop_pos &&
511 buffer_[ data_pos_ + 0 ] !=
'\n' &&
512 buffer_[ data_pos_ + 0 ] !=
'\r' &&
513 buffer_[ data_pos_ + 1 ] !=
'\n' &&
514 buffer_[ data_pos_ + 1 ] !=
'\r' &&
515 buffer_[ data_pos_ + 2 ] !=
'\n' &&
516 buffer_[ data_pos_ + 2 ] !=
'\r' &&
517 buffer_[ data_pos_ + 3 ] !=
'\n' &&
518 buffer_[ data_pos_ + 3 ] !=
'\r' &&
519 buffer_[ data_pos_ + 4 ] !=
'\n' &&
520 buffer_[ data_pos_ + 4 ] !=
'\r' &&
521 buffer_[ data_pos_ + 5 ] !=
'\n' &&
522 buffer_[ data_pos_ + 5 ] !=
'\r' &&
523 buffer_[ data_pos_ + 6 ] !=
'\n' &&
524 buffer_[ data_pos_ + 6 ] !=
'\r' &&
525 buffer_[ data_pos_ + 7 ] !=
'\n' &&
526 buffer_[ data_pos_ + 7 ] !=
'\r'
567 void InputStream::increment_to_next_line_()
570 assert( data_pos_ <= data_end_ );
574 if( data_pos_ == data_end_ ) {
581 }
else if( buffer_[ data_pos_ ] ==
'\n' ) {
584 }
else if( buffer_[ data_pos_ ] ==
'\r' ) {
589 if( data_pos_ < data_end_ && buffer_[ data_pos_ ] ==
'\n' ) {
613 if( data_pos_ + n >= data_end_ ) {
614 if( data_pos_ + n == data_end_ ) {
617 assert( data_pos_ < data_end_ );
626 assert( data_pos_ + n > data_end_ );
627 throw std::runtime_error(
628 "Invalid InputStream jump to position after buffer end."
649 void InputStream::init_( std::shared_ptr<BaseInputSource> input_source )
652 if( input_source ==
nullptr ) {
653 source_name_ =
"invalid source";
673 source_name_ = input_source->source_name();
677 data_end_ = input_source->read( buffer_, 2 *
BlockLength );
680 if( data_end_ >= 3 &&
681 buffer_[0] ==
'\xEF' &&
682 buffer_[1] ==
'\xBB' &&
689 if( data_pos_ == data_end_ ) {
703 input_reader_ = utils::make_unique<InputReader>( input_source );
717 void InputStream::update_blocks_()
727 assert( data_pos_ < data_end_ );
739 if( input_reader_ && input_reader_->valid() ) {
740 data_end_ += input_reader_->finish_reading();
753 void InputStream::set_current_char_()
759 assert( data_pos_ == data_end_ );
761 if( data_pos_ == data_end_ && data_pos_ > 0 && buffer_[ data_pos_ - 1 ] !=
'\n' ) {
763 buffer_[ data_pos_ ] =
'\n';
775 if( buffer_[ data_pos_ ] ==
'\r' ) {
776 buffer_[ data_pos_ ] =
'\n';
781 if( data_pos_ + 1 < data_end_ && buffer_[ data_pos_ + 1 ] ==
'\n' ) {
787 current_ = buffer_[ data_pos_ ];