LCOV - code coverage report
Current view: top level - json/impl - value.ipp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 98.7 % 462 456
Test Date: 2025-12-23 17:21:58 Functions: 100.0 % 70 70

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

Generated by: LCOV version 2.1