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

Generated by: LCOV version 2.3