LCOV - code coverage report
Current view: top level - json/detail - sse2.hpp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 97.8 % 137 134 3
Test Date: 2026-02-25 20:43:10 Functions: 100.0 % 6 6

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Peter Dimov (pdimov at gmail dot com),
       3                 : //                    Vinnie Falco (vinnie.falco@gmail.com)
       4                 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
       5                 : //
       6                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       7                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       8                 : //
       9                 : // Official repository: https://github.com/boostorg/json
      10                 : //
      11                 : 
      12                 : #ifndef BOOST_JSON_DETAIL_SSE2_HPP
      13                 : #define BOOST_JSON_DETAIL_SSE2_HPP
      14                 : 
      15                 : #include <boost/json/detail/config.hpp>
      16                 : #include <boost/json/detail/utf8.hpp>
      17                 : #include <cstddef>
      18                 : #include <cstring>
      19                 : #ifdef BOOST_JSON_USE_SSE2
      20                 : # include <emmintrin.h>
      21                 : # include <xmmintrin.h>
      22                 : # ifdef _MSC_VER
      23                 : #  include <intrin.h>
      24                 : # endif
      25                 : #endif
      26                 : 
      27                 : namespace boost {
      28                 : namespace json {
      29                 : namespace detail {
      30                 : 
      31                 : #ifdef BOOST_JSON_USE_SSE2
      32                 : 
      33                 : template<bool AllowBadUTF8>
      34                 : inline
      35                 : const char*
      36 HIT        2177 : count_valid(
      37                 :     char const* p,
      38                 :     const char* end) noexcept
      39                 : {
      40            2177 :     __m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
      41            2177 :     __m128i const q2 = _mm_set1_epi8( '\\' ); // '\\'
      42            2177 :     __m128i const q3 = _mm_set1_epi8( 0x1F );
      43                 : 
      44            2415 :     while(end - p >= 16)
      45                 :     {
      46             924 :         __m128i v1 = _mm_loadu_si128( (__m128i const*)p );
      47             924 :         __m128i v2 = _mm_cmpeq_epi8( v1, q1 ); // quote
      48             924 :         __m128i v3 = _mm_cmpeq_epi8( v1, q2 ); // backslash
      49             924 :         __m128i v4 = _mm_or_si128( v2, v3 ); // combine quotes and backslash
      50             924 :         __m128i v5 = _mm_min_epu8( v1, q3 );
      51             924 :         __m128i v6 = _mm_cmpeq_epi8( v5, v1 ); // controls
      52             924 :         __m128i v7 = _mm_or_si128( v4, v6 ); // combine with control
      53                 : 
      54             924 :         int w = _mm_movemask_epi8( v7 );
      55                 : 
      56             924 :         if( w != 0 )
      57                 :         {
      58                 :             int m;
      59                 : #if defined(__GNUC__) || defined(__clang__)
      60             686 :             m = __builtin_ffs( w ) - 1;
      61                 : #else
      62                 :             unsigned long index;
      63                 :             _BitScanForward( &index, w );
      64                 :             m = index;
      65                 : #endif
      66             686 :             return p + m;
      67                 :         }
      68                 : 
      69             238 :         p += 16;
      70                 :     }
      71                 : 
      72            3738 :     while(p != end)
      73                 :     {
      74            3689 :         const unsigned char c = *p;
      75            3689 :         if(c == '\x22' || c == '\\' || c < 0x20)
      76                 :             break;
      77            2247 :         ++p;
      78                 :     }
      79                 : 
      80            1491 :     return p;
      81                 : }
      82                 : 
      83                 : template<>
      84                 : inline
      85                 : const char*
      86          162602 : count_valid<false>(
      87                 :     char const* p,
      88                 :     const char* end) noexcept
      89                 : {
      90          162602 :     __m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
      91          162602 :     __m128i const q2 = _mm_set1_epi8( '\\' );
      92          162602 :     __m128i const q3 = _mm_set1_epi8( 0x20 );
      93                 : 
      94        12202131 :     while(end - p >= 16)
      95                 :     {
      96        12090929 :         __m128i v1 = _mm_loadu_si128( (__m128i const*)p );
      97                 : 
      98        12090929 :         __m128i v2 = _mm_cmpeq_epi8( v1, q1 );
      99        12090929 :         __m128i v3 = _mm_cmpeq_epi8( v1, q2 );
     100        12090929 :         __m128i v4 = _mm_cmplt_epi8( v1, q3 );
     101                 : 
     102        12090929 :         __m128i v5 = _mm_or_si128( v2, v3 );
     103        12090929 :         __m128i v6 = _mm_or_si128( v5, v4 );
     104                 : 
     105        12090929 :         int w = _mm_movemask_epi8( v6 );
     106                 : 
     107        12090929 :         if( w != 0 )
     108                 :         {
     109                 :             int m;
     110                 : #if defined(__GNUC__) || defined(__clang__)
     111           51400 :             m = __builtin_ffs( w ) - 1;
     112                 : #else
     113                 :             unsigned long index;
     114                 :             _BitScanForward( &index, w );
     115                 :             m = index;
     116                 : #endif
     117           51400 :             p += m;
     118           51400 :             break;
     119                 :         }
     120                 : 
     121        12039529 :         p += 16;
     122                 :     }
     123                 : 
     124          479946 :     while(p != end)
     125                 :     {
     126          449775 :         const unsigned char c = *p;
     127          449775 :         if(c == '\x22' || c == '\\' || c < 0x20)
     128                 :             break;
     129          320806 :         if(c < 0x80)
     130                 :         {
     131          307616 :             ++p;
     132          307616 :             continue;
     133                 :         }
     134                 :         // validate utf-8
     135           13190 :         uint16_t first = classify_utf8(c);
     136           13190 :         uint8_t len = first & 0xFF;
     137           13190 :         if(BOOST_JSON_UNLIKELY(end - p < len))
     138            1905 :             break;
     139           11285 :         if(BOOST_JSON_UNLIKELY(! is_valid_utf8(p, first)))
     140            1557 :             break;
     141            9728 :         p += len;
     142                 :     }
     143                 : 
     144          162602 :     return p;
     145                 : }
     146                 : 
     147                 : #else
     148                 : 
     149                 : template<bool AllowBadUTF8>
     150                 : char const*
     151                 : count_valid(
     152                 :     char const* p,
     153                 :     char const* end) noexcept
     154                 : {
     155                 :     while(p != end)
     156                 :     {
     157                 :         const unsigned char c = *p;
     158                 :         if(c == '\x22' || c == '\\' || c < 0x20)
     159                 :             break;
     160                 :         ++p;
     161                 :     }
     162                 : 
     163                 :     return p;
     164                 : }
     165                 : 
     166                 : template<>
     167                 : inline
     168                 : char const*
     169                 : count_valid<false>(
     170                 :     char const* p,
     171                 :     char const* end) noexcept
     172                 : {
     173                 :     while(p != end)
     174                 :     {
     175                 :         const unsigned char c = *p;
     176                 :         if(c == '\x22' || c == '\\' || c < 0x20)
     177                 :             break;
     178                 :         if(c < 0x80)
     179                 :         {
     180                 :             ++p;
     181                 :             continue;
     182                 :         }
     183                 :         // validate utf-8
     184                 :         uint16_t first = classify_utf8(c);
     185                 :         uint8_t len = first & 0xFF;
     186                 :         if(BOOST_JSON_UNLIKELY(end - p < len))
     187                 :             break;
     188                 :         if(BOOST_JSON_UNLIKELY(! is_valid_utf8(p, first)))
     189                 :             break;
     190                 :         p += len;
     191                 :     }
     192                 : 
     193                 :     return p;
     194                 : }
     195                 : 
     196                 : #endif
     197                 : 
     198                 : // KRYSTIAN NOTE: does not stop to validate
     199                 : // count_unescaped
     200                 : 
     201                 : #ifdef BOOST_JSON_USE_SSE2
     202                 : 
     203                 : inline
     204                 : size_t
     205           34441 : count_unescaped(
     206                 :     char const* s,
     207                 :     size_t n) noexcept
     208                 : {
     209                 : 
     210           34441 :     __m128i const q1 = _mm_set1_epi8( '\x22' ); // '"'
     211           34441 :     __m128i const q2 = _mm_set1_epi8( '\\' ); // '\\'
     212           34441 :     __m128i const q3 = _mm_set1_epi8( 0x1F );
     213                 : 
     214           34441 :     char const * s0 = s;
     215                 : 
     216         4096152 :     while( n >= 16 )
     217                 :     {
     218         4061711 :         __m128i v1 = _mm_loadu_si128( (__m128i const*)s );
     219         4061711 :         __m128i v2 = _mm_cmpeq_epi8( v1, q1 ); // quote
     220         4061711 :         __m128i v3 = _mm_cmpeq_epi8( v1, q2 ); // backslash
     221         4061711 :         __m128i v4 = _mm_or_si128( v2, v3 ); // combine quotes and backslash
     222         4061711 :         __m128i v5 = _mm_min_epu8( v1, q3 );
     223         4061711 :         __m128i v6 = _mm_cmpeq_epi8( v5, v1 ); // controls
     224         4061711 :         __m128i v7 = _mm_or_si128( v4, v6 ); // combine with control
     225                 : 
     226         4061711 :         int w = _mm_movemask_epi8( v7 );
     227                 : 
     228         4061711 :         if( w != 0 )
     229                 :         {
     230                 :             int m;
     231                 : #if defined(__GNUC__) || defined(__clang__)
     232 MIS           0 :             m = __builtin_ffs( w ) - 1;
     233                 : #else
     234                 :             unsigned long index;
     235                 :             _BitScanForward( &index, w );
     236                 :             m = index;
     237                 : #endif
     238                 : 
     239               0 :             s += m;
     240               0 :             break;
     241                 :         }
     242                 : 
     243 HIT     4061711 :         s += 16;
     244         4061711 :         n -= 16;
     245                 :     }
     246                 : 
     247           34441 :     return s - s0;
     248                 : }
     249                 : 
     250                 : #else
     251                 : 
     252                 : inline
     253                 : std::size_t
     254                 : count_unescaped(
     255                 :     char const*,
     256                 :     std::size_t) noexcept
     257                 : {
     258                 :     return 0;
     259                 : }
     260                 : 
     261                 : #endif
     262                 : 
     263                 : // count_digits
     264                 : 
     265                 : #ifdef BOOST_JSON_USE_SSE2
     266                 : 
     267                 : // assumes p..p+15 are valid
     268         2024516 : inline int count_digits( char const* p ) noexcept
     269                 : {
     270         2024516 :     __m128i v1 = _mm_loadu_si128( (__m128i const*)p );
     271         4049032 :     v1 = _mm_add_epi8(v1, _mm_set1_epi8(70));
     272         4049032 :     v1 = _mm_cmplt_epi8(v1, _mm_set1_epi8(118));
     273                 : 
     274         2024516 :     int m = _mm_movemask_epi8(v1);
     275                 : 
     276                 :     int n;
     277                 : 
     278         2024516 :     if( m == 0 )
     279                 :     {
     280         2012400 :         n = 16;
     281                 :     }
     282                 :     else
     283                 :     {
     284                 : #if defined(__GNUC__) || defined(__clang__)
     285           12116 :         n = __builtin_ffs( m ) - 1;
     286                 : #else
     287                 :         unsigned long index;
     288                 :         _BitScanForward( &index, m );
     289                 :         n = static_cast<int>(index);
     290                 : #endif
     291                 :     }
     292                 : 
     293         2024516 :     return n;
     294                 : }
     295                 : 
     296                 : #else
     297                 : 
     298                 : // assumes p..p+15 are valid
     299                 : inline int count_digits( char const* p ) noexcept
     300                 : {
     301                 :     int n = 0;
     302                 : 
     303                 :     for( ; n < 16; ++n )
     304                 :     {
     305                 :         unsigned char const d = *p++ - '0';
     306                 :         if(d > 9) break;
     307                 :     }
     308                 : 
     309                 :     return n;
     310                 : }
     311                 : 
     312                 : #endif
     313                 : 
     314                 : // parse_unsigned
     315                 : 
     316         2019313 : inline uint64_t parse_unsigned( uint64_t r, char const * p, std::size_t n ) noexcept
     317                 : {
     318        10064473 :     while( n >= 4 )
     319                 :     {
     320                 :         // faster on on clang for x86,
     321                 :         // slower on gcc
     322                 : #ifdef __clang__
     323                 :         r = r * 10 + p[0] - '0';
     324                 :         r = r * 10 + p[1] - '0';
     325                 :         r = r * 10 + p[2] - '0';
     326                 :         r = r * 10 + p[3] - '0';
     327                 : #else
     328                 :         uint32_t v;
     329         8045160 :         std::memcpy( &v, p, 4 );
     330         8045160 :         endian::native_to_little_inplace(v);
     331                 : 
     332         8045160 :         v -= 0x30303030;
     333                 : 
     334         8045160 :         unsigned w0 = v & 0xFF;
     335         8045160 :         unsigned w1 = (v >> 8) & 0xFF;
     336         8045160 :         unsigned w2 = (v >> 16) & 0xFF;
     337         8045160 :         unsigned w3 = (v >> 24);
     338                 : 
     339         8045160 :         r = (((r * 10 + w0) * 10 + w1) * 10 + w2) * 10 + w3;
     340                 : #endif
     341         8045160 :         p += 4;
     342         8045160 :         n -= 4;
     343                 :     }
     344                 : 
     345         2019313 :     switch( n )
     346                 :     {
     347         2010658 :     case 0:
     348         2010658 :         break;
     349            5484 :     case 1:
     350            5484 :         r = r * 10 + p[0] - '0';
     351            5484 :         break;
     352            1714 :     case 2:
     353            1714 :         r = r * 10 + p[0] - '0';
     354            1714 :         r = r * 10 + p[1] - '0';
     355            1714 :         break;
     356            1457 :     case 3:
     357            1457 :         r = r * 10 + p[0] - '0';
     358            1457 :         r = r * 10 + p[1] - '0';
     359            1457 :         r = r * 10 + p[2] - '0';
     360            1457 :         break;
     361                 :     }
     362         2019313 :     return r;
     363                 : }
     364                 : 
     365                 : // KRYSTIAN: this function is unused
     366                 : // count_leading
     367                 : 
     368                 : /*
     369                 : #ifdef BOOST_JSON_USE_SSE2
     370                 : 
     371                 : // assumes p..p+15
     372                 : inline std::size_t count_leading( char const * p, char ch ) noexcept
     373                 : {
     374                 :     __m128i const q1 = _mm_set1_epi8( ch );
     375                 : 
     376                 :     __m128i v = _mm_loadu_si128( (__m128i const*)p );
     377                 : 
     378                 :     __m128i w = _mm_cmpeq_epi8( v, q1 );
     379                 : 
     380                 :     int m = _mm_movemask_epi8( w ) ^ 0xFFFF;
     381                 : 
     382                 :     std::size_t n;
     383                 : 
     384                 :     if( m == 0 )
     385                 :     {
     386                 :         n = 16;
     387                 :     }
     388                 :     else
     389                 :     {
     390                 : #if defined(__GNUC__) || defined(__clang__)
     391                 :         n = __builtin_ffs( m ) - 1;
     392                 : #else
     393                 :         unsigned long index;
     394                 :         _BitScanForward( &index, m );
     395                 :         n = index;
     396                 : #endif
     397                 :     }
     398                 : 
     399                 :     return n;
     400                 : }
     401                 : 
     402                 : #else
     403                 : 
     404                 : // assumes p..p+15
     405                 : inline std::size_t count_leading( char const * p, char ch ) noexcept
     406                 : {
     407                 :     std::size_t n = 0;
     408                 : 
     409                 :     for( ; n < 16 && *p == ch; ++p, ++n );
     410                 : 
     411                 :     return n;
     412                 : }
     413                 : 
     414                 : #endif
     415                 : */
     416                 : 
     417                 : // count_whitespace
     418                 : 
     419                 : #ifdef BOOST_JSON_USE_SSE2
     420                 : 
     421         4701007 : inline const char* count_whitespace( char const* p, const char* end ) noexcept
     422                 : {
     423         4701007 :     if( p == end )
     424                 :     {
     425         2133783 :         return p;
     426                 :     }
     427                 : 
     428         2567224 :     if( static_cast<unsigned char>( *p ) > 0x20 )
     429                 :     {
     430         2484431 :         return p;
     431                 :     }
     432                 : 
     433           82793 :     __m128i const q1 = _mm_set1_epi8( ' ' );
     434           82793 :     __m128i const q2 = _mm_set1_epi8( '\n' );
     435           82793 :     __m128i const q3 = _mm_set1_epi8( 4 ); // '\t' | 4 == '\r'
     436           82793 :     __m128i const q4 = _mm_set1_epi8( '\r' );
     437                 : 
     438          183300 :     while( end - p >= 16 )
     439                 :     {
     440          105374 :         __m128i v0 = _mm_loadu_si128( (__m128i const*)p );
     441                 : 
     442          316122 :         __m128i w0 = _mm_or_si128(
     443                 :             _mm_cmpeq_epi8( v0, q1 ),
     444                 :             _mm_cmpeq_epi8( v0, q2 ));
     445          105374 :         __m128i v1 = _mm_or_si128( v0, q3 );
     446          105374 :         __m128i w1 = _mm_cmpeq_epi8( v1, q4 );
     447          105374 :         __m128i w2 = _mm_or_si128( w0, w1 );
     448                 : 
     449          105374 :         int m = _mm_movemask_epi8( w2 ) ^ 0xFFFF;
     450                 : 
     451          105374 :         if( m != 0 )
     452                 :         {
     453                 : #if defined(__GNUC__) || defined(__clang__)
     454            4867 :             std::size_t c = __builtin_ffs( m ) - 1;
     455                 : #else
     456                 :             unsigned long index;
     457                 :             _BitScanForward( &index, m );
     458                 :             std::size_t c = index;
     459                 : #endif
     460                 : 
     461            4867 :             p += c;
     462            4867 :             return p;
     463                 :         }
     464                 : 
     465          100507 :         p += 16;
     466                 :     }
     467                 : 
     468          462520 :     while( p != end )
     469                 :     {
     470          401661 :         if( *p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' )
     471                 :         {
     472           17067 :             return p;
     473                 :         }
     474                 : 
     475          384594 :         ++p;
     476                 :     }
     477                 : 
     478           60859 :     return p;
     479                 : }
     480                 : 
     481                 : /*
     482                 : 
     483                 : // slightly faster on msvc-14.2, slightly slower on clang-win
     484                 : 
     485                 : inline std::size_t count_whitespace( char const * p, std::size_t n ) noexcept
     486                 : {
     487                 :     char const * p0 = p;
     488                 : 
     489                 :     while( n > 0 )
     490                 :     {
     491                 :         char ch = *p;
     492                 : 
     493                 :         if( ch == '\n' || ch == '\r' )
     494                 :         {
     495                 :             ++p;
     496                 :             --n;
     497                 :             continue;
     498                 :         }
     499                 : 
     500                 :         if( ch != ' ' && ch != '\t' )
     501                 :         {
     502                 :             break;
     503                 :         }
     504                 : 
     505                 :         ++p;
     506                 :         --n;
     507                 : 
     508                 :         while( n >= 16 )
     509                 :         {
     510                 :             std::size_t n2 = count_leading( p, ch );
     511                 : 
     512                 :             p += n2;
     513                 :             n -= n2;
     514                 : 
     515                 :             if( n2 < 16 )
     516                 :             {
     517                 :                 break;
     518                 :             }
     519                 :         }
     520                 :     }
     521                 : 
     522                 :     return p - p0;
     523                 : }
     524                 : */
     525                 : 
     526                 : #else
     527                 : 
     528                 : inline const char* count_whitespace( char const* p, const char* end ) noexcept
     529                 : {
     530                 : 
     531                 :     for(; p != end; ++p)
     532                 :     {
     533                 :         char const c = *p;
     534                 :         if( c != ' ' && c != '\n' && c != '\r' && c != '\t' ) break;
     535                 :     }
     536                 : 
     537                 :     return p;
     538                 : }
     539                 : 
     540                 : #endif
     541                 : 
     542                 : } // detail
     543                 : } // namespace json
     544                 : } // namespace boost
     545                 : 
     546                 : #endif
        

Generated by: LCOV version 2.3