Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:02

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 // Modifiers
0362 //
0363 //----------------------------------------------------------
0364 
0365 string&
0366 value::
0367 emplace_string() noexcept
0368 {
0369     return *::new(&str_) string(destroy());
0370 }
0371 
0372 array&
0373 value::
0374 emplace_array() noexcept
0375 {
0376     return *::new(&arr_) array(destroy());
0377 }
0378 
0379 object&
0380 value::
0381 emplace_object() noexcept
0382 {
0383     return *::new(&obj_) object(destroy());
0384 }
0385 
0386 void
0387 value::
0388 swap(value& other)
0389 {
0390     if(*storage() == *other.storage())
0391     {
0392         // fast path
0393         union U
0394         {
0395             value tmp;
0396             U(){}
0397             ~U(){}
0398         };
0399         U u;
0400         relocate(&u.tmp, *this);
0401         relocate(this, other);
0402         relocate(&other, u.tmp);
0403         return;
0404     }
0405 
0406     // copy
0407     value temp1(
0408         std::move(*this),
0409         other.storage());
0410     value temp2(
0411         std::move(other),
0412         this->storage());
0413     other.~value();
0414     ::new(&other) value(pilfer(temp1));
0415     this->~value();
0416     ::new(this) value(pilfer(temp2));
0417 }
0418 
0419 std::istream&
0420 operator>>(
0421     std::istream& is,
0422     value& jv)
0423 {
0424     using Traits = std::istream::traits_type;
0425 
0426     // sentry prepares the stream for reading and finalizes it in destructor
0427     std::istream::sentry sentry(is);
0428     if( !sentry )
0429         return is;
0430 
0431     parse_options opts = get_parse_options( is );
0432     if( auto depth = static_cast<std::size_t>( is.iword(parse_depth_xalloc) ) )
0433         opts.max_depth = depth;
0434 
0435     unsigned char parser_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0436     stream_parser p( {}, opts, parser_buf );
0437     p.reset( jv.storage() );
0438 
0439     char read_buf[BOOST_JSON_STACK_BUFFER_SIZE / 2];
0440     std::streambuf& buf = *is.rdbuf();
0441     std::ios::iostate err = std::ios::goodbit;
0442 #ifndef BOOST_NO_EXCEPTIONS
0443     try
0444 #endif
0445     {
0446         while( true )
0447         {
0448             error_code ec;
0449 
0450             // we peek the buffer; this either makes sure that there's no
0451             // more input, or makes sure there's something in the internal
0452             // buffer (so in_avail will return a positive number)
0453             std::istream::int_type c = is.rdbuf()->sgetc();
0454             // if we indeed reached EOF, we check if we parsed a full JSON
0455             // document; if not, we error out
0456             if( Traits::eq_int_type(c, Traits::eof()) )
0457             {
0458                 err |= std::ios::eofbit;
0459                 p.finish(ec);
0460                 if( ec.failed() )
0461                     break;
0462             }
0463 
0464             // regardless of reaching EOF, we might have parsed a full JSON
0465             // document; if so, we successfully finish
0466             if( p.done() )
0467             {
0468                 jv = p.release();
0469                 return is;
0470             }
0471 
0472             // at this point we definitely have more input, specifically in
0473             // buf's internal buffer; we also definitely haven't parsed a whole
0474             // document
0475             std::streamsize available = buf.in_avail();
0476             // if this assert fails, the streambuf is buggy
0477             BOOST_ASSERT( available > 0 );
0478 
0479             available = ( std::min )(
0480                 static_cast<std::size_t>(available), sizeof(read_buf) );
0481             // we read from the internal buffer of buf into our buffer
0482             available = buf.sgetn( read_buf, available );
0483 
0484             std::size_t consumed = p.write_some(
0485                 read_buf, static_cast<std::size_t>(available), ec );
0486             // if the parser hasn't consumed the entire input we've took from
0487             // buf, we put the remaining data back; this should succeed,
0488             // because we only read data from buf's internal buffer
0489             while( consumed++ < static_cast<std::size_t>(available) )
0490             {
0491                 std::istream::int_type const status = buf.sungetc();
0492                 BOOST_ASSERT( status != Traits::eof() );
0493                 (void)status;
0494             }
0495 
0496             if( ec.failed() )
0497                 break;
0498         }
0499     }
0500 #ifndef BOOST_NO_EXCEPTIONS
0501     catch(...)
0502     {
0503         try
0504         {
0505             is.setstate(std::ios::badbit);
0506         }
0507         // we ignore the exception, because we need to throw the original
0508         // exception instead
0509         catch( std::ios::failure const& ) { }
0510 
0511         if( is.exceptions() & std::ios::badbit )
0512             throw;
0513     }
0514 #endif
0515 
0516     is.setstate(err | std::ios::failbit);
0517     return is;
0518 }
0519 
0520 std::istream&
0521 operator>>(
0522     std::istream& is,
0523     parse_options const& opts)
0524 {
0525     is.iword(parse_flags_xalloc) = to_bitmask(opts);
0526     is.iword(parse_depth_xalloc) = static_cast<long>(opts.max_depth);
0527     return is;
0528 }
0529 
0530 //----------------------------------------------------------
0531 //
0532 // private
0533 //
0534 //----------------------------------------------------------
0535 
0536 storage_ptr
0537 value::
0538 destroy() noexcept
0539 {
0540     switch(kind())
0541     {
0542     case json::kind::null:
0543     case json::kind::bool_:
0544     case json::kind::int64:
0545     case json::kind::uint64:
0546     case json::kind::double_:
0547         break;
0548 
0549     case json::kind::string:
0550     {
0551         auto sp = str_.storage();
0552         str_.~string();
0553         return sp;
0554     }
0555 
0556     case json::kind::array:
0557     {
0558         auto sp = arr_.storage();
0559         arr_.~array();
0560         return sp;
0561     }
0562 
0563     case json::kind::object:
0564     {
0565         auto sp = obj_.storage();
0566         obj_.~object();
0567         return sp;
0568     }
0569 
0570     }
0571     return std::move(sp_);
0572 }
0573 
0574 bool
0575 value::
0576 equal(value const& other) const noexcept
0577 {
0578     switch(kind())
0579     {
0580     default: // unreachable()?
0581     case json::kind::null:
0582         return other.kind() == json::kind::null;
0583 
0584     case json::kind::bool_:
0585         return
0586             other.kind() == json::kind::bool_ &&
0587             get_bool() == other.get_bool();
0588 
0589     case json::kind::int64:
0590         switch(other.kind())
0591         {
0592         case json::kind::int64:
0593             return get_int64() == other.get_int64();
0594         case json::kind::uint64:
0595             if(get_int64() < 0)
0596                 return false;
0597             return static_cast<std::uint64_t>(
0598                 get_int64()) == other.get_uint64();
0599         default:
0600             return false;
0601         }
0602 
0603     case json::kind::uint64:
0604         switch(other.kind())
0605         {
0606         case json::kind::uint64:
0607             return get_uint64() == other.get_uint64();
0608         case json::kind::int64:
0609             if(other.get_int64() < 0)
0610                 return false;
0611             return static_cast<std::uint64_t>(
0612                 other.get_int64()) == get_uint64();
0613         default:
0614             return false;
0615         }
0616 
0617     case json::kind::double_:
0618         return
0619             other.kind() == json::kind::double_ &&
0620             get_double() == other.get_double();
0621 
0622     case json::kind::string:
0623         return
0624             other.kind() == json::kind::string &&
0625             get_string() == other.get_string();
0626 
0627     case json::kind::array:
0628         return
0629             other.kind() == json::kind::array &&
0630             get_array() == other.get_array();
0631 
0632     case json::kind::object:
0633         return
0634             other.kind() == json::kind::object &&
0635             get_object() == other.get_object();
0636     }
0637 }
0638 
0639 //----------------------------------------------------------
0640 //
0641 // key_value_pair
0642 //
0643 //----------------------------------------------------------
0644 
0645 // empty keys point here
0646 BOOST_JSON_REQUIRE_CONST_INIT
0647 char const
0648 key_value_pair::empty_[1] = { 0 };
0649 
0650 key_value_pair::
0651 key_value_pair(
0652     pilfered<json::value> key,
0653     pilfered<json::value> value) noexcept
0654     : value_(value)
0655 {
0656     std::size_t len;
0657     key_ = access::release_key(key.get(), len);
0658     len_ = static_cast<std::uint32_t>(len);
0659 }
0660 
0661 key_value_pair::
0662 key_value_pair(
0663     key_value_pair const& other,
0664     storage_ptr sp)
0665     : value_(other.value_, std::move(sp))
0666 {
0667     auto p = reinterpret_cast<
0668         char*>(value_.storage()->
0669             allocate(other.len_ + 1,
0670                 alignof(char)));
0671     std::memcpy(
0672         p, other.key_, other.len_);
0673     len_ = other.len_;
0674     p[len_] = 0;
0675     key_ = p;
0676 }
0677 
0678 //----------------------------------------------------------
0679 
0680 namespace detail
0681 {
0682 
0683 std::size_t
0684 hash_value_impl( value const& jv ) noexcept
0685 {
0686     std::size_t seed = 0;
0687 
0688     kind const k = jv.kind();
0689     boost::hash_combine( seed, k != kind::int64 ? k : kind::uint64 );
0690 
0691     visit( value_hasher{seed}, jv );
0692     return seed;
0693 }
0694 
0695 } // namespace detail
0696 } // namespace json
0697 } // namespace boost
0698 
0699 //----------------------------------------------------------
0700 //
0701 // std::hash specialization
0702 //
0703 //----------------------------------------------------------
0704 
0705 std::size_t
0706 std::hash<::boost::json::value>::operator()(
0707     ::boost::json::value const& jv) const noexcept
0708 {
0709     return ::boost::hash< ::boost::json::value >()( jv );
0710 }
0711 
0712 //----------------------------------------------------------
0713 
0714 #endif