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 % 468 462 6
Test Date: 2026-05-10 21:35:50 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         2179054 : value::
      81                 : ~value() noexcept
      82                 : {
      83         2179054 :     switch(kind())
      84                 :     {
      85         2113086 :     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         2113086 :         sca_.~scalar();
      91         2113086 :         break;
      92                 : 
      93           27491 :     case json::kind::string:
      94           27491 :         str_.~string();
      95           27491 :         break;
      96                 : 
      97            3151 :     case json::kind::array:
      98            3151 :         arr_.~array();
      99            3151 :         break;
     100                 : 
     101           35326 :     case json::kind::object:
     102           35326 :         obj_.~object();
     103           35326 :         break;
     104                 :     }
     105         2179054 : }
     106                 : 
     107            9741 : value::
     108                 : value(
     109                 :     value const& other,
     110            9741 :     storage_ptr sp)
     111                 : {
     112            9741 :     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            7084 :     case json::kind::int64:
     126           21252 :         ::new(&sca_) scalar(
     127            7084 :             other.sca_.i,
     128            7084 :             std::move(sp));
     129            7084 :         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             205 :     case json::kind::string:
     144              17 :         ::new(&str_) string(
     145             205 :             other.str_,
     146             239 :             std::move(sp));
     147             188 :         break;
     148                 : 
     149             155 :     case json::kind::array:
     150              26 :         ::new(&arr_) array(
     151             155 :             other.arr_,
     152             207 :             std::move(sp));
     153             129 :         break;
     154                 : 
     155              95 :     case json::kind::object:
     156              10 :         ::new(&obj_) object(
     157              95 :             other.obj_,
     158             115 :             std::move(sp));
     159              85 :         break;
     160                 :     }
     161            9688 : }
     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              99 : value::
     638                 : emplace_string() noexcept
     639                 : {
     640              99 :     storage_ptr sp = destroy();
     641              99 :     return *::new(&str_) string(sp);
     642              99 : }
     643                 : 
     644                 : array&
     645             250 : value::
     646                 : emplace_array() noexcept
     647                 : {
     648             250 :     storage_ptr sp = destroy();
     649             250 :     return *::new(&arr_) array(sp);
     650             250 : }
     651                 : 
     652                 : object&
     653              56 : value::
     654                 : emplace_object() noexcept
     655                 : {
     656              56 :     storage_ptr sp = destroy();
     657              56 :     return *::new(&obj_) object(sp);
     658              56 : }
     659                 : 
     660                 : void
     661             259 : value::
     662                 : swap(value& other)
     663                 : {
     664             259 :     if(*storage() == *other.storage())
     665                 :     {
     666                 :         // fast path
     667                 :         union U
     668                 :         {
     669                 :             value tmp;
     670             258 :             U(){}
     671             258 :             ~U(){}
     672                 :         };
     673             258 :         U u;
     674             258 :         relocate(&u.tmp, *this);
     675             258 :         relocate(this, other);
     676             258 :         relocate(&other, u.tmp);
     677             258 :         return;
     678             258 :     }
     679                 : 
     680                 :     // copy
     681                 :     value temp1(
     682               1 :         std::move(*this),
     683               2 :         other.storage());
     684                 :     value temp2(
     685               1 :         std::move(other),
     686               2 :         this->storage());
     687               1 :     other.~value();
     688               1 :     ::new(&other) value(pilfer(temp1));
     689               1 :     this->~value();
     690               1 :     ::new(this) value(pilfer(temp2));
     691               1 : }
     692                 : 
     693                 : std::istream&
     694              10 : operator>>(
     695                 :     std::istream& is,
     696                 :     value& jv)
     697                 : {
     698                 :     using Traits = std::istream::traits_type;
     699                 : 
     700                 :     // sentry prepares the stream for reading and finalizes it in destructor
     701              10 :     std::istream::sentry sentry(is);
     702              10 :     if( !sentry )
     703               1 :         return is;
     704                 : 
     705               9 :     parse_options opts = get_parse_options( is );
     706               9 :     if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
     707               3 :         opts.max_depth = depth;
     708                 : 
     709                 :     unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
     710               9 :     stream_parser p( {}, opts, parser_buf );
     711               9 :     p.reset( jv.storage() );
     712                 : 
     713                 :     char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
     714               9 :     std::streambuf& buf = *is.rdbuf();
     715               9 :     std::ios::iostate err = std::ios::goodbit;
     716                 : #ifndef BOOST_NO_EXCEPTIONS
     717                 :     try
     718                 : #endif
     719                 :     {
     720                 :         while( true )
     721                 :         {
     722              15 :             system::error_code ec;
     723                 : 
     724                 :             // we peek the buffer; this either makes sure that there's no
     725                 :             // more input, or makes sure there's something in the internal
     726                 :             // buffer (so in_avail will return a positive number)
     727              15 :             std::istream::int_type c = is.rdbuf()->sgetc();
     728                 :             // if we indeed reached EOF, we check if we parsed a full JSON
     729                 :             // document; if not, we error out
     730              13 :             if( Traits::eq_int_type(c, Traits::eof()) )
     731                 :             {
     732               3 :                 err |= std::ios::eofbit;
     733               3 :                 p.finish(ec);
     734               3 :                 if( ec.failed() )
     735               4 :                     break;
     736                 :             }
     737                 : 
     738                 :             // regardless of reaching EOF, we might have parsed a full JSON
     739                 :             // document; if so, we successfully finish
     740              12 :             if( p.done() )
     741                 :             {
     742               3 :                 jv = p.release();
     743               3 :                 return is;
     744                 :             }
     745                 : 
     746                 :             // at this point we definitely have more input, specifically in
     747                 :             // buf's internal buffer; we also definitely haven't parsed a whole
     748                 :             // document
     749               9 :             std::streamsize available = buf.in_avail();
     750                 :             // if this assert fails, the streambuf is buggy
     751               9 :             BOOST_ASSERT( available > 0 );
     752                 : 
     753              18 :             available = ( std::min )(
     754               9 :                 static_cast<std::size_t>(available), sizeof(read_buf) );
     755                 :             // we read from the internal buffer of buf into our buffer
     756               9 :             available = buf.sgetn( read_buf, available );
     757                 : 
     758               9 :             std::size_t consumed = p.write_some(
     759                 :                 read_buf, static_cast<std::size_t>(available), ec );
     760                 :             // if the parser hasn't consumed the entire input we've took from
     761                 :             // buf, we put the remaining data back; this should succeed,
     762                 :             // because we only read data from buf's internal buffer
     763              21 :             while( consumed++ < static_cast<std::size_t>(available) )
     764                 :             {
     765              12 :                 std::istream::int_type const status = buf.sungetc();
     766              12 :                 BOOST_ASSERT( status != Traits::eof() );
     767                 :                 (void)status;
     768                 :             }
     769                 : 
     770               9 :             if( ec.failed() )
     771               3 :                 break;
     772               6 :         }
     773                 :     }
     774                 : #ifndef BOOST_NO_EXCEPTIONS
     775               2 :     catch(...)
     776                 :     {
     777                 :         try
     778                 :         {
     779               2 :             is.setstate(std::ios::badbit);
     780                 :         }
     781                 :         // we ignore the exception, because we need to throw the original
     782                 :         // exception instead
     783               1 :         catch( std::ios::failure const& ) { }
     784                 : 
     785               2 :         if( is.exceptions() & std::ios::badbit )
     786               1 :             throw;
     787               2 :     }
     788                 : #endif
     789                 : 
     790               5 :     is.setstate(err | std::ios::failbit);
     791               5 :     return is;
     792               9 : }
     793                 : 
     794                 : std::istream&
     795               3 : operator>>(
     796                 :     std::istream& is,
     797                 :     parse_options const& opts)
     798                 : {
     799               3 :     is.iword(parse_flags_xalloc) = to_bitmask(opts);
     800               3 :     is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
     801               3 :     return is;
     802                 : }
     803                 : 
     804                 : //----------------------------------------------------------
     805                 : //
     806                 : // private
     807                 : //
     808                 : //----------------------------------------------------------
     809                 : 
     810                 : storage_ptr
     811             423 : value::
     812                 : destroy() noexcept
     813                 : {
     814             423 :     switch(kind())
     815                 :     {
     816             404 :     case json::kind::null:
     817                 :     case json::kind::bool_:
     818                 :     case json::kind::int64:
     819                 :     case json::kind::uint64:
     820                 :     case json::kind::double_:
     821             404 :         break;
     822                 : 
     823              14 :     case json::kind::string:
     824                 :     {
     825              14 :         auto sp = str_.storage();
     826              14 :         str_.~string();
     827              14 :         return sp;
     828              14 :     }
     829                 : 
     830               2 :     case json::kind::array:
     831                 :     {
     832               2 :         auto sp = arr_.storage();
     833               2 :         arr_.~array();
     834               2 :         return sp;
     835               2 :     }
     836                 : 
     837               3 :     case json::kind::object:
     838                 :     {
     839               3 :         auto sp = obj_.storage();
     840               3 :         obj_.~object();
     841               3 :         return sp;
     842               3 :     }
     843                 : 
     844                 :     }
     845             404 :     return std::move(sp_);
     846                 : }
     847                 : 
     848                 : bool
     849            4276 : value::
     850                 : equal(value const& other) const noexcept
     851                 : {
     852            4276 :     switch(kind())
     853                 :     {
     854              21 :     default: // unreachable()?
     855                 :     case json::kind::null:
     856              21 :         return other.kind() == json::kind::null;
     857                 : 
     858              17 :     case json::kind::bool_:
     859                 :         return
     860              27 :             other.kind() == json::kind::bool_ &&
     861              27 :             get_bool() == other.get_bool();
     862                 : 
     863            3967 :     case json::kind::int64:
     864            3967 :         switch(other.kind())
     865                 :         {
     866            3940 :         case json::kind::int64:
     867            3940 :             return get_int64() == other.get_int64();
     868              26 :         case json::kind::uint64:
     869              26 :             if(get_int64() < 0)
     870               1 :                 return false;
     871              25 :             return static_cast<std::uint64_t>(
     872              25 :                 get_int64()) == other.get_uint64();
     873               1 :         default:
     874               1 :             return false;
     875                 :         }
     876                 : 
     877               7 :     case json::kind::uint64:
     878               7 :         switch(other.kind())
     879                 :         {
     880               2 :         case json::kind::uint64:
     881               2 :             return get_uint64() == other.get_uint64();
     882               3 :         case json::kind::int64:
     883               3 :             if(other.get_int64() < 0)
     884               2 :                 return false;
     885               1 :             return static_cast<std::uint64_t>(
     886               1 :                 other.get_int64()) == get_uint64();
     887               2 :         default:
     888               2 :             return false;
     889                 :         }
     890                 : 
     891              55 :     case json::kind::double_:
     892                 :         return
     893             108 :             other.kind() == json::kind::double_ &&
     894             108 :             get_double() == other.get_double();
     895                 : 
     896              70 :     case json::kind::string:
     897                 :         return
     898             137 :             other.kind() == json::kind::string &&
     899             137 :             get_string() == other.get_string();
     900                 : 
     901              82 :     case json::kind::array:
     902                 :         return
     903             162 :             other.kind() == json::kind::array &&
     904             162 :             get_array() == other.get_array();
     905                 : 
     906              57 :     case json::kind::object:
     907                 :         return
     908             111 :             other.kind() == json::kind::object &&
     909             111 :             get_object() == other.get_object();
     910                 :     }
     911                 : }
     912                 : 
     913                 : //----------------------------------------------------------
     914                 : //
     915                 : // key_value_pair
     916                 : //
     917                 : //----------------------------------------------------------
     918                 : 
     919                 : // empty keys point here
     920                 : BOOST_JSON_REQUIRE_CONST_INIT
     921                 : char const
     922                 : key_value_pair::empty_[1] = { 0 };
     923                 : 
     924           38261 : key_value_pair::
     925                 : key_value_pair(
     926                 :     pilfered<json::value> key,
     927           38261 :     pilfered<json::value> value) noexcept
     928           38261 :     : value_(value)
     929                 : {
     930                 :     std::size_t len;
     931           38261 :     key_ = access::release_key(key.get(), len);
     932           38261 :     len_ = static_cast<std::uint32_t>(len);
     933           38261 : }
     934                 : 
     935            7054 : key_value_pair::
     936                 : key_value_pair(
     937                 :     key_value_pair const& other,
     938            7054 :     storage_ptr sp)
     939            7058 :     : value_(other.value_, std::move(sp))
     940                 : {
     941                 :     auto p = reinterpret_cast<
     942            7050 :         char*>(value_.storage()->
     943            7050 :             allocate(other.len_ + 1,
     944                 :                 alignof(char)));
     945            6792 :     std::memcpy(
     946            6792 :         p, other.key_, other.len_);
     947            6792 :     len_ = other.len_;
     948            6792 :     p[len_] = 0;
     949            6792 :     key_ = p;
     950            7050 : }
     951                 : 
     952                 : //----------------------------------------------------------
     953                 : 
     954                 : namespace detail
     955                 : {
     956                 : 
     957                 : std::size_t
     958             248 : hash_value_impl( value const& jv ) noexcept
     959                 : {
     960             248 :     std::size_t seed = 0;
     961                 : 
     962             248 :     kind const k = jv.kind();
     963             248 :     boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
     964                 : 
     965             248 :     visit( value_hasher{seed}, jv );
     966             248 :     return seed;
     967                 : }
     968                 : 
     969                 : } // namespace detail
     970                 : } // namespace json
     971                 : } // namespace boost
     972                 : 
     973                 : //----------------------------------------------------------
     974                 : //
     975                 : // std::hash specialization
     976                 : //
     977                 : //----------------------------------------------------------
     978                 : 
     979                 : std::size_t
     980              62 : std::hash<::boost::json::value>::operator()(
     981                 :     ::boost::json::value const& jv) const noexcept
     982                 : {
     983              62 :     return ::boost::hash< ::boost::json::value >()( jv );
     984                 : }
     985                 : 
     986                 : //----------------------------------------------------------
     987                 : 
     988                 : #endif
        

Generated by: LCOV version 2.3