Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:39:00

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         if( init.size() == 1 )
0242         {
0243             ::new(&sca_) scalar();
0244             value temp = init.begin()->make_value( std::move(sp) );
0245             swap(temp);
0246         }
0247         else
0248         {
0249             ::new(&arr_) array(
0250                 value_ref::make_array(
0251                     init, std::move(sp)));
0252         }
0253     }
0254 }
0255 
0256 //----------------------------------------------------------
0257 //
0258 // Assignment
0259 //
0260 //----------------------------------------------------------
0261 
0262 value&
0263 value::
0264 operator=(value const& other)
0265 {
0266     value(other,
0267         storage()).swap(*this);
0268     return *this;
0269 }
0270 
0271 value&
0272 value::
0273 operator=(value&& other)
0274 {
0275     value(std::move(other),
0276         storage()).swap(*this);
0277     return *this;
0278 }
0279 
0280 value&
0281 value::
0282 operator=(
0283     std::initializer_list<value_ref> init)
0284 {
0285     value(init,
0286         storage()).swap(*this);
0287     return *this;
0288 }
0289 
0290 value&
0291 value::
0292 operator=(string_view s)
0293 {
0294     value(s, storage()).swap(*this);
0295     return *this;
0296 }
0297 
0298 value&
0299 value::
0300 operator=(char const* s)
0301 {
0302     value(s, storage()).swap(*this);
0303     return *this;
0304 }
0305 
0306 value&
0307 value::
0308 operator=(string const& str)
0309 {
0310     value(str, storage()).swap(*this);
0311     return *this;
0312 }
0313 
0314 value&
0315 value::
0316 operator=(string&& str)
0317 {
0318     value(std::move(str),
0319         storage()).swap(*this);
0320     return *this;
0321 }
0322 
0323 value&
0324 value::
0325 operator=(array const& arr)
0326 {
0327     value(arr, storage()).swap(*this);
0328     return *this;
0329 }
0330 
0331 value&
0332 value::
0333 operator=(array&& arr)
0334 {
0335     value(std::move(arr),
0336         storage()).swap(*this);
0337     return *this;
0338 }
0339 
0340 value&
0341 value::
0342 operator=(object const& obj)
0343 {
0344     value(obj, storage()).swap(*this);
0345     return *this;
0346 }
0347 
0348 value&
0349 value::
0350 operator=(object&& obj)
0351 {
0352     value(std::move(obj),
0353         storage()).swap(*this);
0354     return *this;
0355 }
0356 
0357 //----------------------------------------------------------
0358 //
0359 // Accessors
0360 //
0361 //----------------------------------------------------------
0362 
0363 system::result<array&>
0364 value::try_as_array() noexcept
0365 {
0366     if( is_array() )
0367         return arr_;
0368 
0369     system::error_code ec;
0370     BOOST_JSON_FAIL(ec, error::not_array);
0371     return ec;
0372 }
0373 
0374 system::result<array const&>
0375 value::try_as_array() const noexcept
0376 {
0377     if( is_array() )
0378         return arr_;
0379 
0380     system::error_code ec;
0381     BOOST_JSON_FAIL(ec, error::not_array);
0382     return ec;
0383 }
0384 
0385 system::result<object&>
0386 value::try_as_object() noexcept
0387 {
0388     if( is_object() )
0389         return obj_;
0390 
0391     system::error_code ec;
0392     BOOST_JSON_FAIL(ec, error::not_object);
0393     return ec;
0394 }
0395 
0396 system::result<object const&>
0397 value::try_as_object() const noexcept
0398 {
0399     if( is_object() )
0400         return obj_;
0401 
0402     system::error_code ec;
0403     BOOST_JSON_FAIL(ec, error::not_object);
0404     return ec;
0405 }
0406 
0407 system::result<string&>
0408 value::try_as_string() noexcept
0409 {
0410     if( is_string() )
0411         return str_;
0412 
0413     system::error_code ec;
0414     BOOST_JSON_FAIL(ec, error::not_string);
0415     return ec;
0416 }
0417 
0418 system::result<string const&>
0419 value::try_as_string() const noexcept
0420 {
0421     if( is_string() )
0422         return str_;
0423 
0424     system::error_code ec;
0425     BOOST_JSON_FAIL(ec, error::not_string);
0426     return ec;
0427 }
0428 
0429 system::result<std::int64_t&>
0430 value::try_as_int64() noexcept
0431 {
0432     if( is_int64() )
0433         return sca_.i;
0434 
0435     system::error_code ec;
0436     BOOST_JSON_FAIL(ec, error::not_int64);
0437     return ec;
0438 }
0439 
0440 system::result<std::int64_t>
0441 value::try_as_int64() const noexcept
0442 {
0443     if( is_int64() )
0444         return sca_.i;
0445 
0446     system::error_code ec;
0447     BOOST_JSON_FAIL(ec, error::not_int64);
0448     return ec;
0449 }
0450 
0451 system::result<std::uint64_t&>
0452 value::try_as_uint64() noexcept
0453 {
0454     if( is_uint64() )
0455         return sca_.u;
0456 
0457     system::error_code ec;
0458     BOOST_JSON_FAIL(ec, error::not_uint64);
0459     return ec;
0460 }
0461 
0462 system::result<std::uint64_t>
0463 value::try_as_uint64() const noexcept
0464 {
0465     if( is_uint64() )
0466         return sca_.u;
0467 
0468     system::error_code ec;
0469     BOOST_JSON_FAIL(ec, error::not_uint64);
0470     return ec;
0471 }
0472 
0473 system::result<double&>
0474 value::try_as_double() noexcept
0475 {
0476     if( is_double() )
0477         return sca_.d;
0478 
0479     system::error_code ec;
0480     BOOST_JSON_FAIL(ec, error::not_double);
0481     return ec;
0482 }
0483 
0484 system::result<double>
0485 value::try_as_double() const noexcept
0486 {
0487     if( is_double() )
0488         return sca_.d;
0489 
0490     system::error_code ec;
0491     BOOST_JSON_FAIL(ec, error::not_double);
0492     return ec;
0493 }
0494 
0495 system::result<bool&>
0496 value::try_as_bool() noexcept
0497 {
0498     if( is_bool() )
0499         return sca_.b;
0500 
0501     system::error_code ec;
0502     BOOST_JSON_FAIL(ec, error::not_bool);
0503     return ec;
0504 }
0505 
0506 system::result<bool>
0507 value::try_as_bool() const noexcept
0508 {
0509     if( is_bool() )
0510         return sca_.b;
0511 
0512     system::error_code ec;
0513     BOOST_JSON_FAIL(ec, error::not_bool);
0514     return ec;
0515 }
0516 
0517 system::result<std::nullptr_t>
0518 value::try_as_null() const noexcept
0519 {
0520     if( is_null() )
0521         return nullptr;
0522 
0523     system::error_code ec;
0524     BOOST_JSON_FAIL(ec, error::not_null);
0525     return ec;
0526 }
0527 
0528 boost::system::result<value&>
0529 value::try_at(string_view key) noexcept
0530 {
0531     auto r = try_as_object();
0532     if( !r )
0533         return r.error();
0534     return r->try_at(key);
0535 }
0536 
0537 boost::system::result<value const&>
0538 value::try_at(string_view key) const noexcept
0539 {
0540     auto r = try_as_object();
0541     if( !r )
0542         return r.error();
0543     return r->try_at(key);
0544 }
0545 
0546 boost::system::result<value&>
0547 value::try_at(std::size_t pos) noexcept
0548 {
0549     auto r = try_as_array();
0550     if( !r )
0551         return r.error();
0552     return r->try_at(pos);
0553 }
0554 
0555 boost::system::result<value const&>
0556 value::try_at(std::size_t pos) const noexcept
0557 {
0558     auto r = try_as_array();
0559     if( !r )
0560         return r.error();
0561     return r->try_at(pos);
0562 }
0563 
0564 object const&
0565 value::as_object(source_location const& loc) const&
0566 {
0567     return try_as_object().value(loc);
0568 }
0569 
0570 array const&
0571 value::as_array(source_location const& loc) const&
0572 {
0573     return try_as_array().value(loc);
0574 }
0575 
0576 string const&
0577 value::as_string(source_location const& loc) const&
0578 {
0579     return try_as_string().value(loc);
0580 }
0581 
0582 std::int64_t&
0583 value::as_int64(source_location const& loc)
0584 {
0585     return try_as_int64().value(loc);
0586 }
0587 
0588 std::int64_t
0589 value::as_int64(source_location const& loc) const
0590 {
0591     return try_as_int64().value(loc);
0592 }
0593 
0594 std::uint64_t&
0595 value::as_uint64(source_location const& loc)
0596 {
0597     return try_as_uint64().value(loc);
0598 }
0599 
0600 std::uint64_t
0601 value::as_uint64(source_location const& loc) const
0602 {
0603     return try_as_uint64().value(loc);
0604 }
0605 
0606 double&
0607 value::as_double(source_location const& loc)
0608 {
0609     return try_as_double().value(loc);
0610 }
0611 
0612 double
0613 value::as_double(source_location const& loc) const
0614 {
0615     return try_as_double().value(loc);
0616 }
0617 
0618 bool&
0619 value::as_bool(source_location const& loc)
0620 {
0621     return try_as_bool().value(loc);
0622 }
0623 
0624 bool
0625 value::as_bool(source_location const& loc) const
0626 {
0627     return try_as_bool().value(loc);
0628 }
0629 
0630 //----------------------------------------------------------
0631 //
0632 // Modifiers
0633 //
0634 //----------------------------------------------------------
0635 
0636 string&
0637 value::
0638 emplace_string() noexcept
0639 {
0640     return *::new(&str_) string(destroy());
0641 }
0642 
0643 array&
0644 value::
0645 emplace_array() noexcept
0646 {
0647     return *::new(&arr_) array(destroy());
0648 }
0649 
0650 object&
0651 value::
0652 emplace_object() noexcept
0653 {
0654     return *::new(&obj_) object(destroy());
0655 }
0656 
0657 void
0658 value::
0659 swap(value& other)
0660 {
0661     if(*storage() == *other.storage())
0662     {
0663         // fast path
0664         union U
0665         {
0666             value tmp;
0667             U(){}
0668             ~U(){}
0669         };
0670         U u;
0671         relocate(&u.tmp, *this);
0672         relocate(this, other);
0673         relocate(&other, u.tmp);
0674         return;
0675     }
0676 
0677     // copy
0678     value temp1(
0679         std::move(*this),
0680         other.storage());
0681     value temp2(
0682         std::move(other),
0683         this->storage());
0684     other.~value();
0685     ::new(&other) value(pilfer(temp1));
0686     this->~value();
0687     ::new(this) value(pilfer(temp2));
0688 }
0689 
0690 std::istream&
0691 operator>>(
0692     std::istream& is,
0693     value& jv)
0694 {
0695     using Traits = std::istream::traits_type;
0696 
0697     // sentry prepares the stream for reading and finalizes it in destructor
0698     std::istream::sentry sentry(is);
0699     if( !sentry )
0700         return is;
0701 
0702     parse_options opts = get_parse_options( is );
0703     if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
0704         opts.max_depth = depth;
0705 
0706     unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0707     stream_parser p( {}, opts, parser_buf );
0708     p.reset( jv.storage() );
0709 
0710     char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0711     std::streambuf& buf = *is.rdbuf();
0712     std::ios::iostate err = std::ios::goodbit;
0713 #ifndef BOOST_NO_EXCEPTIONS
0714     try
0715 #endif
0716     {
0717         while( true )
0718         {
0719             system::error_code ec;
0720 
0721             // we peek the buffer; this either makes sure that there's no
0722             // more input, or makes sure there's something in the internal
0723             // buffer (so in_avail will return a positive number)
0724             std::istream::int_type c = is.rdbuf()->sgetc();
0725             // if we indeed reached EOF, we check if we parsed a full JSON
0726             // document; if not, we error out
0727             if( Traits::eq_int_type(c, Traits::eof()) )
0728             {
0729                 err |= std::ios::eofbit;
0730                 p.finish(ec);
0731                 if( ec.failed() )
0732                     break;
0733             }
0734 
0735             // regardless of reaching EOF, we might have parsed a full JSON
0736             // document; if so, we successfully finish
0737             if( p.done() )
0738             {
0739                 jv = p.release();
0740                 return is;
0741             }
0742 
0743             // at this point we definitely have more input, specifically in
0744             // buf's internal buffer; we also definitely haven't parsed a whole
0745             // document
0746             std::streamsize available = buf.in_avail();
0747             // if this assert fails, the streambuf is buggy
0748             BOOST_ASSERT( available > 0 );
0749 
0750             available = ( std::min )(
0751                 static_cast<std::size_t>(available), sizeof(read_buf) );
0752             // we read from the internal buffer of buf into our buffer
0753             available = buf.sgetn( read_buf, available );
0754 
0755             std::size_t consumed = p.write_some(
0756                 read_buf, static_cast<std::size_t>(available), ec );
0757             // if the parser hasn't consumed the entire input we've took from
0758             // buf, we put the remaining data back; this should succeed,
0759             // because we only read data from buf's internal buffer
0760             while( consumed++ < static_cast<std::size_t>(available) )
0761             {
0762                 std::istream::int_type const status = buf.sungetc();
0763                 BOOST_ASSERT( status != Traits::eof() );
0764                 (void)status;
0765             }
0766 
0767             if( ec.failed() )
0768                 break;
0769         }
0770     }
0771 #ifndef BOOST_NO_EXCEPTIONS
0772     catch(...)
0773     {
0774         try
0775         {
0776             is.setstate(std::ios::badbit);
0777         }
0778         // we ignore the exception, because we need to throw the original
0779         // exception instead
0780         catch( std::ios::failure const& ) { }
0781 
0782         if( is.exceptions() & std::ios::badbit )
0783             throw;
0784     }
0785 #endif
0786 
0787     is.setstate(err | std::ios::failbit);
0788     return is;
0789 }
0790 
0791 std::istream&
0792 operator>>(
0793     std::istream& is,
0794     parse_options const& opts)
0795 {
0796     is.iword(parse_flags_xalloc) = to_bitmask(opts);
0797     is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
0798     return is;
0799 }
0800 
0801 //----------------------------------------------------------
0802 //
0803 // private
0804 //
0805 //----------------------------------------------------------
0806 
0807 storage_ptr
0808 value::
0809 destroy() noexcept
0810 {
0811     switch(kind())
0812     {
0813     case json::kind::null:
0814     case json::kind::bool_:
0815     case json::kind::int64:
0816     case json::kind::uint64:
0817     case json::kind::double_:
0818         break;
0819 
0820     case json::kind::string:
0821     {
0822         auto sp = str_.storage();
0823         str_.~string();
0824         return sp;
0825     }
0826 
0827     case json::kind::array:
0828     {
0829         auto sp = arr_.storage();
0830         arr_.~array();
0831         return sp;
0832     }
0833 
0834     case json::kind::object:
0835     {
0836         auto sp = obj_.storage();
0837         obj_.~object();
0838         return sp;
0839     }
0840 
0841     }
0842     return std::move(sp_);
0843 }
0844 
0845 bool
0846 value::
0847 equal(value const& other) const noexcept
0848 {
0849     switch(kind())
0850     {
0851     default: // unreachable()?
0852     case json::kind::null:
0853         return other.kind() == json::kind::null;
0854 
0855     case json::kind::bool_:
0856         return
0857             other.kind() == json::kind::bool_ &&
0858             get_bool() == other.get_bool();
0859 
0860     case json::kind::int64:
0861         switch(other.kind())
0862         {
0863         case json::kind::int64:
0864             return get_int64() == other.get_int64();
0865         case json::kind::uint64:
0866             if(get_int64() < 0)
0867                 return false;
0868             return static_cast<std::uint64_t>(
0869                 get_int64()) == other.get_uint64();
0870         default:
0871             return false;
0872         }
0873 
0874     case json::kind::uint64:
0875         switch(other.kind())
0876         {
0877         case json::kind::uint64:
0878             return get_uint64() == other.get_uint64();
0879         case json::kind::int64:
0880             if(other.get_int64() < 0)
0881                 return false;
0882             return static_cast<std::uint64_t>(
0883                 other.get_int64()) == get_uint64();
0884         default:
0885             return false;
0886         }
0887 
0888     case json::kind::double_:
0889         return
0890             other.kind() == json::kind::double_ &&
0891             get_double() == other.get_double();
0892 
0893     case json::kind::string:
0894         return
0895             other.kind() == json::kind::string &&
0896             get_string() == other.get_string();
0897 
0898     case json::kind::array:
0899         return
0900             other.kind() == json::kind::array &&
0901             get_array() == other.get_array();
0902 
0903     case json::kind::object:
0904         return
0905             other.kind() == json::kind::object &&
0906             get_object() == other.get_object();
0907     }
0908 }
0909 
0910 //----------------------------------------------------------
0911 //
0912 // key_value_pair
0913 //
0914 //----------------------------------------------------------
0915 
0916 // empty keys point here
0917 BOOST_JSON_REQUIRE_CONST_INIT
0918 char const
0919 key_value_pair::empty_[1] = { 0 };
0920 
0921 key_value_pair::
0922 key_value_pair(
0923     pilfered<json::value> key,
0924     pilfered<json::value> value) noexcept
0925     : value_(value)
0926 {
0927     std::size_t len;
0928     key_ = access::release_key(key.get(), len);
0929     len_ = static_cast<std::uint32_t>(len);
0930 }
0931 
0932 key_value_pair::
0933 key_value_pair(
0934     key_value_pair const& other,
0935     storage_ptr sp)
0936     : value_(other.value_, std::move(sp))
0937 {
0938     auto p = reinterpret_cast<
0939         char*>(value_.storage()->
0940             allocate(other.len_ + 1,
0941                 alignof(char)));
0942     std::memcpy(
0943         p, other.key_, other.len_);
0944     len_ = other.len_;
0945     p[len_] = 0;
0946     key_ = p;
0947 }
0948 
0949 //----------------------------------------------------------
0950 
0951 namespace detail
0952 {
0953 
0954 std::size_t
0955 hash_value_impl( value const& jv ) noexcept
0956 {
0957     std::size_t seed = 0;
0958 
0959     kind const k = jv.kind();
0960     boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
0961 
0962     visit( value_hasher{seed}, jv );
0963     return seed;
0964 }
0965 
0966 } // namespace detail
0967 } // namespace json
0968 } // namespace boost
0969 
0970 //----------------------------------------------------------
0971 //
0972 // std::hash specialization
0973 //
0974 //----------------------------------------------------------
0975 
0976 std::size_t
0977 std::hash<::boost::json::value>::operator()(
0978     ::boost::json::value const& jv) const noexcept
0979 {
0980     return ::boost::hash< ::boost::json::value >()( jv );
0981 }
0982 
0983 //----------------------------------------------------------
0984 
0985 #endif