LCOV - code coverage report
Current view: top level - spb/pb - deserialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 84.9 % 284 241
Test Date: 2025-05-23 14:18:13 Functions: 27.5 % 1452 400

            Line data    Source code
       1              : /***************************************************************************\
       2              : * Name        : deserialize library for protobuf                            *
       3              : * Description : all protobuf 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 "../utf8.h"
      16              : #include "wire-types.h"
      17              : #include <climits>
      18              : #include <cstddef>
      19              : #include <cstdint>
      20              : #include <cstring>
      21              : #include <limits>
      22              : #include <map>
      23              : #include <memory>
      24              : #include <spb/io/io.hpp>
      25              : #include <stdexcept>
      26              : #include <string_view>
      27              : #include <type_traits>
      28              : 
      29              : namespace spb::pb::detail
      30              : {
      31              : 
      32              : struct istream
      33              : {
      34              : private:
      35              :     spb::io::reader on_read;
      36              :     size_t m_size;
      37              : 
      38              : public:
      39         1313 :     istream( spb::io::reader reader, size_t size = std::numeric_limits< size_t >::max( ) ) noexcept
      40         1313 :         : on_read( reader )
      41         1313 :         , m_size( size )
      42              :     {
      43         1313 :     }
      44              : 
      45              :     void skip( uint32_t tag );
      46              :     void read_skip( size_t size );
      47              : 
      48              :     void deserialize( auto & value, uint32_t tag );
      49              : 
      50              :     template < scalar_encoder encoder >
      51              :     void deserialize_as( auto & value, uint32_t tag );
      52              : 
      53              :     template < size_t ordinal, typename T >
      54              :     void deserialize_variant( T & variant, uint32_t tag );
      55              : 
      56              :     template < size_t ordinal, scalar_encoder encoder, typename T >
      57              :     void deserialize_variant_as( T & variant, uint32_t tag );
      58              : 
      59              :     template < scalar_encoder encoder, typename T >
      60              :     auto deserialize_bitfield_as( uint32_t bits, uint32_t tag ) -> T;
      61              : 
      62         1171 :     [[nodiscard]] auto read_byte( ) -> uint8_t
      63              :     {
      64         1171 :         uint8_t result = { };
      65         1171 :         read_exact( &result, sizeof( result ) );
      66         1111 :         return result;
      67              :     }
      68              : 
      69         1734 :     [[nodiscard]] auto read_byte_or_eof( ) -> int
      70              :     {
      71         1734 :         uint8_t result = { };
      72         1734 :         if( on_read( &result, sizeof( result ) ) == 0 )
      73              :         {
      74          745 :             return -1;
      75              :         }
      76          989 :         return result;
      77              :     }
      78              : 
      79         2790 :     [[nodiscard]] auto size( ) const -> size_t
      80              :     {
      81         2790 :         return m_size;
      82              :     }
      83              : 
      84         1798 :     void read_exact( void * data, size_t size )
      85              :     {
      86         1798 :         if( this->size( ) < size ) [[unlikely]]
      87              :         {
      88           12 :             throw std::runtime_error( "unexpected end of stream" );
      89              :         }
      90              : 
      91         3524 :         while( size > 0 )
      92              :         {
      93         1834 :             auto chunk_size = on_read( data, size );
      94         1834 :             if( chunk_size == 0 )
      95              :             {
      96           96 :                 throw std::runtime_error( "unexpected end of stream" );
      97              :             }
      98              : 
      99         1738 :             size -= chunk_size;
     100         1738 :             m_size -= chunk_size;
     101              :         }
     102         1690 :     }
     103              : 
     104          446 :     [[nodiscard]] auto empty( ) const -> bool
     105              :     {
     106          446 :         return size( ) == 0;
     107              :     }
     108              : 
     109          280 :     [[nodiscard]] auto sub_stream( size_t sub_size ) -> istream
     110              :     {
     111          280 :         if( size( ) < sub_size )
     112              :         {
     113            1 :             throw std::runtime_error( "unexpected end of stream" );
     114              :         }
     115          279 :         m_size -= sub_size;
     116          279 :         return istream( on_read, sub_size );
     117              :     }
     118              : };
     119              : 
     120         1999 : [[nodiscard]] static inline auto wire_type_from_tag( uint32_t tag ) -> wire_type
     121              : {
     122         1999 :     return wire_type( tag & 0x07 );
     123              : }
     124              : 
     125         1949 : [[nodiscard]] static inline auto field_from_tag( uint32_t tag ) -> uint32_t
     126              : {
     127         1949 :     return tag >> 3;
     128              : }
     129              : 
     130          988 : static inline void check_tag( uint32_t tag )
     131              : {
     132          988 :     if( field_from_tag( tag ) == 0 )
     133              :     {
     134            2 :         throw std::runtime_error( "invalid field id" );
     135              :     }
     136          986 : }
     137              : 
     138          757 : static inline void check_wire_type( wire_type type1, wire_type type2 )
     139              : {
     140          757 :     if( type1 != type2 )
     141              :     {
     142            9 :         throw std::runtime_error( "invalid wire type" );
     143              :     }
     144          748 : }
     145              : 
     146          193 : static inline void check_if_empty( istream & stream )
     147              : {
     148          193 :     if( !stream.empty( ) )
     149              :     {
     150            0 :         throw std::runtime_error( "unexpected data in stream" );
     151              :     }
     152          193 : }
     153              : 
     154         1734 : [[nodiscard]] static inline auto read_tag_or_eof( istream & stream ) -> uint32_t
     155              : {
     156         1734 :     auto byte_or_eof = stream.read_byte_or_eof( );
     157         1734 :     if( byte_or_eof < 0 )
     158              :     {
     159          745 :         return 0;
     160              :     }
     161          989 :     auto byte = uint8_t( byte_or_eof );
     162          989 :     auto tag  = uint32_t( byte & 0x7F );
     163              : 
     164         1004 :     for( size_t shift = CHAR_BIT - 1; ( byte & 0x80 ) != 0; shift += CHAR_BIT - 1 )
     165              :     {
     166           16 :         if( shift >= sizeof( tag ) * CHAR_BIT )
     167              :         {
     168            1 :             throw std::runtime_error( "invalid tag" );
     169              :         }
     170              : 
     171           15 :         byte = stream.read_byte( );
     172           15 :         tag |= uint64_t( byte & 0x7F ) << shift;
     173              :     }
     174              : 
     175          988 :     check_tag( tag );
     176              : 
     177          986 :     return tag;
     178              : }
     179              : 
     180              : template < typename T >
     181          691 : [[nodiscard]] static inline auto read_varint( istream & stream ) -> T
     182              : {
     183              :     if constexpr( std::is_same_v< T, bool > )
     184              :     {
     185           38 :         switch( stream.read_byte( ) )
     186              :         {
     187           10 :         case 0:
     188           10 :             return false;
     189           16 :         case 1:
     190           16 :             return true;
     191            8 :         default:
     192            8 :             throw std::runtime_error( "invalid varint for bool" );
     193              :         }
     194              :     }
     195              :     else
     196              :     {
     197          653 :         auto value = uint64_t( 0 );
     198              : 
     199         1132 :         for( auto shift = 0U; shift < sizeof( value ) * CHAR_BIT; shift += CHAR_BIT - 1 )
     200              :         {
     201         1118 :             uint8_t byte = stream.read_byte( );
     202         1062 :             value |= uint64_t( byte & 0x7F ) << shift;
     203         1062 :             if( ( byte & 0x80 ) == 0 )
     204              :             {
     205              :                 if constexpr( std::is_signed_v< T > && sizeof( T ) < sizeof( value ) )
     206              :                 {
     207              :                     //- GPB encodes signed varints always as 64-bits
     208              :                     //- so int32_t(-2) is encoded as "\xfe\xff\xff\xff\xff\xff\xff\xff\xff\x01",
     209              :                     // same as int64_t(-2)
     210              :                     //- but it should be encoded as  "\xfe\xff\xff\xff\x0f"
     211          106 :                     value = T( value );
     212              :                 }
     213          583 :                 auto result = T( value );
     214              :                 if constexpr( std::is_signed_v< T > )
     215              :                 {
     216          134 :                     if( result == std::make_signed_t< T >( value ) )
     217              :                     {
     218          134 :                         return result;
     219              :                     }
     220              :                 }
     221              :                 else
     222              :                 {
     223          449 :                     if( result == value )
     224              :                     {
     225          443 :                         return result;
     226              :                     }
     227              :                 }
     228              : 
     229            6 :                 break;
     230              :             }
     231              :         }
     232           20 :         throw std::runtime_error( "invalid varint" );
     233              :     }
     234              : }
     235              : 
     236              : static inline void deserialize( istream & stream, spb::detail::proto_message auto & value,
     237              :                                 wire_type type );
     238              : 
     239              : template < scalar_encoder encoder >
     240              : static inline void deserialize_as( istream & stream,
     241              :                                    spb::detail::proto_field_int_or_float auto & value,
     242              :                                    wire_type type );
     243              : static inline void deserialize( istream & stream, spb::detail::proto_field_bytes auto & value,
     244              :                                 wire_type type );
     245              : static inline void deserialize( istream & stream, spb::detail::proto_label_repeated auto & value,
     246              :                                 wire_type type );
     247              : static inline void deserialize( istream & stream, spb::detail::proto_field_string auto & value,
     248              :                                 wire_type type );
     249              : 
     250              : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
     251              : static inline void deserialize_as( istream & stream, C & value, wire_type type );
     252              : 
     253              : template < scalar_encoder encoder, typename keyT, typename valueT >
     254              : static inline void deserialize_as( istream & stream, std::map< keyT, valueT > & value,
     255              :                                    wire_type type );
     256              : 
     257              : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & p_value,
     258              :                                 wire_type type );
     259              : 
     260              : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
     261              : static inline void deserialize_as( istream & stream, C & p_value, wire_type type );
     262              : 
     263              : template < typename T >
     264              : static inline void deserialize( istream & stream, std::unique_ptr< T > & value, wire_type type );
     265              : 
     266              : template < typename T, typename signedT, typename unsignedT >
     267          100 : static auto create_tmp_var( )
     268              : {
     269              :     if constexpr( std::is_signed< T >::value )
     270              :     {
     271           40 :         return signedT( );
     272              :     }
     273              :     else
     274              :     {
     275           60 :         return unsignedT( );
     276              :     }
     277              : }
     278              : 
     279              : template < scalar_encoder encoder, typename T >
     280          252 : static inline auto deserialize_bitfield_as( istream & stream, uint32_t bits, wire_type type ) -> T
     281              : {
     282          252 :     auto value = T( );
     283              :     if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::svarint )
     284              :     {
     285           20 :         check_wire_type( type, wire_type::varint );
     286              : 
     287           20 :         auto tmp = read_varint< std::make_unsigned_t< T > >( stream );
     288           20 :         value    = T( ( tmp >> 1 ) ^ ( ~( tmp & 1 ) + 1 ) );
     289              :     }
     290              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::varint )
     291              :     {
     292           52 :         check_wire_type( type, wire_type::varint );
     293           52 :         value = read_varint< T >( stream );
     294              :     }
     295              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i32 )
     296              :     {
     297              :         static_assert( sizeof( T ) <= sizeof( uint32_t ) );
     298              : 
     299          100 :         check_wire_type( type, wire_type::fixed32 );
     300              : 
     301              :         if constexpr( sizeof( value ) == sizeof( uint32_t ) )
     302              :         {
     303           40 :             stream.read_exact( &value, sizeof( value ) );
     304              :         }
     305              :         else
     306              :         {
     307           60 :             auto tmp = create_tmp_var< T, int32_t, uint32_t >( );
     308           60 :             stream.read_exact( &tmp, sizeof( tmp ) );
     309           60 :             spb::detail::check_if_value_fit_in_bits( tmp, bits );
     310           36 :             value = T( tmp );
     311              :         }
     312              :     }
     313              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i64 )
     314              :     {
     315              :         static_assert( sizeof( T ) <= sizeof( uint64_t ) );
     316           80 :         check_wire_type( type, wire_type::fixed64 );
     317              : 
     318              :         if constexpr( sizeof( value ) == sizeof( uint64_t ) )
     319              :         {
     320           40 :             stream.read_exact( &value, sizeof( value ) );
     321              :         }
     322              :         else
     323              :         {
     324           40 :             auto tmp = create_tmp_var< T, int64_t, uint64_t >( );
     325           40 :             stream.read_exact( &tmp, sizeof( tmp ) );
     326           40 :             spb::detail::check_if_value_fit_in_bits( tmp, bits );
     327           24 :             value = T( tmp );
     328              :         }
     329              :     }
     330          208 :     spb::detail::check_if_value_fit_in_bits( value, bits );
     331          156 :     return value;
     332              : }
     333              : 
     334              : template < scalar_encoder encoder >
     335           50 : static inline void deserialize_as( istream & stream, spb::detail::proto_enum auto & value,
     336              :                                    wire_type type )
     337              : {
     338              :     using T        = std::remove_cvref_t< decltype( value ) >;
     339              :     using int_type = std::underlying_type_t< T >;
     340              : 
     341              :     if constexpr( !scalar_encoder_is_packed( encoder ) )
     342              :     {
     343           26 :         check_wire_type( type, wire_type::varint );
     344              :     }
     345              : 
     346           50 :     value = T( read_varint< int_type >( stream ) );
     347           46 : }
     348              : 
     349              : template < scalar_encoder encoder >
     350          478 : static inline void deserialize_as( istream & stream,
     351              :                                    spb::detail::proto_field_int_or_float auto & value,
     352              :                                    wire_type type )
     353              : {
     354              :     using T = std::remove_cvref_t< decltype( value ) >;
     355              : 
     356              :     if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::svarint )
     357              :     {
     358              :         if constexpr( !scalar_encoder_is_packed( encoder ) )
     359              :         {
     360           48 :             check_wire_type( type, wire_type::varint );
     361              :         }
     362           74 :         auto tmp = read_varint< std::make_unsigned_t< T > >( stream );
     363           54 :         value    = T( ( tmp >> 1 ) ^ ( ~( tmp & 1 ) + 1 ) );
     364              :     }
     365              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::varint )
     366              :     {
     367              :         if constexpr( !scalar_encoder_is_packed( encoder ) )
     368              :         {
     369           92 :             check_wire_type( type, wire_type::varint );
     370              :         }
     371          132 :         value = read_varint< T >( stream );
     372              :     }
     373              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i32 )
     374              :     {
     375              :         static_assert( sizeof( T ) <= sizeof( uint32_t ) );
     376              : 
     377              :         if constexpr( !scalar_encoder_is_packed( encoder ) )
     378              :         {
     379          114 :             check_wire_type( type, wire_type::fixed32 );
     380              :         }
     381              :         if constexpr( sizeof( value ) == sizeof( uint32_t ) )
     382              :         {
     383           68 :             stream.read_exact( &value, sizeof( value ) );
     384              :         }
     385              :         else
     386              :         {
     387              :             if constexpr( std::is_signed_v< T > )
     388              :             {
     389           26 :                 auto tmp = int32_t( 0 );
     390           26 :                 stream.read_exact( &tmp, sizeof( tmp ) );
     391           44 :                 if( tmp > std::numeric_limits< T >::max( ) ||
     392           20 :                     tmp < std::numeric_limits< T >::min( ) )
     393              :                 {
     394            4 :                     throw std::runtime_error( "int overflow" );
     395              :                 }
     396           20 :                 value = T( tmp );
     397              :             }
     398              :             else
     399              :             {
     400           60 :                 auto tmp = uint32_t( 0 );
     401           60 :                 stream.read_exact( &tmp, sizeof( tmp ) );
     402           52 :                 if( tmp > std::numeric_limits< T >::max( ) )
     403              :                 {
     404            8 :                     throw std::runtime_error( "int overflow" );
     405              :                 }
     406           44 :                 value = T( tmp );
     407              :             }
     408              :         }
     409              :     }
     410              :     else if constexpr( scalar_encoder_type1( encoder ) == scalar_encoder::i64 )
     411              :     {
     412              :         static_assert( sizeof( T ) <= sizeof( uint64_t ) );
     413              :         if constexpr( !scalar_encoder_is_packed( encoder ) )
     414              :         {
     415           90 :             check_wire_type( type, wire_type::fixed64 );
     416              :         }
     417              :         if constexpr( sizeof( value ) == sizeof( uint64_t ) )
     418              :         {
     419           60 :             stream.read_exact( &value, sizeof( value ) );
     420              :         }
     421              :         else
     422              :         {
     423              :             if constexpr( std::is_signed_v< T > )
     424              :             {
     425           26 :                 auto tmp = int64_t( 0 );
     426           26 :                 stream.read_exact( &tmp, sizeof( tmp ) );
     427           44 :                 if( tmp > std::numeric_limits< T >::max( ) ||
     428           20 :                     tmp < std::numeric_limits< T >::min( ) )
     429              :                 {
     430            4 :                     throw std::runtime_error( "int overflow" );
     431              :                 }
     432           20 :                 value = T( tmp );
     433              :             }
     434              :             else
     435              :             {
     436           26 :                 auto tmp = uint64_t( 0 );
     437           26 :                 stream.read_exact( &tmp, sizeof( tmp ) );
     438           24 :                 if( tmp > std::numeric_limits< T >::max( ) )
     439              :                 {
     440            4 :                     throw std::runtime_error( "int overflow" );
     441              :                 }
     442           20 :                 value = T( tmp );
     443              :             }
     444              :         }
     445              :     }
     446          372 : }
     447              : 
     448           41 : static inline void deserialize( istream & stream, spb::detail::proto_label_optional auto & p_value,
     449              :                                 wire_type type )
     450              : {
     451           71 :     auto & value = p_value.emplace( typename std::decay_t< decltype( p_value ) >::value_type( ) );
     452           41 :     deserialize( stream, value, type );
     453           28 : }
     454              : 
     455              : template < scalar_encoder encoder, spb::detail::proto_label_optional C >
     456          100 : static inline void deserialize_as( istream & stream, C & p_value, wire_type type )
     457              : {
     458          100 :     auto & value = p_value.emplace( typename C::value_type( ) );
     459          100 :     deserialize_as< encoder >( stream, value, type );
     460           92 : }
     461              : 
     462           79 : static inline void deserialize( istream & stream, spb::detail::proto_field_string auto & value,
     463              :                                 wire_type type )
     464              : {
     465           79 :     check_wire_type( type, wire_type::length_delimited );
     466              :     if constexpr( spb::detail::proto_field_string_resizable< decltype( value ) > )
     467              :     {
     468           46 :         value.resize( stream.size( ) );
     469              :     }
     470              :     else
     471              :     {
     472           30 :         if( value.size( ) != stream.size( ) )
     473              :         {
     474           14 :             throw std::runtime_error( "invalid string size" );
     475              :         }
     476              :     }
     477           78 :     stream.read_exact( value.data( ), stream.size( ) );
     478           71 :     spb::detail::utf8::validate( std::string_view( value.data( ), value.size( ) ) );
     479           54 : }
     480              : 
     481              : template < typename T >
     482            0 : static inline void deserialize( istream & stream, std::unique_ptr< T > & value, wire_type type )
     483              : {
     484            0 :     value = std::make_unique< T >( );
     485            0 :     deserialize( stream, *value, type );
     486            0 : }
     487              : 
     488           48 : static inline void deserialize( istream & stream, spb::detail::proto_field_bytes auto & value,
     489              :                                 wire_type type )
     490              : {
     491           48 :     check_wire_type( type, wire_type::length_delimited );
     492              :     if constexpr( spb::detail::proto_field_bytes_resizable< decltype( value ) > )
     493              :     {
     494           24 :         value.resize( stream.size( ) );
     495              :     }
     496              :     else
     497              :     {
     498           48 :         if( stream.size( ) != value.size( ) )
     499              :         {
     500           12 :             throw std::runtime_error( "invalid bytes size" );
     501              :         }
     502              :     }
     503           48 :     stream.read_exact( value.data( ), stream.size( ) );
     504           34 : }
     505              : 
     506           38 : static inline void deserialize( istream & stream, spb::detail::proto_label_repeated auto & value,
     507              :                                 wire_type type )
     508              : {
     509           38 :     deserialize( stream, value.emplace_back( ), type );
     510           30 : }
     511              : 
     512              : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
     513          100 : static inline void deserialize_packed_as( istream & stream, C & value, wire_type type )
     514              : {
     515          234 :     while( !stream.empty( ) )
     516              :     {
     517              :         if constexpr( std::is_same_v< typename C::value_type, bool > )
     518              :         {
     519           10 :             value.emplace_back( read_varint< bool >( stream ) );
     520              :         }
     521              :         else
     522              :         {
     523          158 :             deserialize_as< encoder >( stream, value.emplace_back( ), type );
     524              :         }
     525              :     }
     526           66 : }
     527              : 
     528              : template < scalar_encoder encoder, spb::detail::proto_label_repeated C >
     529          224 : static inline void deserialize_as( istream & stream, C & value, wire_type type )
     530              : {
     531              :     if constexpr( scalar_encoder_is_packed( encoder ) )
     532              :     {
     533          100 :         deserialize_packed_as< encoder >( stream, value, wire_type_from_scalar_encoder( encoder ) );
     534              :     }
     535              :     else
     536              :     {
     537              :         if constexpr( std::is_same_v< typename C::value_type, bool > )
     538              :         {
     539           14 :             value.emplace_back( read_varint< bool >( stream ) );
     540              :         }
     541              :         else
     542              :         {
     543          110 :             deserialize_as< encoder >( stream, value.emplace_back( ), type );
     544              :         }
     545              :     }
     546          186 : }
     547              : 
     548              : template < scalar_encoder encoder, typename keyT, typename valueT >
     549            0 : static inline void deserialize_as( istream & stream, std::map< keyT, valueT > & value,
     550              :                                    wire_type type )
     551              : {
     552            0 :     const auto key_encoder   = scalar_encoder_type1( encoder );
     553            0 :     const auto value_encoder = scalar_encoder_type2( encoder );
     554              : 
     555            0 :     check_wire_type( type, wire_type::length_delimited );
     556              : 
     557            0 :     auto pair          = std::pair< keyT, valueT >( );
     558            0 :     auto key_defined   = false;
     559            0 :     auto value_defined = false;
     560            0 :     while( !stream.empty( ) )
     561              :     {
     562            0 :         const auto tag        = read_varint< uint32_t >( stream );
     563            0 :         const auto field      = field_from_tag( tag );
     564            0 :         const auto field_type = wire_type_from_tag( tag );
     565              : 
     566            0 :         switch( field )
     567              :         {
     568            0 :         case 1:
     569              :             if constexpr( std::is_integral_v< keyT > )
     570              :             {
     571            0 :                 deserialize_as< key_encoder >( stream, pair.first, field_type );
     572              :             }
     573              :             else
     574              :             {
     575            0 :                 if( field_type == wire_type::length_delimited )
     576              :                 {
     577            0 :                     const auto size = read_varint< uint32_t >( stream );
     578            0 :                     auto substream  = stream.sub_stream( size );
     579            0 :                     deserialize( substream, pair.first, field_type );
     580            0 :                     check_if_empty( substream );
     581              :                 }
     582              :                 else
     583              :                 {
     584            0 :                     deserialize( stream, pair.first, field_type );
     585              :                 }
     586              :             }
     587            0 :             key_defined = true;
     588            0 :             break;
     589            0 :         case 2:
     590              :             if constexpr( spb::detail::proto_field_number< valueT > )
     591              :             {
     592            0 :                 deserialize_as< value_encoder >( stream, pair.second, field_type );
     593              :             }
     594              :             else
     595              :             {
     596            0 :                 if( field_type == wire_type::length_delimited )
     597              :                 {
     598            0 :                     const auto size = read_varint< uint32_t >( stream );
     599            0 :                     auto substream  = stream.sub_stream( size );
     600            0 :                     deserialize( substream, pair.second, field_type );
     601            0 :                     check_if_empty( substream );
     602              :                 }
     603              :                 else
     604              :                 {
     605            0 :                     throw std::runtime_error( "invalid field" );
     606              :                 }
     607              :             }
     608            0 :             value_defined = true;
     609            0 :             break;
     610            0 :         default:
     611            0 :             throw std::runtime_error( "invalid field" );
     612              :         }
     613              :     }
     614            0 :     if( key_defined && value_defined )
     615              :     {
     616            0 :         value.insert( std::move( pair ) );
     617              :     }
     618              :     else
     619              :     {
     620            0 :         throw std::runtime_error( "invalid map item" );
     621              :     }
     622            0 : }
     623              : 
     624              : template < size_t ordinal, typename T >
     625            6 : static inline void deserialize_variant( istream & stream, T & variant, wire_type type )
     626              : {
     627            6 :     deserialize( stream, variant.template emplace< ordinal >( ), type );
     628            6 : }
     629              : 
     630              : template < size_t ordinal, scalar_encoder encoder, typename T >
     631            2 : static inline void deserialize_variant_as( istream & stream, T & variant, wire_type type )
     632              : {
     633            2 :     deserialize_as< encoder >( stream, variant.template emplace< ordinal >( ), type );
     634            2 : }
     635              : 
     636         1034 : static inline void deserialize_main( istream & stream, spb::detail::proto_message auto & value )
     637              : {
     638          700 :     for( ;; )
     639              :     {
     640         1734 :         const auto tag = read_tag_or_eof( stream );
     641         1731 :         if( !tag )
     642              :         {
     643          745 :             break;
     644              :         }
     645          986 :         const auto field_type = wire_type_from_tag( tag );
     646              : 
     647          986 :         if( field_type == wire_type::length_delimited )
     648              :         {
     649          270 :             const auto size = read_varint< uint32_t >( stream );
     650          270 :             auto substream  = stream.sub_stream( size );
     651          270 :             deserialize_value( substream, value, tag );
     652          186 :             check_if_empty( substream );
     653              :         }
     654              :         else
     655              :         {
     656          716 :             deserialize_value( stream, value, tag );
     657              :         }
     658              :     }
     659          745 : }
     660              : 
     661            8 : static inline void deserialize( istream & stream, spb::detail::proto_message auto & value,
     662              :                                 wire_type type )
     663              : {
     664            8 :     check_wire_type( type, wire_type::length_delimited );
     665              : 
     666           19 :     while( !stream.empty( ) )
     667              :     {
     668           15 :         const auto tag        = read_varint< uint32_t >( stream );
     669           14 :         const auto field_type = wire_type_from_tag( tag );
     670              : 
     671           14 :         if( field_type == wire_type::length_delimited )
     672              :         {
     673            8 :             const auto size = read_varint< uint32_t >( stream );
     674            8 :             auto substream  = stream.sub_stream( size );
     675            7 :             deserialize_value( substream, value, tag );
     676            7 :             check_if_empty( substream );
     677              :         }
     678              :         else
     679              :         {
     680            6 :             deserialize_value( stream, value, tag );
     681              :         }
     682              :     }
     683            4 : }
     684              : 
     685          129 : inline void istream::deserialize( auto & value, uint32_t tag )
     686              : {
     687          129 :     detail::deserialize( *this, value, wire_type_from_tag( tag ) );
     688           86 : }
     689              : 
     690           83 : inline void istream::read_skip( size_t size )
     691              : {
     692              :     uint8_t buffer[ 64 ];
     693          151 :     while( size > 0 )
     694              :     {
     695           83 :         auto chunk_size = std::min( size, sizeof( buffer ) );
     696           83 :         read_exact( buffer, chunk_size );
     697           68 :         size -= chunk_size;
     698              :     }
     699           68 : }
     700              : 
     701          128 : inline void istream::skip( uint32_t tag )
     702              : {
     703          128 :     switch( wire_type_from_tag( tag ) )
     704              :     {
     705           44 :     case wire_type::varint:
     706           44 :         return ( void ) read_varint< uint64_t >( *this );
     707           44 :     case wire_type::length_delimited:
     708           44 :         return read_skip( size( ) );
     709           20 :     case wire_type::fixed32:
     710           20 :         return read_skip( sizeof( uint32_t ) );
     711           19 :     case wire_type::fixed64:
     712           19 :         return read_skip( sizeof( uint64_t ) );
     713            1 :     default:
     714            1 :         throw std::runtime_error( "invalid wire type" );
     715              :     }
     716              : }
     717              : 
     718              : template < scalar_encoder encoder >
     719          482 : inline void istream::deserialize_as( auto & value, uint32_t tag )
     720              : {
     721          482 :     detail::deserialize_as< encoder >( *this, value, wire_type_from_tag( tag ) );
     722          364 : }
     723              : 
     724              : template < size_t ordinal, typename T >
     725            6 : inline void istream::deserialize_variant( T & variant, uint32_t tag )
     726              : {
     727            6 :     detail::deserialize_variant< ordinal >( *this, variant, wire_type_from_tag( tag ) );
     728            6 : }
     729              : 
     730              : template < size_t ordinal, scalar_encoder encoder, typename T >
     731            2 : inline void istream::deserialize_variant_as( T & variant, uint32_t tag )
     732              : {
     733            2 :     detail::deserialize_variant_as< ordinal, encoder >( *this, variant, wire_type_from_tag( tag ) );
     734            2 : }
     735              : 
     736              : template < scalar_encoder encoder, typename T >
     737          252 : inline auto istream::deserialize_bitfield_as( uint32_t bits, uint32_t tag ) -> T
     738              : {
     739          252 :     return detail::deserialize_bitfield_as< encoder, T >( *this, bits, wire_type_from_tag( tag ) );
     740              : }
     741              : 
     742              : static inline void deserialize( auto & value, spb::io::reader on_read )
     743              : {
     744              :     using T = std::remove_cvref_t< decltype( value ) >;
     745              :     static_assert( spb::detail::proto_message< T > );
     746              : 
     747              :     auto stream = istream( on_read );
     748              :     deserialize_main( stream, value );
     749              : }
     750              : 
     751              : }// namespace spb::pb::detail
        

Generated by: LCOV version 2.0-1