LCOV - code coverage report
Current view: top level - spb/json - deserialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.1 % 370 363
Test Date: 2026-03-06 17:56:28 Functions: 33.5 % 1308 438

            Line data    Source code
       1              : /***************************************************************************\
       2              : * Name        : deserialize library for json                                *
       3              : * Description : all json deserialization functions                          *
       4              : * Author      : antonin.kriz@gmail.com                                      *
       5              : * ------------------------------------------------------------------------- *
       6              : * This is free software; you can redistribute it and/or modify it under the *
       7              : * terms of the MIT license. A copy of the license can be found in the file  *
       8              : * "LICENSE" at the root of this distribution.                               *
       9              : \***************************************************************************/
      10              : 
      11              : #pragma once
      12              : 
      13              : #include "../bits.h"
      14              : #include "../concepts.h"
      15              : #include "../to_from_chars.h"
      16              : #include "../utf8.h"
      17              : #include "base64.h"
      18              : #include <algorithm>
      19              : #include <cctype>
      20              : #include <cstddef>
      21              : #include <cstdint>
      22              : #include <cstring>
      23              : #include <map>
      24              : #include <memory>
      25              : #include <spb/io/buffer-io.hpp>
      26              : #include <spb/io/io.hpp>
      27              : #include <stdexcept>
      28              : #include <string>
      29              : #include <string_view>
      30              : #include <type_traits>
      31              : #include <variant>
      32              : 
      33              : namespace spb::json::detail
      34              : {
      35              : using namespace std::literals;
      36              : 
      37              : static const auto escape = '\\';
      38              : 
      39              : /**
      40              :  * @brief helper for std::variant visit
      41              :  *        https://en.cppreference.com/w/cpp/utility/variant/visit
      42              :  *
      43              :  */
      44              : template < class... Ts >
      45              : struct overloaded : Ts...
      46              : {
      47              :     using Ts::operator( )...;
      48              : };
      49              : // explicit deduction guide (not needed as of C++20)
      50              : template < class... Ts >
      51              : overloaded( Ts... ) -> overloaded< Ts... >;
      52              : 
      53              : /**
      54              :  * @brief djb2_hash for strings
      55              :  *        http://www.cse.yorku.ca/~oz/hash.html
      56              :  *
      57              :  * @param str
      58              :  * @return uint32_t
      59              :  */
      60         2923 : static constexpr inline auto djb2_hash( std::string_view str ) noexcept -> uint32_t
      61              : {
      62         2923 :     uint32_t hash = 5381U;
      63              : 
      64        30963 :     for( auto c : str )
      65              :     {
      66        28040 :         hash = ( ( hash << 5U ) + hash ) + uint8_t( c ); /* hash * 33 + c */
      67              :     }
      68              : 
      69         2923 :     return hash;
      70              : }
      71              : 
      72              : static constexpr inline auto fnv1a_hash( std::string_view str ) noexcept -> uint64_t
      73              : {
      74              :     uint64_t hash        = 14695981039346656037ULL;
      75              :     const uint64_t prime = 1099511628211ULL;
      76              : 
      77              :     for( auto c : str )
      78              :     {
      79              :         hash *= prime;
      80              :         hash ^= c;
      81              :     }
      82              : 
      83              :     return hash;
      84              : }
      85              : 
      86              : template < spb::detail::proto_field_bytes T >
      87            2 : void clear( T & container )
      88              : {
      89              :     if constexpr( spb::detail::proto_field_bytes_resizable< T > )
      90              :     {
      91            2 :         container.clear( );
      92              :     }
      93              :     else
      94              :     {
      95            0 :         std::fill( container.begin( ), container.end( ), typename T::value_type( ) );
      96              :     }
      97            2 : }
      98              : 
      99              : struct istream
     100              : {
     101              : private:
     102              :     spb::io::buffered_reader reader;
     103              : 
     104              :     //- current char
     105              :     int m_current = -1;
     106              : 
     107              :     std::string_view m_current_key;
     108              : 
     109              :     /**
     110              :      * @brief gets the next char from the stream
     111              :      *
     112              :      * @param skip_white_space if true, skip white spaces
     113              :      */
     114        11562 :     void update_current( bool skip_white_space )
     115              :     {
     116              :         for( ;; )
     117              :         {
     118        11563 :             auto view = reader.view( 1 );
     119        11563 :             if( view.empty( ) )
     120              :             {
     121          811 :                 m_current = 0;
     122        11562 :                 return;
     123              :             }
     124        10752 :             m_current = view[ 0 ];
     125        10752 :             if( !skip_white_space )
     126              :             {
     127         3273 :                 return;
     128              :             }
     129         7479 :             size_t spaces = 0;
     130         7915 :             for( auto c : view )
     131              :             {
     132         7914 :                 if( !isspace( c ) )
     133              :                 {
     134         7478 :                     m_current = c;
     135         7478 :                     reader.skip( spaces );
     136         7478 :                     return;
     137              :                 }
     138          436 :                 spaces += 1;
     139              :             }
     140            1 :             reader.skip( spaces );
     141            1 :         }
     142              :     }
     143              : 
     144              :     [[nodiscard]] auto eof( ) -> bool
     145              :     {
     146              :         return current_char( ) == 0;
     147              :     }
     148              : 
     149              : public:
     150         3809 :     istream( spb::io::reader reader )
     151         3809 :         : reader( reader )
     152              :     {
     153         3809 :     }
     154              : 
     155              :     void deserialize( auto & value );
     156              :     template < size_t ordinal, typename T >
     157              :     void deserialize_variant( T & variant );
     158              :     template < typename T >
     159              :     [[nodiscard]] auto deserialize_bitfield( uint32_t bits ) -> T;
     160              :     [[nodiscard]] auto deserialize_int( ) -> int32_t;
     161              :     [[nodiscard]] auto deserialize_string_or_int( size_t min_size, size_t max_size )
     162              :         -> std::variant< std::string_view, int32_t >;
     163              :     [[nodiscard]] auto deserialize_key( size_t min_size, size_t max_size ) -> std::string_view;
     164              :     [[nodiscard]] auto current_key( ) const -> std::string_view;
     165              : 
     166        12372 :     [[nodiscard]] auto current_char( ) -> char
     167              :     {
     168        12372 :         if( m_current < 0 )
     169              :         {
     170         5500 :             update_current( true );
     171              :         }
     172              : 
     173        12372 :         return m_current;
     174              :     }
     175              :     /**
     176              :      * @brief consumes `current char` if its equal to c
     177              :      *
     178              :      * @param c consumed char
     179              :      * @return true if char was consumed
     180              :      */
     181         6974 :     [[nodiscard]] auto consume( char c ) -> bool
     182              :     {
     183         6974 :         if( current_char( ) == c )
     184              :         {
     185         2697 :             consume_current_char( true );
     186         2697 :             return true;
     187              :         }
     188         4277 :         return false;
     189              :     }
     190              : 
     191              :     /**
     192              :      * @brief consumes an `token`
     193              :      *
     194              :      * @param token consumed `token` (whole word)
     195              :      * @return true if `token` was consumed
     196              :      */
     197          594 :     [[nodiscard]] auto consume( std::string_view token ) -> bool
     198              :     {
     199          594 :         assert( !token.empty( ) );
     200              : 
     201          594 :         if( current_char( ) != token[ 0 ] )
     202              :         {
     203          518 :             return false;
     204              :         }
     205              : 
     206           76 :         if( !reader.view( token.size( ) ).starts_with( token ) )
     207              :         {
     208            3 :             return false;
     209              :         }
     210           73 :         auto token_view = reader.view( token.size( ) + 1 ).substr( 0, token.size( ) + 1 );
     211          109 :         if( token_view.size( ) == token.size( ) || isspace( token_view.back( ) ) ||
     212           36 :             ( !isalnum( token_view.back( ) ) && token_view.back( ) != '_' ) )
     213              :         {
     214           67 :             reader.skip( token.size( ) );
     215           67 :             update_current( true );
     216           67 :             return true;
     217              :         }
     218            6 :         return false;
     219              :     }
     220              : 
     221        23108 :     [[nodiscard]] auto view( size_t size ) -> std::string_view
     222              :     {
     223        23108 :         auto result = reader.view( size );
     224        23108 :         if( result.empty( ) )
     225              :         {
     226         2584 :             throw std::runtime_error( "unexpected end of stream" );
     227              :         }
     228        20524 :         return result;
     229              :     }
     230              : 
     231         5995 :     void consume_current_char( bool skip_white_space ) noexcept
     232              :     {
     233         5995 :         reader.skip( 1 );
     234         5995 :         update_current( skip_white_space );
     235         5995 :     }
     236              : 
     237        23045 :     void skip( size_t size )
     238              :     {
     239        23045 :         reader.skip( size );
     240        23045 :         m_current = -1;
     241        23045 :     }
     242              :     void skip_value( );
     243              : };
     244              : 
     245           50 : static inline void deserialize( istream & stream, spb::detail::proto_enum auto & value )
     246              : {
     247           50 :     deserialize_value( stream, value );
     248           48 : }
     249              : 
     250           20 : static inline void ignore_string( istream & stream )
     251              : {
     252           20 :     if( stream.current_char( ) != '"' )
     253              :     {
     254            1 :         throw std::runtime_error( "expecting '\"'" );
     255              :     }
     256              : 
     257           19 :     auto last = escape;
     258              :     for( ;; )
     259              :     {
     260           21 :         auto view   = stream.view( UINT32_MAX );
     261           21 :         auto length = 0U;
     262          921 :         for( auto current : view )
     263              :         {
     264          919 :             length += 1;
     265          919 :             if( current == '"' && last != escape )
     266              :             {
     267           19 :                 stream.skip( length );
     268           19 :                 return;
     269              :             }
     270              :             //- handle \\"
     271          900 :             last = current != escape || last != escape ? current : ' ';
     272              :         }
     273            2 :         stream.skip( view.size( ) );
     274            2 :     }
     275              : }
     276              : 
     277          700 : static inline auto deserialize_string_view( istream & stream, size_t min_size, size_t max_size )
     278              :     -> std::string_view
     279              : {
     280          700 :     if( stream.current_char( ) != '"' )
     281              :     {
     282            1 :         throw std::runtime_error( "expecting '\"'" );
     283              :     }
     284              : 
     285              :     //- +2 for '"'
     286          699 :     auto view   = stream.view( max_size + 2 );
     287          699 :     auto last   = escape;
     288          699 :     auto length = size_t( 0 );
     289         5417 :     for( auto current : view )
     290              :     {
     291         5416 :         length += 1;
     292              : 
     293         5416 :         if( current == '"' && last != escape )
     294              :         {
     295          698 :             stream.skip( length );
     296              : 
     297          698 :             if( ( length - 2 ) >= min_size && ( length - 2 ) <= max_size )
     298              :             {
     299          689 :                 return view.substr( 1, length - 2 );
     300              :             }
     301              : 
     302            9 :             return { };
     303              :         }
     304              :         //- handle \\"
     305         4718 :         last = current != escape || last != escape ? current : ' ';
     306              :     }
     307              : 
     308            1 :     ignore_string( stream );
     309            1 :     return { };
     310              : }
     311              : 
     312           21 : static inline auto unicode_from_hex( istream & stream ) -> uint16_t
     313              : {
     314           21 :     const auto esc_size = 4U;
     315           21 :     auto unicode_view   = stream.view( esc_size );
     316           21 :     if( unicode_view.size( ) < esc_size )
     317              :     {
     318            4 :         throw std::runtime_error( "invalid escape sequence" );
     319              :     }
     320           17 :     auto value = uint16_t( 0 );
     321              :     auto result =
     322           17 :         spb_std_emu::from_chars( unicode_view.data( ), unicode_view.data( ) + esc_size, value, 16 );
     323           17 :     if( result.ec != std::errc{ } || result.ptr != unicode_view.data( ) + esc_size )
     324              :     {
     325            1 :         throw std::runtime_error( "invalid escape sequence" );
     326              :     }
     327           16 :     stream.skip( esc_size );
     328           16 :     return value;
     329              : }
     330              : 
     331           15 : static inline auto unescape_unicode( istream & stream, char utf8[ 4 ] ) -> uint32_t
     332              : {
     333           15 :     auto value = uint32_t( unicode_from_hex( stream ) );
     334           12 :     if( value >= 0xD800 && value <= 0xDBFF && stream.view( 2 ).starts_with( "\\u"sv ) )
     335              :     {
     336            6 :         stream.skip( 2 );
     337            6 :         auto low = unicode_from_hex( stream );
     338              : 
     339            4 :         if( low < 0xDC00 || low > 0xDFFF )
     340              :         {
     341            2 :             throw std::invalid_argument( "invalid escape sequence" );
     342              :         }
     343            2 :         value = ( ( value - 0xD800 ) << 10 ) + ( low - 0xDC00 ) + 0x10000;
     344              :     }
     345            8 :     if( auto result = spb::detail::utf8::encode_point( value, utf8 ); result != 0 )
     346              :     {
     347            8 :         return result;
     348              :     }
     349            0 :     throw std::runtime_error( "invalid escape sequence" );
     350              : }
     351          309 : static inline auto unescape( istream & stream, char utf8[ 4 ] ) -> uint32_t
     352              : {
     353          309 :     auto c = stream.current_char( );
     354          309 :     stream.consume_current_char( false );
     355          309 :     switch( c )
     356              :     {
     357           15 :     case '"':
     358           15 :         utf8[ 0 ] = '"';
     359           15 :         return 1;
     360            5 :     case '\\':
     361            5 :         utf8[ 0 ] = '\\';
     362            5 :         return 1;
     363            1 :     case '/':
     364            1 :         utf8[ 0 ] = '/';
     365            1 :         return 1;
     366            4 :     case 'b':
     367            4 :         utf8[ 0 ] = '\b';
     368            4 :         return 1;
     369            4 :     case 'f':
     370            4 :         utf8[ 0 ] = '\f';
     371            4 :         return 1;
     372            7 :     case 'n':
     373            7 :         utf8[ 0 ] = '\n';
     374            7 :         return 1;
     375            6 :     case 'r':
     376            6 :         utf8[ 0 ] = '\r';
     377            6 :         return 1;
     378           11 :     case 't':
     379           11 :         utf8[ 0 ] = '\t';
     380           11 :         return 1;
     381           15 :     case 'u':
     382           15 :         return unescape_unicode( stream, utf8 );
     383          241 :     default:
     384          241 :         throw std::runtime_error( "invalid escape sequence" );
     385              :     }
     386              : }
     387              : 
     388          353 : static inline void deserialize( istream & stream, spb::detail::proto_field_string auto & value )
     389              : {
     390          353 :     if( stream.current_char( ) != '"' )
     391              :     {
     392            7 :         throw std::runtime_error( "expecting '\"'" );
     393              :     }
     394              : 
     395          346 :     stream.consume_current_char( false );
     396              : 
     397              :     if constexpr( spb::detail::proto_field_string_resizable< decltype( value ) > )
     398              :     {
     399          326 :         value.clear( );
     400              :     }
     401          346 :     auto index           = size_t( 0 );
     402          388 :     auto append_to_value = [ & ]( const char * str, size_t size )
     403              :     {
     404              :         if constexpr( spb::detail::proto_field_string_resizable< decltype( value ) > )
     405              :         {
     406          418 :             value.append( str, size );
     407              :         }
     408              :         else
     409              :         {
     410           88 :             if( auto space_left = value.size( ) - index; size <= space_left ) [[likely]]
     411              :             {
     412           42 :                 memcpy( value.data( ) + index, str, size );
     413           42 :                 index += size;
     414              :             }
     415              :             else
     416              :             {
     417            2 :                 throw std::runtime_error( "invalid string size" );
     418              :             }
     419              :         }
     420              :     };
     421              : 
     422           62 :     for( ;; )
     423              :     {
     424          408 :         auto view  = stream.view( UINT32_MAX );
     425          401 :         auto found = view.find_first_of( R"("\)" );
     426          401 :         if( found == view.npos ) [[unlikely]]
     427              :         {
     428            1 :             append_to_value( view.data( ), view.size( ) );
     429            1 :             stream.skip( view.size( ) );
     430            1 :             continue;
     431              :         }
     432              : 
     433          400 :         append_to_value( view.data( ), found );
     434              :         // +1 for '"' or '\'
     435          398 :         stream.skip( found + 1 );
     436          398 :         if( view[ found ] == '"' ) [[likely]]
     437              :         {
     438              :             if constexpr( !spb::detail::proto_field_string_resizable< decltype( value ) > )
     439              :             {
     440           18 :                 if( index != value.size( ) )
     441              :                 {
     442            2 :                     throw std::runtime_error( "invalid string size" );
     443              :                 }
     444              :             }
     445           87 :             return;
     446              :         }
     447              :         char utf8_buffer[ 4 ];
     448          309 :         auto utf8_size = unescape( stream, utf8_buffer );
     449           61 :         append_to_value( utf8_buffer, utf8_size );
     450              :     }
     451              :     spb::detail::utf8::validate( std::string_view( value.data( ), value.size( ) ) );
     452              : }
     453              : 
     454          691 : static inline void deserialize( istream & stream,
     455              :                                 spb::detail::proto_field_int_or_float auto & value )
     456              : {
     457          691 :     if( stream.current_char( ) == '"' ) [[unlikely]]
     458              :     {
     459              :         //- https://protobuf.dev/programming-guides/proto2/#json
     460              :         //- number can be a string
     461           16 :         auto view   = deserialize_string_view( stream, 1, UINT32_MAX );
     462           16 :         auto result = spb_std_emu::from_chars( view.data( ), view.data( ) + view.size( ), value );
     463           16 :         if( result.ec != std::errc{ } )
     464              :         {
     465            8 :             throw std::runtime_error( "invalid number" );
     466              :         }
     467            8 :         return;
     468              :     }
     469          675 :     auto view   = stream.view( UINT32_MAX );
     470          662 :     auto result = spb_std_emu::from_chars( view.data( ), view.data( ) + view.size( ), value );
     471          662 :     if( result.ec != std::errc{ } )
     472              :     {
     473           25 :         throw std::runtime_error( "invalid number" );
     474              :     }
     475          637 :     stream.skip( result.ptr - view.data( ) );
     476              : }
     477              : 
     478           66 : static inline void deserialize( istream & stream, bool & value )
     479              : {
     480           66 :     if( stream.consume( "true"sv ) )
     481              :     {
     482           27 :         value = true;
     483              :     }
     484           39 :     else if( stream.consume( "false"sv ) )
     485              :     {
     486           22 :         value = false;
     487              :     }
     488              :     else
     489              :     {
     490           17 :         throw std::runtime_error( "expecting 'true' or 'false'" );
     491              :     }
     492           49 : }
     493              : 
     494              : static inline void deserialize( istream & stream, auto & value );
     495              : 
     496              : template < typename keyT, typename valueT >
     497              : static inline void deserialize( istream & stream, std::map< keyT, valueT > & value );
     498              : 
     499              : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & value );
     500              : 
     501              : template < spb::detail::proto_label_repeated C >
     502          208 : static inline void deserialize( istream & stream, C & value )
     503              : {
     504          208 :     if( stream.consume( "null"sv ) )
     505              :     {
     506            5 :         value.clear( );
     507            5 :         return;
     508              :     }
     509              : 
     510          203 :     if( !stream.consume( '[' ) )
     511              :     {
     512           10 :         throw std::runtime_error( "expecting '['" );
     513              :     }
     514              : 
     515          193 :     if( stream.consume( ']' ) )
     516              :     {
     517            5 :         return;
     518              :     }
     519              : 
     520              :     do
     521              :     {
     522              :         if constexpr( std::is_same_v< typename C::value_type, bool > )
     523              :         {
     524           16 :             auto b = false;
     525           16 :             deserialize( stream, b );
     526           14 :             value.push_back( b );
     527              :         }
     528              :         else
     529              :         {
     530          277 :             deserialize( stream, value.emplace_back( ) );
     531              :         }
     532          283 :     } while( stream.consume( ',' ) );
     533              : 
     534          178 :     if( !stream.consume( ']' ) )
     535              :     {
     536            2 :         throw std::runtime_error( "expecting ']'" );
     537              :     }
     538              : }
     539              : 
     540              : template < spb::detail::proto_label_repeated_fixed_size C >
     541           12 : static inline void deserialize( istream & stream, C & value )
     542              : {
     543           12 :     if( stream.consume( "null"sv ) )
     544              :     {
     545            0 :         typename C::value_type tmp = { };
     546            0 :         for( size_t i = 0; i < value.size( ); i++ )
     547              :         {
     548            0 :             value[ i ] = tmp;
     549              :         }
     550            0 :         return;
     551              :     }
     552              : 
     553           12 :     if( !stream.consume( '[' ) )
     554              :     {
     555            0 :         throw std::runtime_error( "expecting '['" );
     556              :     }
     557              : 
     558           96 :     for( size_t i = 0; i < value.size( ); i++ )
     559              :     {
     560              :         typename C::value_type tmp;
     561           48 :         deserialize( stream, tmp );
     562           44 :         value[ i ] = tmp;
     563           88 :         if( i + 1 >= value.size( ) )
     564            8 :             break;
     565              : 
     566           68 :         while( stream.consume( ',' ) )
     567              :             ;
     568              :     }
     569              : 
     570            8 :     if( !stream.consume( ']' ) )
     571              :     {
     572            4 :         throw std::runtime_error( "expecting ']'" );
     573              :     }
     574              : }
     575              : 
     576           62 : static inline void deserialize( istream & stream, spb::detail::proto_field_bytes auto & value )
     577              : {
     578           62 :     if( stream.consume( "null"sv ) )
     579              :     {
     580            2 :         clear( value );
     581            2 :         return;
     582              :     }
     583              : 
     584           60 :     base64_decode_string( value, stream );
     585              : }
     586              : 
     587              : template < typename T >
     588           16 : void deserialize_map_key( istream & stream, T & map_key )
     589              : {
     590              :     if constexpr( std::is_same_v< T, std::string > )
     591              :     {
     592            8 :         return deserialize( stream, map_key );
     593              :     }
     594            8 :     auto str_key_map = deserialize_string_view( stream, 1, UINT32_MAX );
     595           24 :     auto reader = [ ptr = str_key_map.data( ), end = str_key_map.data( ) + str_key_map.size( ) ](
     596              :                       void * data, size_t size ) mutable -> size_t
     597              :     {
     598           16 :         size_t bytes_left = end - ptr;
     599           16 :         size              = std::min( size, bytes_left );
     600           16 :         memcpy( data, ptr, size );
     601           16 :         ptr += size;
     602           16 :         return size;
     603              :     };
     604            8 :     auto key_stream = istream( reader );
     605            8 :     deserialize( key_stream, map_key );
     606            6 : }
     607              : 
     608              : template < typename keyT, typename valueT >
     609           28 : static inline void deserialize( istream & stream, std::map< keyT, valueT > & value )
     610              : {
     611           28 :     if( stream.consume( "null"sv ) )
     612              :     {
     613            4 :         value.clear( );
     614            4 :         return;
     615              :     }
     616           24 :     if( !stream.consume( '{' ) )
     617              :     {
     618            5 :         throw std::runtime_error( "expecting '{'" );
     619              :     }
     620              : 
     621           19 :     if( stream.consume( '}' ) )
     622              :     {
     623            4 :         return;
     624              :     }
     625              : 
     626              :     do
     627              :     {
     628           16 :         auto map_key = keyT( );
     629           16 :         deserialize_map_key( stream, map_key );
     630           14 :         if( !stream.consume( ':' ) )
     631              :         {
     632            1 :             throw std::runtime_error( "expecting ':'" );
     633              :         }
     634           13 :         auto map_value = valueT( );
     635           13 :         deserialize( stream, map_value );
     636            8 :         value.emplace( std::move( map_key ), std::move( map_value ) );
     637           15 :     } while( stream.consume( ',' ) );
     638              : 
     639            7 :     if( !stream.consume( '}' ) )
     640              :     {
     641            1 :         throw std::runtime_error( "expecting '}'" );
     642              :     }
     643              : }
     644              : 
     645          164 : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & p_value )
     646              : {
     647          164 :     if( stream.consume( "null"sv ) )
     648              :     {
     649            4 :         p_value.reset( );
     650            4 :         return;
     651              :     }
     652              : 
     653          160 :     if( p_value.has_value( ) )
     654              :     {
     655            4 :         deserialize( stream, *p_value );
     656              :     }
     657              :     else
     658              :     {
     659          156 :         deserialize(
     660              :             stream,
     661          322 :             p_value.emplace( typename std::decay_t< decltype( p_value ) >::value_type( ) ) );
     662              :     }
     663              : }
     664              : 
     665              : template < typename T >
     666           13 : static inline void deserialize( istream & stream, std::unique_ptr< T > & value )
     667              : {
     668           13 :     if( stream.consume( "null"sv ) )
     669              :     {
     670            2 :         value.reset( );
     671            2 :         return;
     672              :     }
     673              : 
     674           11 :     if( value )
     675              :     {
     676            5 :         deserialize( stream, *value );
     677              :     }
     678              :     else
     679              :     {
     680            6 :         value = std::make_unique< T >( );
     681            6 :         deserialize( stream, *value );
     682              :     }
     683              : }
     684              : 
     685              : static inline void ignore_value( istream & stream );
     686           10 : static inline void ignore_key_and_value( istream & stream )
     687              : {
     688           10 :     ignore_string( stream );
     689            9 :     if( !stream.consume( ':' ) )
     690              :     {
     691            1 :         throw std::runtime_error( "expecting ':'" );
     692              :     }
     693            8 :     ignore_value( stream );
     694            7 : }
     695              : 
     696            8 : static inline void ignore_object( istream & stream )
     697              : {
     698              :     //- '{' was already checked by caller
     699            8 :     stream.consume_current_char( true );
     700              : 
     701            8 :     if( stream.consume( '}' ) )
     702              :     {
     703            1 :         return;
     704              :     }
     705              : 
     706              :     do
     707              :     {
     708           10 :         ignore_key_and_value( stream );
     709            7 :     } while( stream.consume( ',' ) );
     710              : 
     711            4 :     if( !stream.consume( '}' ) )
     712              :     {
     713            1 :         throw std::runtime_error( "expecting '}'" );
     714              :     }
     715              : }
     716              : 
     717            9 : static inline void ignore_array( istream & stream )
     718              : {
     719              :     //- '[' was already checked by caller
     720            9 :     stream.consume_current_char( true );
     721              : 
     722            9 :     if( stream.consume( ']' ) )
     723              :     {
     724            2 :         return;
     725              :     }
     726              : 
     727              :     do
     728              :     {
     729            9 :         ignore_value( stream );
     730            6 :     } while( stream.consume( ',' ) );
     731              : 
     732            4 :     if( !stream.consume( ']' ) )
     733              :     {
     734            1 :         throw std::runtime_error( "expecting ']" );
     735              :     }
     736              : }
     737              : 
     738           13 : static inline void ignore_number( istream & stream )
     739              : {
     740           13 :     auto value = double{ };
     741           13 :     deserialize( stream, value );
     742            9 : }
     743              : 
     744            5 : static inline void ignore_bool( istream & stream )
     745              : {
     746            5 :     auto value = bool{ };
     747            5 :     deserialize( stream, value );
     748            3 : }
     749              : 
     750            2 : static inline void ignore_null( istream & stream )
     751              : {
     752            2 :     if( !stream.consume( "null"sv ) )
     753              :     {
     754            1 :         throw std::runtime_error( "expecting 'null'" );
     755              :     }
     756            1 : }
     757              : 
     758           46 : static inline void ignore_value( istream & stream )
     759              : {
     760           46 :     switch( stream.current_char( ) )
     761              :     {
     762            8 :     case '{':
     763            8 :         return ignore_object( stream );
     764            9 :     case '[':
     765            9 :         return ignore_array( stream );
     766            9 :     case '"':
     767            9 :         return ignore_string( stream );
     768            2 :     case 'n':
     769            2 :         return ignore_null( stream );
     770            5 :     case 't':
     771              :     case 'f':
     772            5 :         return ignore_bool( stream );
     773           13 :     default:
     774           13 :         return ignore_number( stream );
     775              :     }
     776              : }
     777              : 
     778              : template < typename T >
     779          159 : inline auto deserialize_bitfield( istream & stream, uint32_t bits ) -> T
     780              : {
     781          159 :     auto value = T( );
     782          159 :     deserialize( stream, value );
     783          159 :     spb::detail::check_if_value_fit_in_bits( value, bits );
     784          158 :     return value;
     785              : }
     786              : 
     787              : template < size_t ordinal, typename T >
     788           12 : static inline void deserialize_variant( istream & stream, T & variant )
     789              : {
     790           12 :     deserialize( stream, variant.template emplace< ordinal >( ) );
     791           12 : }
     792              : 
     793          739 : static inline void deserialize( istream & stream, auto & value )
     794              : {
     795          739 :     if( !stream.consume( '{' ) )
     796              :     {
     797            2 :         throw std::runtime_error( "expecting '{'" );
     798              :     }
     799              : 
     800          737 :     if( stream.consume( '}' ) )
     801              :     {
     802          134 :         return;
     803              :     }
     804              : 
     805              :     for( ;; )
     806              :     {
     807              :         //
     808              :         //- deserialize_value is generated by the sprotoc
     809              :         //
     810          629 :         deserialize_value( stream, value );
     811              : 
     812          603 :         if( stream.consume( ',' ) )
     813              :         {
     814           26 :             continue;
     815              :         }
     816              : 
     817          577 :         if( stream.consume( '}' ) )
     818              :         {
     819          576 :             return;
     820              :         }
     821              : 
     822            1 :         throw std::runtime_error( "expecting '}' or ','" );
     823              :     }
     824              : }
     825              : 
     826          629 : inline auto istream::deserialize_key( size_t min_size, size_t max_size ) -> std::string_view
     827              : {
     828          629 :     m_current_key = deserialize_string_view( *this, min_size, max_size );
     829          628 :     if( !consume( ':' ) )
     830              :     {
     831            1 :         throw std::runtime_error( "expecting ':'" );
     832              :     }
     833          627 :     return m_current_key;
     834              : }
     835              : 
     836          427 : inline void istream::deserialize( auto & value )
     837              : {
     838          427 :     return detail::deserialize( *this, value );
     839              : }
     840              : 
     841              : template < size_t ordinal, typename T >
     842           12 : inline void istream::deserialize_variant( T & variant )
     843              : {
     844           12 :     return detail::deserialize_variant< ordinal >( *this, variant );
     845              : }
     846              : 
     847              : template < typename T >
     848          159 : inline auto istream::deserialize_bitfield( uint32_t bits ) -> T
     849              : {
     850          159 :     return detail::deserialize_bitfield< T >( *this, bits );
     851              : }
     852              : 
     853           50 : inline auto istream::deserialize_string_or_int( size_t min_size, size_t max_size )
     854              :     -> std::variant< std::string_view, int32_t >
     855              : {
     856           50 :     if( current_char( ) == '"' )
     857              :     {
     858           47 :         return deserialize_string_view( *this, min_size, max_size );
     859              :     }
     860            3 :     return deserialize_int( );
     861              : }
     862              : 
     863            3 : inline auto istream::deserialize_int( ) -> int32_t
     864              : {
     865            3 :     auto result = int32_t{ };
     866            3 :     detail::deserialize( *this, result );
     867            2 :     return result;
     868              : }
     869              : 
     870           29 : inline void istream::skip_value( )
     871              : {
     872           29 :     return detail::ignore_value( *this );
     873              : }
     874              : 
     875         1226 : static inline void deserialize( auto & value, spb::io::reader reader )
     876              : {
     877         1226 :     auto stream = detail::istream( reader );
     878         2076 :     return detail::deserialize( stream, value );
     879              : }
     880              : 
     881              : }// namespace spb::json::detail
        

Generated by: LCOV version 2.0-1