From edcafb3f5dbdcdfc8e080a501f27eaa83ef11180 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Fri, 27 Mar 2020 21:41:05 +0200 Subject: [PATCH] Add a count argument to count_whitespace --- include/boost/json/detail/sse2.hpp | 84 +++++++++++++++--------- include/boost/json/impl/basic_parser.ipp | 37 +++-------- 2 files changed, 61 insertions(+), 60 deletions(-) diff --git a/include/boost/json/detail/sse2.hpp b/include/boost/json/detail/sse2.hpp index 1546441f..b95627d6 100644 --- a/include/boost/json/detail/sse2.hpp +++ b/include/boost/json/detail/sse2.hpp @@ -207,59 +207,81 @@ inline uint64_t parse_unsigned( uint64_t r, char const * p, std::size_t n ) noex #ifdef BOOST_JSON_USE_SSE2 -// assumes p..p+15 -inline std::size_t count_whitespace( char const * p ) +inline std::size_t count_whitespace( char const * p, std::size_t n ) noexcept { - // if( static_cast( p[0] ) > 0x20 ) return 0; + if( n == 0 ) + { + return 0; + } + + if( static_cast( *p ) > 0x20 ) + { + return 0; + } + + char const * p0 = p; __m128i const q1 = _mm_set1_epi8( ' ' ); __m128i const q2 = _mm_set1_epi8( '\n' ); __m128i const q3 = _mm_set1_epi8( '\r' ); __m128i const q4 = _mm_set1_epi8( '\t' ); - __m128i v = _mm_loadu_si128( (__m128i const*)p ); - - __m128i w = _mm_cmpeq_epi8( v, q1 ); - w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q2 ) ); - w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q3 ) ); - w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q4 ) ); - - int m = _mm_movemask_epi8( w ) ^ 0xFFFF; - - std::size_t n; - - if( m == 0 ) - { - n = 16; - } - else + while( n >= 16 ) { + __m128i v = _mm_loadu_si128( (__m128i const*)p ); + + __m128i w = _mm_cmpeq_epi8( v, q1 ); + w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q2 ) ); + w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q3 ) ); + w = _mm_or_si128( w, _mm_cmpeq_epi8( v, q4 ) ); + + int m = _mm_movemask_epi8( w ) ^ 0xFFFF; + + if( m != 0 ) + { #if defined(__GNUC__) || defined(__clang__) - n = __builtin_ffs( m ) - 1; + std::size_t n = __builtin_ffs( m ) - 1; #else - unsigned long index; - _BitScanForward( &index, m ); - n = index; + unsigned long index; + _BitScanForward( &index, m ); + std::size_t n = index; #endif + + p += n; + return p - p0; + } + + p += 16; + n -= 16; } - return n; + while( n > 0 ) + { + if( *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' ) + { + return p - p0; + } + + ++p; + --n; + } + + return p - p0; } #else -// assumes p..p+15 -inline std::size_t count_whitespace( char const * p ) +inline std::size_t count_whitespace( char const * p, std::size_t n ) noexcept { - std::size_t n = 0; + std::size_t i = 0; - for( ; n < 16; ++p, ++n ) + for( ; i < n; ++p, ++i ) { char const c = *p; if( c != ' ' && c != '\n' && c != '\r' && c != '\t' ) break; } - return n; + return i; } #endif @@ -269,7 +291,7 @@ inline std::size_t count_whitespace( char const * p ) #ifdef BOOST_JSON_USE_SSE2 // assumes p..p+15 -inline std::size_t count_leading( char const * p, char ch ) +inline std::size_t count_leading( char const * p, char ch ) noexcept { __m128i const q1 = _mm_set1_epi8( ch ); @@ -302,7 +324,7 @@ inline std::size_t count_leading( char const * p, char ch ) #else // assumes p..p+15 -inline std::size_t count_leading( char const * p, char ch ) +inline std::size_t count_leading( char const * p, char ch ) noexcept { std::size_t n = 0; diff --git a/include/boost/json/impl/basic_parser.ipp b/include/boost/json/impl/basic_parser.ipp index faf82e11..9dd56ca8 100644 --- a/include/boost/json/impl/basic_parser.ipp +++ b/include/boost/json/impl/basic_parser.ipp @@ -299,37 +299,16 @@ void basic_parser:: parse_white(const_stream& cs) { - while( BOOST_JSON_LIKELY(cs) ) + char const * p = cs.data(); + std::size_t n = cs.remain(); + + std::size_t n2 = detail::count_whitespace( p, n ); + cs.skip( n2 ); + + if( n2 == n ) { - char const ch = *cs; - - if( static_cast( ch ) > 0x20 ) return; - - if( ch == '\n' || ch == '\r' ) - { - ++cs; - continue; - } - - if( ch != ' ' && ch != '\t' ) - { - return; - } - - ++cs; - - while( cs.remain() >= 16 ) - { - if( static_cast( *cs ) > 0x20 ) return; - - std::size_t n = detail::count_leading( cs.data(), ch ); - cs.skip( n ); - - if( n < 16 ) break; - } + ec_ = error::incomplete; } - - ec_ = error::incomplete; } void