38 #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
53 if(
this == &other ) {
57 input_reader_ = std::move( other.input_reader_ );
58 source_name_ = std::move( other.source_name_ );
66 buffer_ = other.buffer_;
67 data_pos_ = other.data_pos_;
68 data_end_ = other.data_end_;
69 current_ = other.current_;
71 column_ = other.column_;
74 other.buffer_ =
nullptr;
77 other.current_ =
'\0';
91 if( data_pos_ >= data_end_ ) {
105 size_t const start = data_pos_;
110 auto const stop = std::min( data_end_, start +
BlockLength );
117 data_pos_ + 7 < stop &&
118 buffer_[ data_pos_ + 0 ] !=
'\n' &&
119 buffer_[ data_pos_ + 0 ] !=
'\r' &&
120 buffer_[ data_pos_ + 1 ] !=
'\n' &&
121 buffer_[ data_pos_ + 1 ] !=
'\r' &&
122 buffer_[ data_pos_ + 2 ] !=
'\n' &&
123 buffer_[ data_pos_ + 2 ] !=
'\r' &&
124 buffer_[ data_pos_ + 3 ] !=
'\n' &&
125 buffer_[ data_pos_ + 3 ] !=
'\r' &&
126 buffer_[ data_pos_ + 4 ] !=
'\n' &&
127 buffer_[ data_pos_ + 4 ] !=
'\r' &&
128 buffer_[ data_pos_ + 5 ] !=
'\n' &&
129 buffer_[ data_pos_ + 5 ] !=
'\r' &&
130 buffer_[ data_pos_ + 6 ] !=
'\n' &&
131 buffer_[ data_pos_ + 6 ] !=
'\r' &&
132 buffer_[ data_pos_ + 7 ] !=
'\n' &&
133 buffer_[ data_pos_ + 7 ] !=
'\r'
198 buffer_[ data_pos_ ] !=
'\n' &&
199 buffer_[ data_pos_ ] !=
'\r'
205 target.append( buffer_ + start, data_pos_ - start );
208 assert( data_pos_ >= start );
218 assert( data_pos_ <= data_end_ );
222 if( data_pos_ == data_end_ ) {
229 }
else if( buffer_[ data_pos_ ] ==
'\n' ) {
232 }
else if( buffer_[ data_pos_ ] ==
'\r' ) {
237 if( data_pos_ < data_end_ && buffer_[ data_pos_ ] ==
'\n' ) {
258 #if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
260 size_t InputStream::parse_unsigned_integer_gcc_intrinsic_()
273 std::uint64_t chunk = 0;
274 std::memcpy( &chunk, &buffer_[ data_pos_ ],
sizeof( chunk ));
280 auto const zero =
static_cast<uint64_t
>(0);
281 #define hasless(x,n) (((x)-~zero/255*(n))&~(x)&~zero/255*128)
282 #define hasmore(x,n) ((((x)+~zero/255*(127-(n)))|(x))&~zero/255*128)
285 auto const l = hasless( chunk,
'0' );
286 auto const m = hasmore( chunk,
'9' );
287 auto const p = l | m;
309 if(
sizeof(
int) ==
sizeof(std::uint64_t) ) {
310 idx = __builtin_ffs(p) / 8;
311 }
else if(
sizeof(
long) ==
sizeof(std::uint64_t) ) {
312 idx = __builtin_ffsl(p) / 8;
313 }
else if(
sizeof(
long long) ==
sizeof(std::uint64_t) ) {
314 idx = __builtin_ffsll(p) / 8;
317 (
sizeof(
int) ==
sizeof(std::uint64_t) ) ||
318 (
sizeof(
long) ==
sizeof(std::uint64_t) ) ||
319 (
sizeof(
long long) ==
sizeof(std::uint64_t) ),
320 "No compilter intrinsic __builtin_ffs[l][l] for std::uint64_t"
322 throw std::runtime_error(
323 "No compilter intrinsic __builtin_ffs[l][l] for std::uint64_t"
326 assert( 0 <= idx && idx <= 8 );
335 chunk <<= (8 * ( 8 - idx + 1 ));
342 std::uint64_t lower_digits = (chunk & 0x0f000f000f000f00) >> 8;
343 std::uint64_t upper_digits = (chunk & 0x000f000f000f000f) * 10;
344 chunk = lower_digits + upper_digits;
347 lower_digits = (chunk & 0x00ff000000ff0000) >> 16;
348 upper_digits = (chunk & 0x000000ff000000ff) * 100;
349 chunk = lower_digits + upper_digits;
352 lower_digits = (chunk & 0x0000ffff00000000) >> 32;
353 upper_digits = (chunk & 0x000000000000ffff) * 10000;
354 chunk = lower_digits + upper_digits;
368 if( idx == 0 || data_pos_ + 8 >= data_end_ ) {
369 return parse_unsigned_integer_naive_();
372 throw std::runtime_error(
373 "Expecting integer in " +
source_name() +
" at " +
at() +
"."
378 data_pos_ += idx - 1;
391 size_t InputStream::parse_unsigned_integer_from_chars_()
400 using namespace utils;
404 auto raise_and_add_ = [base]( T& val,
unsigned char c ) {
406 __builtin_mul_overflow( val, base, &val ) ||
407 __builtin_add_overflow( val, c, &val )
411 auto from_chars_digit_ = [&](
char const*& first,
char const* last, T& val ) {
412 while( first != last ) {
413 char const c = *first;
415 if( !raise_and_add_(val, c -
'0') ) {
426 char const* start = &buffer_[ data_pos_ ];
427 char const* end = &buffer_[ data_end_ ];
428 auto const valid = from_chars_digit_( start, end, x );
429 auto const dist = start - &buffer_[ data_pos_ ];
432 throw std::runtime_error(
433 "Expecting integer in " +
source_name() +
" at " +
at() +
"."
435 }
else if( !valid ) {
436 throw std::overflow_error(
437 "Numerical overflow in " +
source_name() +
" at " +
at() +
"."
439 }
else if( std::is_signed<T>::value ) {
463 #endif // defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
465 #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
467 size_t InputStream::parse_unsigned_integer_std_from_chars_()
474 using namespace utils;
481 auto const conv = std::from_chars( &buffer_[ data_pos_ ], &buffer_[ data_end_ ], x );
484 auto const dist = conv.ptr - &buffer_[ data_pos_ ];
490 throw std::runtime_error(
491 "Expecting integer in " +
source_name() +
" at " +
at() +
"."
495 if( conv.ec != std::errc() ) {
496 if( conv.ec == std::errc::result_out_of_range ) {
497 throw std::overflow_error(
498 "Numerical overflow in " +
source_name() +
" at " +
at() +
"."
500 }
else if( conv.ec == std::errc::invalid_argument ) {
509 throw std::overflow_error(
510 "Integer parsing error in " +
source_name() +
" at " +
at() +
"."
530 #endif // ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
532 size_t InputStream::parse_unsigned_integer_naive_()
536 using namespace utils;
539 if( data_pos_ >= data_end_ || !
is_digit( current_ ) ) {
540 throw std::runtime_error(
541 "Expecting integer in " +
source_name() +
" at " +
at() +
"."
545 while(( data_pos_ < data_end_ ) &&
is_digit( current_ )) {
546 T y = current_ -
'0';
548 if( x > ( std::numeric_limits<T>::max() - y ) / 10 ) {
549 throw std::overflow_error(
550 "Numerical overflow in " +
source_name() +
" at " +
at() +
"."
565 assert( data_pos_ < data_end_ );
566 assert( current_ !=
'\n' );
569 current_ = buffer_[ data_pos_ ];
584 size_t InputStream::parse_unsigned_integer_size_t_()
587 #if defined(__GNUC__) || defined(__GNUG__) || defined(__clang__)
590 return parse_unsigned_integer_gcc_intrinsic_();
601 return parse_unsigned_integer_naive_();
610 void InputStream::init_( std::shared_ptr<BaseInputSource> input_source )
613 if( input_source ==
nullptr ) {
614 source_name_ =
"invalid source";
634 source_name_ = input_source->source_name();
638 data_end_ = input_source->read( buffer_, 2 *
BlockLength );
641 if( data_end_ >= 3 &&
642 buffer_[0] ==
'\xEF' &&
643 buffer_[1] ==
'\xBB' &&
650 if( data_pos_ == data_end_ ) {
664 input_reader_ = utils::make_unique<InputReader>();
666 input_reader_->init( input_source );
676 void InputStream::update_blocks_()
686 assert( data_pos_ < data_end_ );
698 if( input_reader_ && input_reader_->valid() ) {
699 data_end_ += input_reader_->finish_reading();