LCOV - code coverage report
Current view: top level - spb/pb - deserialize.hpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 85.7 % 294 252
Test Date: 2026-03-06 17:56:28 Functions: 28.2 % 1464 413

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

Generated by: LCOV version 2.0-1