Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-11 08:14:24

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/json
0008 //
0009 
0010 #ifndef BOOST_JSON_IMPL_VALUE_IPP
0011 #define BOOST_JSON_IMPL_VALUE_IPP
0012 
0013 #include <boost/container_hash/hash.hpp>
0014 #include <boost/json/value.hpp>
0015 #include <boost/json/parser.hpp>
0016 #include <cstring>
0017 #include <istream>
0018 #include <limits>
0019 #include <new>
0020 #include <utility>
0021 
0022 namespace boost {
0023 namespace json {
0024 
0025 namespace
0026 {
0027 
0028 int parse_depth_xalloc = std::ios::xalloc();
0029 int parse_flags_xalloc = std::ios::xalloc();
0030 
0031 struct value_hasher
0032 {
0033     std::size_t& seed;
0034 
0035     template< class T >
0036     void operator()( T&& t ) const noexcept
0037     {
0038         boost::hash_combine( seed, t );
0039     }
0040 };
0041 
0042 enum class stream_parse_flags
0043 {
0044     allow_comments = 1 << 0,
0045     allow_trailing_commas = 1 << 1,
0046     allow_invalid_utf8 = 1 << 2,
0047 };
0048 
0049 long
0050 to_bitmask( parse_options const& opts )
0051 {
0052     using E = stream_parse_flags;
0053     return
0054         (opts.allow_comments ?
0055             static_cast<long>(E::allow_comments) : 0) |
0056         (opts.allow_trailing_commas ?
0057             static_cast<long>(E::allow_trailing_commas) : 0) |
0058         (opts.allow_invalid_utf8 ?
0059             static_cast<long>(E::allow_invalid_utf8) : 0);
0060 }
0061 
0062 parse_options
0063 get_parse_options( std::istream& is )
0064 {
0065     long const flags = is.iword(parse_flags_xalloc);
0066 
0067     using E = stream_parse_flags;
0068     parse_options opts;
0069     opts.allow_comments =
0070         flags & static_cast<long>(E::allow_comments) ? true : false;
0071     opts.allow_trailing_commas =
0072         flags & static_cast<long>(E::allow_trailing_commas) ? true : false;
0073     opts.allow_invalid_utf8 =
0074         flags & static_cast<long>(E::allow_invalid_utf8) ? true : false;
0075     return opts;
0076 }
0077 
0078 } // namespace
0079 
0080 value::
0081 ~value() noexcept
0082 {
0083     switch(kind())
0084     {
0085     case json::kind::null:
0086     case json::kind::bool_:
0087     case json::kind::int64:
0088     case json::kind::uint64:
0089     case json::kind::double_:
0090         sca_.~scalar();
0091         break;
0092 
0093     case json::kind::string:
0094         str_.~string();
0095         break;
0096 
0097     case json::kind::array:
0098         arr_.~array();
0099         break;
0100 
0101     case json::kind::object:
0102         obj_.~object();
0103         break;
0104     }
0105 }
0106 
0107 value::
0108 value(
0109     value const& other,
0110     storage_ptr sp)
0111 {
0112     switch(other.kind())
0113     {
0114     case json::kind::null:
0115         ::new(&sca_) scalar(
0116             std::move(sp));
0117         break;
0118 
0119     case json::kind::bool_:
0120         ::new(&sca_) scalar(
0121             other.sca_.b,
0122             std::move(sp));
0123         break;
0124 
0125     case json::kind::int64:
0126         ::new(&sca_) scalar(
0127             other.sca_.i,
0128             std::move(sp));
0129         break;
0130 
0131     case json::kind::uint64:
0132         ::new(&sca_) scalar(
0133             other.sca_.u,
0134             std::move(sp));
0135         break;
0136 
0137     case json::kind::double_:
0138         ::new(&sca_) scalar(
0139             other.sca_.d,
0140             std::move(sp));
0141         break;
0142 
0143     case json::kind::string:
0144         ::new(&str_) string(
0145             other.str_,
0146             std::move(sp));
0147         break;
0148 
0149     case json::kind::array:
0150         ::new(&arr_) array(
0151             other.arr_,
0152             std::move(sp));
0153         break;
0154 
0155     case json::kind::object:
0156         ::new(&obj_) object(
0157             other.obj_,
0158             std::move(sp));
0159         break;
0160     }
0161 }
0162 
0163 value::
0164 value(value&& other) noexcept
0165 {
0166     relocate(this, other);
0167     ::new(&other.sca_) scalar(sp_);
0168 }
0169 
0170 value::
0171 value(
0172     value&& other,
0173     storage_ptr sp)
0174 {
0175     switch(other.kind())
0176     {
0177     case json::kind::null:
0178         ::new(&sca_) scalar(
0179             std::move(sp));
0180         break;
0181 
0182     case json::kind::bool_:
0183         ::new(&sca_) scalar(
0184             other.sca_.b, std::move(sp));
0185         break;
0186 
0187     case json::kind::int64:
0188         ::new(&sca_) scalar(
0189             other.sca_.i, std::move(sp));
0190         break;
0191 
0192     case json::kind::uint64:
0193         ::new(&sca_) scalar(
0194             other.sca_.u, std::move(sp));
0195         break;
0196 
0197     case json::kind::double_:
0198         ::new(&sca_) scalar(
0199             other.sca_.d, std::move(sp));
0200         break;
0201 
0202     case json::kind::string:
0203         ::new(&str_) string(
0204             std::move(other.str_),
0205             std::move(sp));
0206         break;
0207 
0208     case json::kind::array:
0209         ::new(&arr_) array(
0210             std::move(other.arr_),
0211             std::move(sp));
0212         break;
0213 
0214     case json::kind::object:
0215         ::new(&obj_) object(
0216             std::move(other.obj_),
0217             std::move(sp));
0218         break;
0219     }
0220 }
0221 
0222 //----------------------------------------------------------
0223 //
0224 // Conversion
0225 //
0226 //----------------------------------------------------------
0227 
0228 value::
0229 value(
0230     std::initializer_list<value_ref> init,
0231     storage_ptr sp)
0232 {
0233     if(value_ref::maybe_object(init))
0234     {
0235         ::new(&obj_) object(
0236             value_ref::make_object(
0237                 init, std::move(sp)));
0238     }
0239     else
0240     {
0241 #ifndef BOOST_JSON_LEGACY_INIT_LIST_BEHAVIOR
0242         if( init.size() == 1 )
0243         {
0244             ::new(&sca_) scalar();
0245             value temp = init.begin()->make_value( std::move(sp) );
0246             swap(temp);
0247         }
0248         else
0249 #endif
0250         {
0251             ::new(&arr_) array(
0252                 value_ref::make_array(
0253                     init, std::move(sp)));
0254         }
0255     }
0256 }
0257 
0258 //----------------------------------------------------------
0259 //
0260 // Assignment
0261 //
0262 //----------------------------------------------------------
0263 
0264 value&
0265 value::
0266 operator=(value const& other)
0267 {
0268     value(other,
0269         storage()).swap(*this);
0270     return *this;
0271 }
0272 
0273 value&
0274 value::
0275 operator=(value&& other)
0276 {
0277     value(std::move(other),
0278         storage()).swap(*this);
0279     return *this;
0280 }
0281 
0282 value&
0283 value::
0284 operator=(
0285     std::initializer_list<value_ref> init)
0286 {
0287     value(init,
0288         storage()).swap(*this);
0289     return *this;
0290 }
0291 
0292 value&
0293 value::
0294 operator=(string_view s)
0295 {
0296     value(s, storage()).swap(*this);
0297     return *this;
0298 }
0299 
0300 value&
0301 value::
0302 operator=(char const* s)
0303 {
0304     value(s, storage()).swap(*this);
0305     return *this;
0306 }
0307 
0308 value&
0309 value::
0310 operator=(string const& str)
0311 {
0312     value(str, storage()).swap(*this);
0313     return *this;
0314 }
0315 
0316 value&
0317 value::
0318 operator=(string&& str)
0319 {
0320     value(std::move(str),
0321         storage()).swap(*this);
0322     return *this;
0323 }
0324 
0325 value&
0326 value::
0327 operator=(array const& arr)
0328 {
0329     value(arr, storage()).swap(*this);
0330     return *this;
0331 }
0332 
0333 value&
0334 value::
0335 operator=(array&& arr)
0336 {
0337     value(std::move(arr),
0338         storage()).swap(*this);
0339     return *this;
0340 }
0341 
0342 value&
0343 value::
0344 operator=(object const& obj)
0345 {
0346     value(obj, storage()).swap(*this);
0347     return *this;
0348 }
0349 
0350 value&
0351 value::
0352 operator=(object&& obj)
0353 {
0354     value(std::move(obj),
0355         storage()).swap(*this);
0356     return *this;
0357 }
0358 
0359 //----------------------------------------------------------
0360 //
0361 // Accessors
0362 //
0363 //----------------------------------------------------------
0364 
0365 system::result<array&>
0366 value::try_as_array() noexcept
0367 {
0368     if( is_array() )
0369         return arr_;
0370 
0371     system::error_code ec;
0372     BOOST_JSON_FAIL(ec, error::not_array);
0373     return ec;
0374 }
0375 
0376 system::result<array const&>
0377 value::try_as_array() const noexcept
0378 {
0379     if( is_array() )
0380         return arr_;
0381 
0382     system::error_code ec;
0383     BOOST_JSON_FAIL(ec, error::not_array);
0384     return ec;
0385 }
0386 
0387 system::result<object&>
0388 value::try_as_object() noexcept
0389 {
0390     if( is_object() )
0391         return obj_;
0392 
0393     system::error_code ec;
0394     BOOST_JSON_FAIL(ec, error::not_object);
0395     return ec;
0396 }
0397 
0398 system::result<object const&>
0399 value::try_as_object() const noexcept
0400 {
0401     if( is_object() )
0402         return obj_;
0403 
0404     system::error_code ec;
0405     BOOST_JSON_FAIL(ec, error::not_object);
0406     return ec;
0407 }
0408 
0409 system::result<string&>
0410 value::try_as_string() noexcept
0411 {
0412     if( is_string() )
0413         return str_;
0414 
0415     system::error_code ec;
0416     BOOST_JSON_FAIL(ec, error::not_string);
0417     return ec;
0418 }
0419 
0420 system::result<string const&>
0421 value::try_as_string() const noexcept
0422 {
0423     if( is_string() )
0424         return str_;
0425 
0426     system::error_code ec;
0427     BOOST_JSON_FAIL(ec, error::not_string);
0428     return ec;
0429 }
0430 
0431 system::result<std::int64_t&>
0432 value::try_as_int64() noexcept
0433 {
0434     if( is_int64() )
0435         return sca_.i;
0436 
0437     system::error_code ec;
0438     BOOST_JSON_FAIL(ec, error::not_int64);
0439     return ec;
0440 }
0441 
0442 system::result<std::int64_t>
0443 value::try_as_int64() const noexcept
0444 {
0445     if( is_int64() )
0446         return sca_.i;
0447 
0448     system::error_code ec;
0449     BOOST_JSON_FAIL(ec, error::not_int64);
0450     return ec;
0451 }
0452 
0453 system::result<std::uint64_t&>
0454 value::try_as_uint64() noexcept
0455 {
0456     if( is_uint64() )
0457         return sca_.u;
0458 
0459     system::error_code ec;
0460     BOOST_JSON_FAIL(ec, error::not_uint64);
0461     return ec;
0462 }
0463 
0464 system::result<std::uint64_t>
0465 value::try_as_uint64() const noexcept
0466 {
0467     if( is_uint64() )
0468         return sca_.u;
0469 
0470     system::error_code ec;
0471     BOOST_JSON_FAIL(ec, error::not_uint64);
0472     return ec;
0473 }
0474 
0475 system::result<double&>
0476 value::try_as_double() noexcept
0477 {
0478     if( is_double() )
0479         return sca_.d;
0480 
0481     system::error_code ec;
0482     BOOST_JSON_FAIL(ec, error::not_double);
0483     return ec;
0484 }
0485 
0486 system::result<double>
0487 value::try_as_double() const noexcept
0488 {
0489     if( is_double() )
0490         return sca_.d;
0491 
0492     system::error_code ec;
0493     BOOST_JSON_FAIL(ec, error::not_double);
0494     return ec;
0495 }
0496 
0497 system::result<bool&>
0498 value::try_as_bool() noexcept
0499 {
0500     if( is_bool() )
0501         return sca_.b;
0502 
0503     system::error_code ec;
0504     BOOST_JSON_FAIL(ec, error::not_bool);
0505     return ec;
0506 }
0507 
0508 system::result<bool>
0509 value::try_as_bool() const noexcept
0510 {
0511     if( is_bool() )
0512         return sca_.b;
0513 
0514     system::error_code ec;
0515     BOOST_JSON_FAIL(ec, error::not_bool);
0516     return ec;
0517 }
0518 
0519 system::result<std::nullptr_t>
0520 value::try_as_null() const noexcept
0521 {
0522     if( is_null() )
0523         return nullptr;
0524 
0525     system::error_code ec;
0526     BOOST_JSON_FAIL(ec, error::not_null);
0527     return ec;
0528 }
0529 
0530 boost::system::result<value&>
0531 value::try_at(string_view key) noexcept
0532 {
0533     auto r = try_as_object();
0534     if( !r )
0535         return r.error();
0536     return r->try_at(key);
0537 }
0538 
0539 boost::system::result<value const&>
0540 value::try_at(string_view key) const noexcept
0541 {
0542     auto r = try_as_object();
0543     if( !r )
0544         return r.error();
0545     return r->try_at(key);
0546 }
0547 
0548 boost::system::result<value&>
0549 value::try_at(std::size_t pos) noexcept
0550 {
0551     auto r = try_as_array();
0552     if( !r )
0553         return r.error();
0554     return r->try_at(pos);
0555 }
0556 
0557 boost::system::result<value const&>
0558 value::try_at(std::size_t pos) const noexcept
0559 {
0560     auto r = try_as_array();
0561     if( !r )
0562         return r.error();
0563     return r->try_at(pos);
0564 }
0565 
0566 object const&
0567 value::as_object(source_location const& loc) const&
0568 {
0569     return try_as_object().value(loc);
0570 }
0571 
0572 array const&
0573 value::as_array(source_location const& loc) const&
0574 {
0575     return try_as_array().value(loc);
0576 }
0577 
0578 string const&
0579 value::as_string(source_location const& loc) const&
0580 {
0581     return try_as_string().value(loc);
0582 }
0583 
0584 std::int64_t&
0585 value::as_int64(source_location const& loc)
0586 {
0587     return try_as_int64().value(loc);
0588 }
0589 
0590 std::int64_t
0591 value::as_int64(source_location const& loc) const
0592 {
0593     return try_as_int64().value(loc);
0594 }
0595 
0596 std::uint64_t&
0597 value::as_uint64(source_location const& loc)
0598 {
0599     return try_as_uint64().value(loc);
0600 }
0601 
0602 std::uint64_t
0603 value::as_uint64(source_location const& loc) const
0604 {
0605     return try_as_uint64().value(loc);
0606 }
0607 
0608 double&
0609 value::as_double(source_location const& loc)
0610 {
0611     return try_as_double().value(loc);
0612 }
0613 
0614 double
0615 value::as_double(source_location const& loc) const
0616 {
0617     return try_as_double().value(loc);
0618 }
0619 
0620 bool&
0621 value::as_bool(source_location const& loc)
0622 {
0623     return try_as_bool().value(loc);
0624 }
0625 
0626 bool
0627 value::as_bool(source_location const& loc) const
0628 {
0629     return try_as_bool().value(loc);
0630 }
0631 
0632 //----------------------------------------------------------
0633 //
0634 // Modifiers
0635 //
0636 //----------------------------------------------------------
0637 
0638 string&
0639 value::
0640 emplace_string() noexcept
0641 {
0642     return *::new(&str_) string(destroy());
0643 }
0644 
0645 array&
0646 value::
0647 emplace_array() noexcept
0648 {
0649     return *::new(&arr_) array(destroy());
0650 }
0651 
0652 object&
0653 value::
0654 emplace_object() noexcept
0655 {
0656     return *::new(&obj_) object(destroy());
0657 }
0658 
0659 void
0660 value::
0661 swap(value& other)
0662 {
0663     if(*storage() == *other.storage())
0664     {
0665         // fast path
0666         union U
0667         {
0668             value tmp;
0669             U(){}
0670             ~U(){}
0671         };
0672         U u;
0673         relocate(&u.tmp, *this);
0674         relocate(this, other);
0675         relocate(&other, u.tmp);
0676         return;
0677     }
0678 
0679     // copy
0680     value temp1(
0681         std::move(*this),
0682         other.storage());
0683     value temp2(
0684         std::move(other),
0685         this->storage());
0686     other.~value();
0687     ::new(&other) value(pilfer(temp1));
0688     this->~value();
0689     ::new(this) value(pilfer(temp2));
0690 }
0691 
0692 std::istream&
0693 operator>>(
0694     std::istream& is,
0695     value& jv)
0696 {
0697     using Traits = std::istream::traits_type;
0698 
0699     // sentry prepares the stream for reading and finalizes it in destructor
0700     std::istream::sentry sentry(is);
0701     if( !sentry )
0702         return is;
0703 
0704     parse_options opts = get_parse_options( is );
0705     if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
0706         opts.max_depth = depth;
0707 
0708     unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0709     stream_parser p( {}, opts, parser_buf );
0710     p.reset( jv.storage() );
0711 
0712     char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0713     std::streambuf& buf = *is.rdbuf();
0714     std::ios::iostate err = std::ios::goodbit;
0715 #ifndef BOOST_NO_EXCEPTIONS
0716     try
0717 #endif
0718     {
0719         while( true )
0720         {
0721             system::error_code ec;
0722 
0723             // we peek the buffer; this either makes sure that there's no
0724             // more input, or makes sure there's something in the internal
0725             // buffer (so in_avail will return a positive number)
0726             std::istream::int_type c = is.rdbuf()->sgetc();
0727             // if we indeed reached EOF, we check if we parsed a full JSON
0728             // document; if not, we error out
0729             if( Traits::eq_int_type(c, Traits::eof()) )
0730             {
0731                 err |= std::ios::eofbit;
0732                 p.finish(ec);
0733                 if( ec.failed() )
0734                     break;
0735             }
0736 
0737             // regardless of reaching EOF, we might have parsed a full JSON
0738             // document; if so, we successfully finish
0739             if( p.done() )
0740             {
0741                 jv = p.release();
0742                 return is;
0743             }
0744 
0745             // at this point we definitely have more input, specifically in
0746             // buf's internal buffer; we also definitely haven't parsed a whole
0747             // document
0748             std::streamsize available = buf.in_avail();
0749             // if this assert fails, the streambuf is buggy
0750             BOOST_ASSERT( available > 0 );
0751 
0752             available = ( std::min )(
0753                 static_cast<std::size_t>(available), sizeof(read_buf) );
0754             // we read from the internal buffer of buf into our buffer
0755             available = buf.sgetn( read_buf, available );
0756 
0757             std::size_t consumed = p.write_some(
0758                 read_buf, static_cast<std::size_t>(available), ec );
0759             // if the parser hasn't consumed the entire input we've took from
0760             // buf, we put the remaining data back; this should succeed,
0761             // because we only read data from buf's internal buffer
0762             while( consumed++ < static_cast<std::size_t>(available) )
0763             {
0764                 std::istream::int_type const status = buf.sungetc();
0765                 BOOST_ASSERT( status != Traits::eof() );
0766                 (void)status;
0767             }
0768 
0769             if( ec.failed() )
0770                 break;
0771         }
0772     }
0773 #ifndef BOOST_NO_EXCEPTIONS
0774     catch(...)
0775     {
0776         try
0777         {
0778             is.setstate(std::ios::badbit);
0779         }
0780         // we ignore the exception, because we need to throw the original
0781         // exception instead
0782         catch( std::ios::failure const& ) { }
0783 
0784         if( is.exceptions() & std::ios::badbit )
0785             throw;
0786     }
0787 #endif
0788 
0789     is.setstate(err | std::ios::failbit);
0790     return is;
0791 }
0792 
0793 std::istream&
0794 operator>>(
0795     std::istream& is,
0796     parse_options const& opts)
0797 {
0798     is.iword(parse_flags_xalloc) = to_bitmask(opts);
0799     is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
0800     return is;
0801 }
0802 
0803 //----------------------------------------------------------
0804 //
0805 // private
0806 //
0807 //----------------------------------------------------------
0808 
0809 storage_ptr
0810 value::
0811 destroy() noexcept
0812 {
0813     switch(kind())
0814     {
0815     case json::kind::null:
0816     case json::kind::bool_:
0817     case json::kind::int64:
0818     case json::kind::uint64:
0819     case json::kind::double_:
0820         break;
0821 
0822     case json::kind::string:
0823     {
0824         auto sp = str_.storage();
0825         str_.~string();
0826         return sp;
0827     }
0828 
0829     case json::kind::array:
0830     {
0831         auto sp = arr_.storage();
0832         arr_.~array();
0833         return sp;
0834     }
0835 
0836     case json::kind::object:
0837     {
0838         auto sp = obj_.storage();
0839         obj_.~object();
0840         return sp;
0841     }
0842 
0843     }
0844     return std::move(sp_);
0845 }
0846 
0847 bool
0848 value::
0849 equal(value const& other) const noexcept
0850 {
0851     switch(kind())
0852     {
0853     default: // unreachable()?
0854     case json::kind::null:
0855         return other.kind() == json::kind::null;
0856 
0857     case json::kind::bool_:
0858         return
0859             other.kind() == json::kind::bool_ &&
0860             get_bool() == other.get_bool();
0861 
0862     case json::kind::int64:
0863         switch(other.kind())
0864         {
0865         case json::kind::int64:
0866             return get_int64() == other.get_int64();
0867         case json::kind::uint64:
0868             if(get_int64() < 0)
0869                 return false;
0870             return static_cast<std::uint64_t>(
0871                 get_int64()) == other.get_uint64();
0872         default:
0873             return false;
0874         }
0875 
0876     case json::kind::uint64:
0877         switch(other.kind())
0878         {
0879         case json::kind::uint64:
0880             return get_uint64() == other.get_uint64();
0881         case json::kind::int64:
0882             if(other.get_int64() < 0)
0883                 return false;
0884             return static_cast<std::uint64_t>(
0885                 other.get_int64()) == get_uint64();
0886         default:
0887             return false;
0888         }
0889 
0890     case json::kind::double_:
0891         return
0892             other.kind() == json::kind::double_ &&
0893             get_double() == other.get_double();
0894 
0895     case json::kind::string:
0896         return
0897             other.kind() == json::kind::string &&
0898             get_string() == other.get_string();
0899 
0900     case json::kind::array:
0901         return
0902             other.kind() == json::kind::array &&
0903             get_array() == other.get_array();
0904 
0905     case json::kind::object:
0906         return
0907             other.kind() == json::kind::object &&
0908             get_object() == other.get_object();
0909     }
0910 }
0911 
0912 //----------------------------------------------------------
0913 //
0914 // key_value_pair
0915 //
0916 //----------------------------------------------------------
0917 
0918 // empty keys point here
0919 BOOST_JSON_REQUIRE_CONST_INIT
0920 char const
0921 key_value_pair::empty_[1] = { 0 };
0922 
0923 key_value_pair::
0924 key_value_pair(
0925     pilfered<json::value> key,
0926     pilfered<json::value> value) noexcept
0927     : value_(value)
0928 {
0929     std::size_t len;
0930     key_ = access::release_key(key.get(), len);
0931     len_ = static_cast<std::uint32_t>(len);
0932 }
0933 
0934 key_value_pair::
0935 key_value_pair(
0936     key_value_pair const& other,
0937     storage_ptr sp)
0938     : value_(other.value_, std::move(sp))
0939 {
0940     auto p = reinterpret_cast<
0941         char*>(value_.storage()->
0942             allocate(other.len_ + 1,
0943                 alignof(char)));
0944     std::memcpy(
0945         p, other.key_, other.len_);
0946     len_ = other.len_;
0947     p[len_] = 0;
0948     key_ = p;
0949 }
0950 
0951 //----------------------------------------------------------
0952 
0953 namespace detail
0954 {
0955 
0956 std::size_t
0957 hash_value_impl( value const& jv ) noexcept
0958 {
0959     std::size_t seed = 0;
0960 
0961     kind const k = jv.kind();
0962     boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
0963 
0964     visit( value_hasher{seed}, jv );
0965     return seed;
0966 }
0967 
0968 } // namespace detail
0969 } // namespace json
0970 } // namespace boost
0971 
0972 //----------------------------------------------------------
0973 //
0974 // std::hash specialization
0975 //
0976 //----------------------------------------------------------
0977 
0978 std::size_t
0979 std::hash<::boost::json::value>::operator()(
0980     ::boost::json::value const& jv) const noexcept
0981 {
0982     return ::boost::hash< ::boost::json::value >()( jv );
0983 }
0984 
0985 //----------------------------------------------------------
0986 
0987 #endif