Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-06-30 08:17:45

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_OBJECT_HPP
0011 #define BOOST_JSON_IMPL_OBJECT_HPP
0012 
0013 #include <boost/json/value.hpp>
0014 #include <iterator>
0015 #include <cmath>
0016 #include <type_traits>
0017 #include <utility>
0018 
0019 namespace boost {
0020 namespace json {
0021 
0022 namespace detail {
0023 
0024 // Objects with size less than or equal
0025 // to this number will use a linear search
0026 // instead of the more expensive hash function.
0027 static
0028 constexpr
0029 std::size_t
0030 small_object_size_ = 18;
0031 
0032 BOOST_STATIC_ASSERT(
0033     small_object_size_ <
0034     BOOST_JSON_MAX_STRUCTURED_SIZE);
0035 
0036 } // detail
0037 
0038 //----------------------------------------------------------
0039 
0040 struct alignas(key_value_pair)
0041     object::table
0042 {
0043     std::uint32_t size = 0;
0044     std::uint32_t capacity = 0;
0045     std::uintptr_t salt = 0;
0046 
0047 #if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
0048     // VFALCO If we make key_value_pair smaller,
0049     //        then we might want to revisit this
0050     //        padding.
0051     BOOST_STATIC_ASSERT(
0052         sizeof(key_value_pair) == 32);
0053     char pad[4] = {}; // silence warnings
0054 #endif
0055 
0056     constexpr table();
0057 
0058     // returns true if we use a linear
0059     // search instead of the hash table.
0060     bool is_small() const noexcept
0061     {
0062         return capacity <=
0063             detail::small_object_size_;
0064     }
0065 
0066     key_value_pair&
0067     operator[](
0068         std::size_t pos) noexcept
0069     {
0070         return reinterpret_cast<
0071             key_value_pair*>(
0072                 this + 1)[pos];
0073     }
0074 
0075     // VFALCO This is exported for tests
0076     BOOST_JSON_DECL
0077     std::size_t
0078     digest(string_view key) const noexcept;
0079 
0080     inline
0081     index_t&
0082     bucket(std::size_t hash) noexcept;
0083 
0084     inline
0085     index_t&
0086     bucket(string_view key) noexcept;
0087 
0088     inline
0089     void
0090     clear() noexcept;
0091 
0092     static
0093     inline
0094     table*
0095     allocate(
0096         std::size_t capacity,
0097         std::uintptr_t salt,
0098         storage_ptr const& sp);
0099 
0100     static
0101     void
0102     deallocate(
0103         table* p,
0104         storage_ptr const& sp) noexcept
0105     {
0106         if(p->capacity == 0)
0107             return;
0108         if(! p->is_small())
0109             sp->deallocate(p,
0110                 sizeof(table) + p->capacity * (
0111                     sizeof(key_value_pair) +
0112                     sizeof(index_t)));
0113         else
0114             sp->deallocate(p,
0115                 sizeof(table) + p->capacity *
0116                     sizeof(key_value_pair));
0117     }
0118 };
0119 
0120 //----------------------------------------------------------
0121 
0122 class object::revert_construct
0123 {
0124     object* obj_;
0125 
0126     BOOST_JSON_DECL
0127     void
0128     destroy() noexcept;
0129 
0130 public:
0131     explicit
0132     revert_construct(
0133         object& obj) noexcept
0134         : obj_(&obj)
0135     {
0136     }
0137 
0138     ~revert_construct()
0139     {
0140         if(! obj_)
0141             return;
0142         destroy();
0143     }
0144 
0145     void
0146     commit() noexcept
0147     {
0148         obj_ = nullptr;
0149     }
0150 };
0151 
0152 //----------------------------------------------------------
0153 
0154 class object::revert_insert
0155 {
0156     object* obj_;
0157     table* t_ = nullptr;
0158     std::size_t size_;
0159 
0160     BOOST_JSON_DECL
0161     void
0162     destroy() noexcept;
0163 
0164 public:
0165     explicit
0166     revert_insert(
0167         object& obj,
0168         std::size_t capacity)
0169         : obj_(&obj)
0170         , size_(obj_->size())
0171     {
0172         if( capacity > obj_->capacity() )
0173             t_ = obj_->reserve_impl(capacity);
0174     }
0175 
0176     ~revert_insert()
0177     {
0178         if(! obj_)
0179             return;
0180 
0181         destroy();
0182         if( t_ )
0183         {
0184             table::deallocate( obj_->t_, obj_->sp_ );
0185             obj_->t_ = t_;
0186         }
0187         else
0188         {
0189             obj_->t_->size = static_cast<index_t>(size_);
0190         }
0191     }
0192 
0193     void
0194     commit() noexcept
0195     {
0196         BOOST_ASSERT(obj_);
0197         if( t_ )
0198             table::deallocate( t_, obj_->sp_ );
0199         obj_ = nullptr;
0200     }
0201 };
0202 
0203 //----------------------------------------------------------
0204 //
0205 // Iterators
0206 //
0207 //----------------------------------------------------------
0208 
0209 auto
0210 object::
0211 begin() noexcept ->
0212     iterator
0213 {
0214     return &(*t_)[0];
0215 }
0216 
0217 auto
0218 object::
0219 begin() const noexcept ->
0220     const_iterator
0221 {
0222     return &(*t_)[0];
0223 }
0224 
0225 auto
0226 object::
0227 cbegin() const noexcept ->
0228     const_iterator
0229 {
0230     return &(*t_)[0];
0231 }
0232 
0233 auto
0234 object::
0235 end() noexcept ->
0236     iterator
0237 {
0238     return &(*t_)[t_->size];
0239 }
0240 
0241 auto
0242 object::
0243 end() const noexcept ->
0244     const_iterator
0245 {
0246     return &(*t_)[t_->size];
0247 }
0248 
0249 auto
0250 object::
0251 cend() const noexcept ->
0252     const_iterator
0253 {
0254     return &(*t_)[t_->size];
0255 }
0256 
0257 auto
0258 object::
0259 rbegin() noexcept ->
0260     reverse_iterator
0261 {
0262     return reverse_iterator(end());
0263 }
0264 
0265 auto
0266 object::
0267 rbegin() const noexcept ->
0268     const_reverse_iterator
0269 {
0270     return const_reverse_iterator(end());
0271 }
0272 
0273 auto
0274 object::
0275 crbegin() const noexcept ->
0276     const_reverse_iterator
0277 {
0278     return const_reverse_iterator(end());
0279 }
0280 
0281 auto
0282 object::
0283 rend() noexcept ->
0284     reverse_iterator
0285 {
0286     return reverse_iterator(begin());
0287 }
0288 
0289 auto
0290 object::
0291 rend() const noexcept ->
0292     const_reverse_iterator
0293 {
0294     return const_reverse_iterator(begin());
0295 }
0296 
0297 auto
0298 object::
0299 crend() const noexcept ->
0300     const_reverse_iterator
0301 {
0302     return const_reverse_iterator(begin());
0303 }
0304 
0305 //----------------------------------------------------------
0306 //
0307 // Capacity
0308 //
0309 //----------------------------------------------------------
0310 
0311 bool
0312 object::
0313 empty() const noexcept
0314 {
0315     return t_->size == 0;
0316 }
0317 
0318 auto
0319 object::
0320 size() const noexcept ->
0321     std::size_t
0322 {
0323     return t_->size;
0324 }
0325 
0326 constexpr
0327 std::size_t
0328 object::
0329 max_size() noexcept
0330 {
0331     // max_size depends on the address model
0332     using min = std::integral_constant<std::size_t,
0333         (std::size_t(-1) - sizeof(table)) /
0334             (sizeof(key_value_pair) + sizeof(index_t))>;
0335     return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
0336         min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
0337 }
0338 
0339 auto
0340 object::
0341 capacity() const noexcept ->
0342     std::size_t
0343 {
0344     return t_->capacity;
0345 }
0346 
0347 void
0348 object::
0349 reserve(std::size_t new_capacity)
0350 {
0351     if( new_capacity <= capacity() )
0352         return;
0353     table* const old_table = reserve_impl(new_capacity);
0354     table::deallocate( old_table, sp_ );
0355 }
0356 
0357 //----------------------------------------------------------
0358 //
0359 // Lookup
0360 //
0361 //----------------------------------------------------------
0362 
0363 value&
0364 object::
0365 at(string_view key, source_location const& loc) &
0366 {
0367     auto const& self = *this;
0368     return const_cast< value& >( self.at(key, loc) );
0369 }
0370 
0371 value&&
0372 object::
0373 at(string_view key, source_location const& loc) &&
0374 {
0375     return std::move( at(key, loc) );
0376 }
0377 
0378 //----------------------------------------------------------
0379 
0380 template<class P, class>
0381 auto
0382 object::
0383 insert(P&& p) ->
0384     std::pair<iterator, bool>
0385 {
0386     key_value_pair v(
0387         std::forward<P>(p), sp_);
0388     return emplace_impl( v.key(), pilfer(v) );
0389 }
0390 
0391 template<class M>
0392 auto
0393 object::
0394 insert_or_assign(
0395     string_view key, M&& m) ->
0396         std::pair<iterator, bool>
0397 {
0398     std::pair<iterator, bool> result = emplace_impl(
0399         key, key, static_cast<M&&>(m) );
0400     if( !result.second )
0401     {
0402         value(static_cast<M>(m), sp_).swap(
0403             result.first->value());
0404     }
0405     return result;
0406 }
0407 
0408 template<class Arg>
0409 auto
0410 object::
0411 emplace(
0412     string_view key,
0413     Arg&& arg) ->
0414         std::pair<iterator, bool>
0415 {
0416     return emplace_impl( key, key, static_cast<Arg&&>(arg) );
0417 }
0418 
0419 //----------------------------------------------------------
0420 //
0421 // (private)
0422 //
0423 //----------------------------------------------------------
0424 
0425 template<class InputIt>
0426 void
0427 object::
0428 construct(
0429     InputIt first,
0430     InputIt last,
0431     std::size_t min_capacity,
0432     std::input_iterator_tag)
0433 {
0434     reserve(min_capacity);
0435     revert_construct r(*this);
0436     while(first != last)
0437     {
0438         insert(*first);
0439         ++first;
0440     }
0441     r.commit();
0442 }
0443 
0444 template<class InputIt>
0445 void
0446 object::
0447 construct(
0448     InputIt first,
0449     InputIt last,
0450     std::size_t min_capacity,
0451     std::forward_iterator_tag)
0452 {
0453     auto n = static_cast<
0454         std::size_t>(std::distance(
0455             first, last));
0456     if( n < min_capacity)
0457         n = min_capacity;
0458     reserve(n);
0459     revert_construct r(*this);
0460     while(first != last)
0461     {
0462         insert(*first);
0463         ++first;
0464     }
0465     r.commit();
0466 }
0467 
0468 template<class InputIt>
0469 void
0470 object::
0471 insert(
0472     InputIt first,
0473     InputIt last,
0474     std::input_iterator_tag)
0475 {
0476     // Since input iterators cannot be rewound,
0477     // we keep inserted elements on an exception.
0478     //
0479     while(first != last)
0480     {
0481         insert(*first);
0482         ++first;
0483     }
0484 }
0485 
0486 template<class InputIt>
0487 void
0488 object::
0489 insert(
0490     InputIt first,
0491     InputIt last,
0492     std::forward_iterator_tag)
0493 {
0494     auto const n =
0495         static_cast<std::size_t>(
0496             std::distance(first, last));
0497     auto const n0 = size();
0498     if(n > max_size() - n0)
0499     {
0500         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0501         detail::throw_system_error( error::object_too_large, &loc );
0502     }
0503     revert_insert r( *this, n0 + n );
0504     while(first != last)
0505     {
0506         insert(*first);
0507         ++first;
0508     }
0509     r.commit();
0510 }
0511 
0512 template< class... Args >
0513 std::pair<object::iterator, bool>
0514 object::
0515 emplace_impl( string_view key, Args&& ... args )
0516 {
0517     std::pair<iterator, std::size_t> search_result(nullptr, 0);
0518     if( !empty() )
0519     {
0520         search_result = detail::find_in_object(*this, key);
0521         if( search_result.first )
0522             return { search_result.first, false };
0523     }
0524 
0525     // we create the new value before reserving, in case it is a reference to
0526     // a subobject of the current object
0527     key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
0528     // the key might get deallocated too
0529     key = kv.key();
0530 
0531     std::size_t const old_capacity = capacity();
0532     reserve(size() + 1);
0533     if( (empty() && capacity() > detail::small_object_size_)
0534             || (capacity() != old_capacity) )
0535         search_result.second = detail::digest(
0536             key.begin(), key.end(), t_->salt);
0537 
0538     BOOST_ASSERT(
0539         t_->is_small() ||
0540         (search_result.second ==
0541             detail::digest(key.begin(), key.end(), t_->salt)) );
0542 
0543     return { insert_impl(pilfer(kv), search_result.second), true };
0544 }
0545 
0546 //----------------------------------------------------------
0547 
0548 namespace detail {
0549 
0550 unchecked_object::
0551 ~unchecked_object()
0552 {
0553     if(! data_)
0554         return;
0555     if(sp_.is_not_shared_and_deallocate_is_trivial())
0556         return;
0557     value* p = data_;
0558     while(size_--)
0559     {
0560         p[0].~value();
0561         p[1].~value();
0562         p += 2;
0563     }
0564 }
0565 
0566 } // detail
0567 
0568 } // namespace json
0569 } // namespace boost
0570 
0571 #endif