LCOV - code coverage report
Current view: top level - json/impl - value.ipp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 98.5 % 466 459 7
Test Date: 2026-08-08 11:31:37 Functions: 100.0 % 70 70

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : //
       4                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6                 : //
       7                 : // Official repository: https://github.com/boostorg/json
       8                 : //
       9                 : 
      10                 : #ifndef BOOST_JSON_IMPL_VALUE_IPP
      11                 : #define BOOST_JSON_IMPL_VALUE_IPP
      12                 : 
      13                 : #include <boost/container_hash/hash.hpp>
      14                 : #include <boost/json/value.hpp>
      15                 : #include <boost/json/parser.hpp>
      16                 : #include <cstring>
      17                 : #include <istream>
      18                 : #include <limits>
      19                 : #include <new>
      20                 : #include <utility>
      21                 : 
      22                 : namespace boost {
      23                 : namespace json {
      24                 : 
      25                 : namespace
      26                 : {
      27                 : 
      28                 : int parse_depth_xalloc = std::ios::xalloc();
      29                 : int parse_flags_xalloc = std::ios::xalloc();
      30                 : 
      31                 : struct value_hasher
      32                 : {
      33                 :     std::size_t& seed;
      34                 : 
      35                 :     template< class T >
      36 HIT         248 :     void operator()( T&& t ) const noexcept
      37                 :     {
      38             248 :         boost::hash_combine( seed, t );
      39             248 :     }
      40                 : };
      41                 : 
      42                 : enum class stream_parse_flags
      43                 : {
      44                 :     allow_comments = 1 << 0,
      45                 :     allow_trailing_commas = 1 << 1,
      46                 :     allow_invalid_utf8 = 1 << 2,
      47                 : };
      48                 : 
      49                 : long
      50               3 : to_bitmask( parse_options const& opts )
      51                 : {
      52                 :     using E = stream_parse_flags;
      53                 :     return
      54               3 :         (opts.allow_comments ?
      55               3 :             static_cast<long>(E::allow_comments) : 0) |
      56               3 :         (opts.allow_trailing_commas ?
      57                 :             static_cast<long>(E::allow_trailing_commas) : 0) |
      58               3 :         (opts.allow_invalid_utf8 ?
      59               3 :             static_cast<long>(E::allow_invalid_utf8) : 0);
      60                 : }
      61                 : 
      62                 : parse_options
      63               9 : get_parse_options( std::istream& is )
      64                 : {
      65               9 :     long const flags = is.iword(parse_flags_xalloc);
      66                 : 
      67                 :     using E = stream_parse_flags;
      68               9 :     parse_options opts;
      69               9 :     opts.allow_comments =
      70               9 :         flags & static_cast<long>(E::allow_comments) ? true : false;
      71               9 :     opts.allow_trailing_commas =
      72               9 :         flags & static_cast<long>(E::allow_trailing_commas) ? true : false;
      73               9 :     opts.allow_invalid_utf8 =
      74               9 :         flags & static_cast<long>(E::allow_invalid_utf8) ? true : false;
      75               9 :     return opts;
      76                 : }
      77                 : 
      78                 : } // namespace
      79                 : 
      80         2178819 : value::
      81                 : ~value() noexcept
      82                 : {
      83         2178819 :     switch(kind())
      84                 :     {
      85         2113113 :     case json::kind::null:
      86                 :     case json::kind::bool_:
      87                 :     case json::kind::int64:
      88                 :     case json::kind::uint64:
      89                 :     case json::kind::double_:
      90         2113113 :         sca_.~scalar();
      91         2113113 :         break;
      92                 : 
      93           27394 :     case json::kind::string:
      94           27394 :         str_.~string();
      95           27394 :         break;
      96                 : 
      97            3107 :     case json::kind::array:
      98            3107 :         arr_.~array();
      99            3107 :         break;
     100                 : 
     101           35205 :     case json::kind::object:
     102           35205 :         obj_.~object();
     103           35205 :         break;
     104                 :     }
     105         2178819 : }
     106                 : 
     107            9587 : value::
     108                 : value(
     109                 :     value const& other,
     110            9587 :     storage_ptr sp)
     111                 : {
     112            9587 :     switch(other.kind())
     113                 :     {
     114            2037 :     case json::kind::null:
     115            6111 :         ::new(&sca_) scalar(
     116            2037 :             std::move(sp));
     117            2037 :         break;
     118                 : 
     119             136 :     case json::kind::bool_:
     120             408 :         ::new(&sca_) scalar(
     121             136 :             other.sca_.b,
     122             136 :             std::move(sp));
     123             136 :         break;
     124                 : 
     125            7052 :     case json::kind::int64:
     126           21156 :         ::new(&sca_) scalar(
     127            7052 :             other.sca_.i,
     128            7052 :             std::move(sp));
     129            7052 :         break;
     130                 : 
     131              35 :     case json::kind::uint64:
     132             105 :         ::new(&sca_) scalar(
     133              35 :             other.sca_.u,
     134              35 :             std::move(sp));
     135              35 :         break;
     136                 : 
     137              12 :     case json::kind::double_:
     138              36 :         ::new(&sca_) scalar(
     139              12 :             other.sca_.d,
     140              12 :             std::move(sp));
     141              12 :         break;
     142                 : 
     143             143 :     case json::kind::string:
     144              18 :         ::new(&str_) string(
     145             143 :             other.str_,
     146             179 :             std::move(sp));
     147             125 :         break;
     148                 : 
     149             142 :     case json::kind::array:
     150              29 :         ::new(&arr_) array(
     151             142 :             other.arr_,
     152             200 :             std::move(sp));
     153             113 :         break;
     154                 : 
     155              30 :     case json::kind::object:
     156              10 :         ::new(&obj_) object(
     157              30 :             other.obj_,
     158              50 :             std::move(sp));
     159              20 :         break;
     160                 :     }
     161            9530 : }
     162                 : 
     163            3784 : value::
     164            3784 : value(value&& other) noexcept
     165                 : {
     166            3784 :     relocate(this, other);
     167            3784 :     ::new(&other.sca_) scalar(sp_);
     168            3784 : }
     169                 : 
     170           11501 : value::
     171                 : value(
     172                 :     value&& other,
     173           11501 :     storage_ptr sp)
     174                 : {
     175           11501 :     switch(other.kind())
     176                 :     {
     177              77 :     case json::kind::null:
     178             229 :         ::new(&sca_) scalar(
     179              77 :             std::move(sp));
     180              77 :         break;
     181                 : 
     182             193 :     case json::kind::bool_:
     183             579 :         ::new(&sca_) scalar(
     184             193 :             other.sca_.b, std::move(sp));
     185             193 :         break;
     186                 : 
     187           10494 :     case json::kind::int64:
     188           31482 :         ::new(&sca_) scalar(
     189           10494 :             other.sca_.i, std::move(sp));
     190           10494 :         break;
     191                 : 
     192              75 :     case json::kind::uint64:
     193             225 :         ::new(&sca_) scalar(
     194              75 :             other.sca_.u, std::move(sp));
     195              75 :         break;
     196                 : 
     197              34 :     case json::kind::double_:
     198             102 :         ::new(&sca_) scalar(
     199              34 :             other.sca_.d, std::move(sp));
     200              34 :         break;
     201                 : 
     202             340 :     case json::kind::string:
     203               6 :         ::new(&str_) string(
     204             340 :             std::move(other.str_),
     205             692 :             std::move(sp));
     206             334 :         break;
     207                 : 
     208             224 :     case json::kind::array:
     209               5 :         ::new(&arr_) array(
     210             224 :             std::move(other.arr_),
     211             458 :             std::move(sp));
     212             219 :         break;
     213                 : 
     214              64 :     case json::kind::object:
     215              13 :         ::new(&obj_) object(
     216              64 :             std::move(other.obj_),
     217             154 :             std::move(sp));
     218              51 :         break;
     219                 :     }
     220           11477 : }
     221                 : 
     222                 : //----------------------------------------------------------
     223                 : //
     224                 : // Conversion
     225                 : //
     226                 : //----------------------------------------------------------
     227                 : 
     228             338 : value::
     229                 : value(
     230                 :     std::initializer_list<value_ref> init,
     231             338 :     storage_ptr sp)
     232                 : {
     233             338 :     if(value_ref::maybe_object(init))
     234                 :     {
     235 MIS           0 :         ::new(&obj_) object(
     236                 :             value_ref::make_object(
     237 HIT         103 :                 init, std::move(sp)));
     238                 :     }
     239                 :     else
     240                 :     {
     241             235 :         if( init.size() == 1 )
     242                 :         {
     243 MIS           0 :             ::new(this) value(
     244 HIT          14 :                 init.begin()->make_value( std::move(sp) ));
     245                 :         }
     246                 :         else
     247                 :         {
     248 MIS           0 :             ::new(&arr_) array(
     249                 :                 value_ref::make_array(
     250 HIT         221 :                     init, std::move(sp)));
     251                 :         }
     252                 :     }
     253             338 : }
     254                 : 
     255                 : //----------------------------------------------------------
     256                 : //
     257                 : // Assignment
     258                 : //
     259                 : //----------------------------------------------------------
     260                 : 
     261                 : value&
     262              38 : value::
     263                 : operator=(value const& other)
     264                 : {
     265              76 :     value(other,
     266              32 :         storage()).swap(*this);
     267              32 :     return *this;
     268                 : }
     269                 : 
     270                 : value&
     271              82 : value::
     272                 : operator=(value&& other)
     273                 : {
     274             164 :     value(std::move(other),
     275              63 :         storage()).swap(*this);
     276              63 :     return *this;
     277                 : }
     278                 : 
     279                 : value&
     280              13 : value::
     281                 : operator=(
     282                 :     std::initializer_list<value_ref> init)
     283                 : {
     284              26 :     value(init,
     285              13 :         storage()).swap(*this);
     286              13 :     return *this;
     287                 : }
     288                 : 
     289                 : value&
     290               2 : value::
     291                 : operator=(string_view s)
     292                 : {
     293               2 :     value(s, storage()).swap(*this);
     294               2 :     return *this;
     295                 : }
     296                 : 
     297                 : value&
     298              28 : value::
     299                 : operator=(char const* s)
     300                 : {
     301              28 :     value(s, storage()).swap(*this);
     302              28 :     return *this;
     303                 : }
     304                 : 
     305                 : value&
     306              12 : value::
     307                 : operator=(string const& str)
     308                 : {
     309              12 :     value(str, storage()).swap(*this);
     310              12 :     return *this;
     311                 : }
     312                 : 
     313                 : value&
     314               7 : value::
     315                 : operator=(string&& str)
     316                 : {
     317              14 :     value(std::move(str),
     318               7 :         storage()).swap(*this);
     319               7 :     return *this;
     320                 : }
     321                 : 
     322                 : value&
     323               4 : value::
     324                 : operator=(array const& arr)
     325                 : {
     326               4 :     value(arr, storage()).swap(*this);
     327               4 :     return *this;
     328                 : }
     329                 : 
     330                 : value&
     331              21 : value::
     332                 : operator=(array&& arr)
     333                 : {
     334              42 :     value(std::move(arr),
     335              21 :         storage()).swap(*this);
     336              21 :     return *this;
     337                 : }
     338                 : 
     339                 : value&
     340               4 : value::
     341                 : operator=(object const& obj)
     342                 : {
     343               4 :     value(obj, storage()).swap(*this);
     344               4 :     return *this;
     345                 : }
     346                 : 
     347                 : value&
     348              54 : value::
     349                 : operator=(object&& obj)
     350                 : {
     351             108 :     value(std::move(obj),
     352              54 :         storage()).swap(*this);
     353              54 :     return *this;
     354                 : }
     355                 : 
     356                 : //----------------------------------------------------------
     357                 : //
     358                 : // Accessors
     359                 : //
     360                 : //----------------------------------------------------------
     361                 : 
     362                 : system::result<array&>
     363              16 : value::try_as_array() noexcept
     364                 : {
     365              16 :     if( is_array() )
     366               9 :         return arr_;
     367                 : 
     368               7 :     system::error_code ec;
     369               7 :     BOOST_JSON_FAIL(ec, error::not_array);
     370               7 :     return ec;
     371                 : }
     372                 : 
     373                 : system::result<array const&>
     374             186 : value::try_as_array() const noexcept
     375                 : {
     376             186 :     if( is_array() )
     377             158 :         return arr_;
     378                 : 
     379              28 :     system::error_code ec;
     380              28 :     BOOST_JSON_FAIL(ec, error::not_array);
     381              28 :     return ec;
     382                 : }
     383                 : 
     384                 : system::result<object&>
     385               9 : value::try_as_object() noexcept
     386                 : {
     387               9 :     if( is_object() )
     388               2 :         return obj_;
     389                 : 
     390               7 :     system::error_code ec;
     391               7 :     BOOST_JSON_FAIL(ec, error::not_object);
     392               7 :     return ec;
     393                 : }
     394                 : 
     395                 : system::result<object const&>
     396             208 : value::try_as_object() const noexcept
     397                 : {
     398             208 :     if( is_object() )
     399             180 :         return obj_;
     400                 : 
     401              28 :     system::error_code ec;
     402              28 :     BOOST_JSON_FAIL(ec, error::not_object);
     403              28 :     return ec;
     404                 : }
     405                 : 
     406                 : system::result<string&>
     407               9 : value::try_as_string() noexcept
     408                 : {
     409               9 :     if( is_string() )
     410               2 :         return str_;
     411                 : 
     412               7 :     system::error_code ec;
     413               7 :     BOOST_JSON_FAIL(ec, error::not_string);
     414               7 :     return ec;
     415                 : }
     416                 : 
     417                 : system::result<string const&>
     418             123 : value::try_as_string() const noexcept
     419                 : {
     420             123 :     if( is_string() )
     421              94 :         return str_;
     422                 : 
     423              29 :     system::error_code ec;
     424              29 :     BOOST_JSON_FAIL(ec, error::not_string);
     425              29 :     return ec;
     426                 : }
     427                 : 
     428                 : system::result<std::int64_t&>
     429              69 : value::try_as_int64() noexcept
     430                 : {
     431              69 :     if( is_int64() )
     432              55 :         return sca_.i;
     433                 : 
     434              14 :     system::error_code ec;
     435              14 :     BOOST_JSON_FAIL(ec, error::not_int64);
     436              14 :     return ec;
     437                 : }
     438                 : 
     439                 : system::result<std::int64_t>
     440              33 : value::try_as_int64() const noexcept
     441                 : {
     442              33 :     if( is_int64() )
     443              19 :         return sca_.i;
     444                 : 
     445              14 :     system::error_code ec;
     446              14 :     BOOST_JSON_FAIL(ec, error::not_int64);
     447              14 :     return ec;
     448                 : }
     449                 : 
     450                 : system::result<std::uint64_t&>
     451              16 : value::try_as_uint64() noexcept
     452                 : {
     453              16 :     if( is_uint64() )
     454               2 :         return sca_.u;
     455                 : 
     456              14 :     system::error_code ec;
     457              14 :     BOOST_JSON_FAIL(ec, error::not_uint64);
     458              14 :     return ec;
     459                 : }
     460                 : 
     461                 : system::result<std::uint64_t>
     462              16 : value::try_as_uint64() const noexcept
     463                 : {
     464              16 :     if( is_uint64() )
     465               2 :         return sca_.u;
     466                 : 
     467              14 :     system::error_code ec;
     468              14 :     BOOST_JSON_FAIL(ec, error::not_uint64);
     469              14 :     return ec;
     470                 : }
     471                 : 
     472                 : system::result<double&>
     473         2000657 : value::try_as_double() noexcept
     474                 : {
     475         2000657 :     if( is_double() )
     476         2000643 :         return sca_.d;
     477                 : 
     478              14 :     system::error_code ec;
     479              14 :     BOOST_JSON_FAIL(ec, error::not_double);
     480              14 :     return ec;
     481                 : }
     482                 : 
     483                 : system::result<double>
     484             580 : value::try_as_double() const noexcept
     485                 : {
     486             580 :     if( is_double() )
     487             566 :         return sca_.d;
     488                 : 
     489              14 :     system::error_code ec;
     490              14 :     BOOST_JSON_FAIL(ec, error::not_double);
     491              14 :     return ec;
     492                 : }
     493                 : 
     494                 : system::result<bool&>
     495              19 : value::try_as_bool() noexcept
     496                 : {
     497              19 :     if( is_bool() )
     498               4 :         return sca_.b;
     499                 : 
     500              15 :     system::error_code ec;
     501              15 :     BOOST_JSON_FAIL(ec, error::not_bool);
     502              15 :     return ec;
     503                 : }
     504                 : 
     505                 : system::result<bool>
     506              30 : value::try_as_bool() const noexcept
     507                 : {
     508              30 :     if( is_bool() )
     509              16 :         return sca_.b;
     510                 : 
     511              14 :     system::error_code ec;
     512              14 :     BOOST_JSON_FAIL(ec, error::not_bool);
     513              14 :     return ec;
     514                 : }
     515                 : 
     516                 : system::result<std::nullptr_t>
     517               2 : value::try_as_null() const noexcept
     518                 : {
     519               2 :     if( is_null() )
     520               1 :         return nullptr;
     521                 : 
     522               1 :     system::error_code ec;
     523               1 :     BOOST_JSON_FAIL(ec, error::not_null);
     524               1 :     return ec;
     525                 : }
     526                 : 
     527                 : boost::system::result<value&>
     528               1 : value::try_at(string_view key) noexcept
     529                 : {
     530               1 :     auto r = try_as_object();
     531               1 :     if( !r )
     532 MIS           0 :         return r.error();
     533 HIT           1 :     return r.unsafe_value().try_at(key);
     534                 : }
     535                 : 
     536                 : boost::system::result<value const&>
     537               3 : value::try_at(string_view key) const noexcept
     538                 : {
     539               3 :     auto r = try_as_object();
     540               3 :     if( !r )
     541 MIS           0 :         return r.error();
     542 HIT           3 :     return r.unsafe_value().try_at(key);
     543                 : }
     544                 : 
     545                 : boost::system::result<value&>
     546               8 : value::try_at(std::size_t pos) noexcept
     547                 : {
     548               8 :     auto r = try_as_array();
     549               8 :     if( !r )
     550 MIS           0 :         return r.error();
     551 HIT           8 :     return r.unsafe_value().try_at(pos);
     552                 : }
     553                 : 
     554                 : boost::system::result<value const&>
     555               2 : value::try_at(std::size_t pos) const noexcept
     556                 : {
     557               2 :     auto r = try_as_array();
     558               2 :     if( !r )
     559 MIS           0 :         return r.error();
     560 HIT           2 :     return r.unsafe_value().try_at(pos);
     561                 : }
     562                 : 
     563                 : object const&
     564             197 : value::as_object(source_location const& loc) const&
     565                 : {
     566             197 :     return try_as_object().value(loc);
     567                 : }
     568                 : 
     569                 : array const&
     570             176 : value::as_array(source_location const& loc) const&
     571                 : {
     572             176 :     return try_as_array().value(loc);
     573                 : }
     574                 : 
     575                 : string const&
     576             115 : value::as_string(source_location const& loc) const&
     577                 : {
     578             115 :     return try_as_string().value(loc);
     579                 : }
     580                 : 
     581                 : std::int64_t&
     582              61 : value::as_int64(source_location const& loc)
     583                 : {
     584              61 :     return try_as_int64().value(loc);
     585                 : }
     586                 : 
     587                 : std::int64_t
     588              26 : value::as_int64(source_location const& loc) const
     589                 : {
     590              26 :     return try_as_int64().value(loc);
     591                 : }
     592                 : 
     593                 : std::uint64_t&
     594               8 : value::as_uint64(source_location const& loc)
     595                 : {
     596               8 :     return try_as_uint64().value(loc);
     597                 : }
     598                 : 
     599                 : std::uint64_t
     600               8 : value::as_uint64(source_location const& loc) const
     601                 : {
     602               8 :     return try_as_uint64().value(loc);
     603                 : }
     604                 : 
     605                 : double&
     606         2000649 : value::as_double(source_location const& loc)
     607                 : {
     608         2000649 :     return try_as_double().value(loc);
     609                 : }
     610                 : 
     611                 : double
     612             572 : value::as_double(source_location const& loc) const
     613                 : {
     614             572 :     return try_as_double().value(loc);
     615                 : }
     616                 : 
     617                 : bool&
     618              10 : value::as_bool(source_location const& loc)
     619                 : {
     620              10 :     return try_as_bool().value(loc);
     621                 : }
     622                 : 
     623                 : bool
     624              22 : value::as_bool(source_location const& loc) const
     625                 : {
     626              22 :     return try_as_bool().value(loc);
     627                 : }
     628                 : 
     629                 : //----------------------------------------------------------
     630                 : //
     631                 : // Modifiers
     632                 : //
     633                 : //----------------------------------------------------------
     634                 : 
     635                 : string&
     636              99 : value::
     637                 : emplace_string() noexcept
     638                 : {
     639              99 :     storage_ptr sp = destroy();
     640              99 :     return *::new(&str_) string(sp);
     641              99 : }
     642                 : 
     643                 : array&
     644             250 : value::
     645                 : emplace_array() noexcept
     646                 : {
     647             250 :     storage_ptr sp = destroy();
     648             250 :     return *::new(&arr_) array(sp);
     649             250 : }
     650                 : 
     651                 : object&
     652              56 : value::
     653                 : emplace_object() noexcept
     654                 : {
     655              56 :     storage_ptr sp = destroy();
     656              56 :     return *::new(&obj_) object(sp);
     657              56 : }
     658                 : 
     659                 : void
     660             246 : value::
     661                 : swap(value& other)
     662                 : {
     663             246 :     if(*storage() == *other.storage())
     664                 :     {
     665                 :         // fast path
     666                 :         union U
     667                 :         {
     668                 :             value tmp;
     669             245 :             U(){}
     670             245 :             ~U(){}
     671                 :         };
     672             245 :         U u;
     673             245 :         relocate(&u.tmp, *this);
     674             245 :         relocate(this, other);
     675             245 :         relocate(&other, u.tmp);
     676             245 :         return;
     677             245 :     }
     678                 : 
     679                 :     // copy
     680                 :     value temp1(
     681               1 :         std::move(*this),
     682               2 :         other.storage());
     683                 :     value temp2(
     684               1 :         std::move(other),
     685               2 :         this->storage());
     686               1 :     other.~value();
     687               1 :     ::new(&other) value(pilfer(temp1));
     688               1 :     this->~value();
     689               1 :     ::new(this) value(pilfer(temp2));
     690               1 : }
     691                 : 
     692                 : std::istream&
     693              10 : operator>>(
     694                 :     std::istream& is,
     695                 :     value& jv)
     696                 : {
     697                 :     using Traits = std::istream::traits_type;
     698                 : 
     699                 :     // sentry prepares the stream for reading and finalizes it in destructor
     700              10 :     std::istream::sentry sentry(is);
     701              10 :     if( !sentry )
     702               1 :         return is;
     703                 : 
     704               9 :     parse_options opts = get_parse_options( is );
     705               9 :     if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
     706               3 :         opts.max_depth = depth;
     707                 : 
     708                 :     unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
     709               9 :     stream_parser p( {}, opts, parser_buf );
     710               9 :     p.reset( jv.storage() );
     711                 : 
     712                 :     char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
     713               9 :     std::streambuf& buf = *is.rdbuf();
     714               9 :     std::ios::iostate err = std::ios::goodbit;
     715                 : #ifndef BOOST_NO_EXCEPTIONS
     716                 :     try
     717                 : #endif
     718                 :     {
     719                 :         while( true )
     720                 :         {
     721              15 :             system::error_code ec;
     722                 : 
     723                 :             // we peek the buffer; this either makes sure that there's no
     724                 :             // more input, or makes sure there's something in the internal
     725                 :             // buffer (so in_avail will return a positive number)
     726              15 :             std::istream::int_type c = is.rdbuf()->sgetc();
     727                 :             // if we indeed reached EOF, we check if we parsed a full JSON
     728                 :             // document; if not, we error out
     729              13 :             if( Traits::eq_int_type(c, Traits::eof()) )
     730                 :             {
     731               3 :                 err |= std::ios::eofbit;
     732               3 :                 p.finish(ec);
     733               3 :                 if( ec.failed() )
     734               4 :                     break;
     735                 :             }
     736                 : 
     737                 :             // regardless of reaching EOF, we might have parsed a full JSON
     738                 :             // document; if so, we successfully finish
     739              12 :             if( p.done() )
     740                 :             {
     741               3 :                 jv = p.release();
     742               3 :                 return is;
     743                 :             }
     744                 : 
     745                 :             // at this point we definitely have more input, specifically in
     746                 :             // buf's internal buffer; we also definitely haven't parsed a whole
     747                 :             // document
     748               9 :             std::streamsize available = buf.in_avail();
     749                 :             // if this assert fails, the streambuf is buggy
     750               9 :             BOOST_ASSERT( available > 0 );
     751                 : 
     752              18 :             available = ( std::min )(
     753               9 :                 static_cast<std::size_t>(available), sizeof(read_buf) );
     754                 :             // we read from the internal buffer of buf into our buffer
     755               9 :             available = buf.sgetn( read_buf, available );
     756                 : 
     757               9 :             std::size_t consumed = p.write_some(
     758                 :                 read_buf, static_cast<std::size_t>(available), ec );
     759                 :             // if the parser hasn't consumed the entire input we've took from
     760                 :             // buf, we put the remaining data back; this should succeed,
     761                 :             // because we only read data from buf's internal buffer
     762              21 :             while( consumed++ < static_cast<std::size_t>(available) )
     763                 :             {
     764              12 :                 std::istream::int_type const status = buf.sungetc();
     765              12 :                 BOOST_ASSERT( status != Traits::eof() );
     766                 :                 (void)status;
     767                 :             }
     768                 : 
     769               9 :             if( ec.failed() )
     770               3 :                 break;
     771               6 :         }
     772                 :     }
     773                 : #ifndef BOOST_NO_EXCEPTIONS
     774               2 :     catch(...)
     775                 :     {
     776                 :         try
     777                 :         {
     778               2 :             is.setstate(std::ios::badbit);
     779                 :         }
     780                 :         // we ignore the exception, because we need to throw the original
     781                 :         // exception instead
     782               1 :         catch( std::ios::failure const& ) { }
     783                 : 
     784               2 :         if( is.exceptions() & std::ios::badbit )
     785               1 :             throw;
     786               2 :     }
     787                 : #endif
     788                 : 
     789               5 :     is.setstate(err | std::ios::failbit);
     790               5 :     return is;
     791               9 : }
     792                 : 
     793                 : std::istream&
     794               3 : operator>>(
     795                 :     std::istream& is,
     796                 :     parse_options const& opts)
     797                 : {
     798               3 :     is.iword(parse_flags_xalloc) = to_bitmask(opts);
     799               3 :     is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
     800               3 :     return is;
     801                 : }
     802                 : 
     803                 : //----------------------------------------------------------
     804                 : //
     805                 : // private
     806                 : //
     807                 : //----------------------------------------------------------
     808                 : 
     809                 : storage_ptr
     810             423 : value::
     811                 : destroy() noexcept
     812                 : {
     813             423 :     switch(kind())
     814                 :     {
     815             404 :     case json::kind::null:
     816                 :     case json::kind::bool_:
     817                 :     case json::kind::int64:
     818                 :     case json::kind::uint64:
     819                 :     case json::kind::double_:
     820             404 :         break;
     821                 : 
     822              14 :     case json::kind::string:
     823                 :     {
     824              14 :         auto sp = str_.storage();
     825              14 :         str_.~string();
     826              14 :         return sp;
     827              14 :     }
     828                 : 
     829               2 :     case json::kind::array:
     830                 :     {
     831               2 :         auto sp = arr_.storage();
     832               2 :         arr_.~array();
     833               2 :         return sp;
     834               2 :     }
     835                 : 
     836               3 :     case json::kind::object:
     837                 :     {
     838               3 :         auto sp = obj_.storage();
     839               3 :         obj_.~object();
     840               3 :         return sp;
     841               3 :     }
     842                 : 
     843                 :     }
     844             404 :     return std::move(sp_);
     845                 : }
     846                 : 
     847                 : bool
     848            4172 : value::
     849                 : equal(value const& other) const noexcept
     850                 : {
     851            4172 :     switch(kind())
     852                 :     {
     853              21 :     default: // unreachable()?
     854                 :     case json::kind::null:
     855              21 :         return other.kind() == json::kind::null;
     856                 : 
     857              17 :     case json::kind::bool_:
     858                 :         return
     859              27 :             other.kind() == json::kind::bool_ &&
     860              27 :             get_bool() == other.get_bool();
     861                 : 
     862            3943 :     case json::kind::int64:
     863            3943 :         switch(other.kind())
     864                 :         {
     865            3916 :         case json::kind::int64:
     866            3916 :             return get_int64() == other.get_int64();
     867              26 :         case json::kind::uint64:
     868              26 :             if(get_int64() < 0)
     869               1 :                 return false;
     870              25 :             return static_cast<std::uint64_t>(
     871              25 :                 get_int64()) == other.get_uint64();
     872               1 :         default:
     873               1 :             return false;
     874                 :         }
     875                 : 
     876               7 :     case json::kind::uint64:
     877               7 :         switch(other.kind())
     878                 :         {
     879               2 :         case json::kind::uint64:
     880               2 :             return get_uint64() == other.get_uint64();
     881               3 :         case json::kind::int64:
     882               3 :             if(other.get_int64() < 0)
     883               2 :                 return false;
     884               1 :             return static_cast<std::uint64_t>(
     885               1 :                 other.get_int64()) == get_uint64();
     886               2 :         default:
     887               2 :             return false;
     888                 :         }
     889                 : 
     890              55 :     case json::kind::double_:
     891                 :         return
     892             108 :             other.kind() == json::kind::double_ &&
     893             108 :             get_double() == other.get_double();
     894                 : 
     895              47 :     case json::kind::string:
     896                 :         return
     897              91 :             other.kind() == json::kind::string &&
     898              91 :             get_string() == other.get_string();
     899                 : 
     900              62 :     case json::kind::array:
     901                 :         return
     902             122 :             other.kind() == json::kind::array &&
     903             122 :             get_array() == other.get_array();
     904                 : 
     905              20 :     case json::kind::object:
     906                 :         return
     907              37 :             other.kind() == json::kind::object &&
     908              37 :             get_object() == other.get_object();
     909                 :     }
     910                 : }
     911                 : 
     912                 : //----------------------------------------------------------
     913                 : //
     914                 : // key_value_pair
     915                 : //
     916                 : //----------------------------------------------------------
     917                 : 
     918                 : // empty keys point here
     919                 : BOOST_JSON_REQUIRE_CONST_INIT
     920                 : char const
     921                 : key_value_pair::empty_[1] = { 0 };
     922                 : 
     923           38150 : key_value_pair::
     924                 : key_value_pair(
     925                 :     pilfered<json::value> key,
     926           38150 :     pilfered<json::value> value) noexcept
     927           38150 :     : value_(value)
     928                 : {
     929                 :     std::size_t len;
     930           38150 :     key_ = access::release_key(key.get(), len);
     931           38150 :     len_ = static_cast<std::uint32_t>(len);
     932           38150 : }
     933                 : 
     934            6858 : key_value_pair::
     935                 : key_value_pair(
     936                 :     key_value_pair const& other,
     937            6858 :     storage_ptr sp)
     938            6862 :     : value_(other.value_, std::move(sp))
     939                 : {
     940                 :     auto p = reinterpret_cast<
     941            6854 :         char*>(value_.storage()->
     942            6854 :             allocate(other.len_ + 1,
     943                 :                 alignof(char)));
     944            6596 :     std::memcpy(
     945            6596 :         p, other.key_, other.len_);
     946            6596 :     len_ = other.len_;
     947            6596 :     p[len_] = 0;
     948            6596 :     key_ = p;
     949            6854 : }
     950                 : 
     951                 : //----------------------------------------------------------
     952                 : 
     953                 : namespace detail
     954                 : {
     955                 : 
     956                 : std::size_t
     957             248 : hash_value_impl( value const& jv ) noexcept
     958                 : {
     959             248 :     std::size_t seed = 0;
     960                 : 
     961             248 :     kind const k = jv.kind();
     962             248 :     boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
     963                 : 
     964             248 :     visit( value_hasher{seed}, jv );
     965             248 :     return seed;
     966                 : }
     967                 : 
     968                 : } // namespace detail
     969                 : } // namespace json
     970                 : } // namespace boost
     971                 : 
     972                 : //----------------------------------------------------------
     973                 : //
     974                 : // std::hash specialization
     975                 : //
     976                 : //----------------------------------------------------------
     977                 : 
     978                 : std::size_t
     979              62 : std::hash<::boost::json::value>::operator()(
     980                 :     ::boost::json::value const& jv) const noexcept
     981                 : {
     982              62 :     return ::boost::hash< ::boost::json::value >()( jv );
     983                 : }
     984                 : 
     985                 : //----------------------------------------------------------
     986                 : 
     987                 : #endif
        

Generated by: LCOV version 2.3