Back to home page

EIC code displayed by LXR

 
 

    


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

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 auto
0364 object::
0365 at(string_view key) & ->
0366     value&
0367 {
0368     auto const& self = *this;
0369     return const_cast< value& >( self.at(key) );
0370 }
0371 
0372 auto
0373 object::
0374 at(string_view key) && ->
0375     value&&
0376 {
0377     return std::move( at(key) );
0378 }
0379 
0380 auto
0381 object::
0382 at(string_view key) const& ->
0383     value const&
0384 {
0385     auto it = find(key);
0386     if(it == end())
0387     {
0388         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0389         detail::throw_system_error( error::out_of_range, &loc );
0390     }
0391     return it->value();
0392 }
0393 
0394 //----------------------------------------------------------
0395 
0396 template<class P, class>
0397 auto
0398 object::
0399 insert(P&& p) ->
0400     std::pair<iterator, bool>
0401 {
0402     key_value_pair v(
0403         std::forward<P>(p), sp_);
0404     return emplace_impl( v.key(), pilfer(v) );
0405 }
0406 
0407 template<class M>
0408 auto
0409 object::
0410 insert_or_assign(
0411     string_view key, M&& m) ->
0412         std::pair<iterator, bool>
0413 {
0414     std::pair<iterator, bool> result = emplace_impl(
0415         key, key, static_cast<M&&>(m) );
0416     if( !result.second )
0417     {
0418         value(static_cast<M>(m), sp_).swap(
0419             result.first->value());
0420     }
0421     return result;
0422 }
0423 
0424 template<class Arg>
0425 auto
0426 object::
0427 emplace(
0428     string_view key,
0429     Arg&& arg) ->
0430         std::pair<iterator, bool>
0431 {
0432     return emplace_impl( key, key, static_cast<Arg&&>(arg) );
0433 }
0434 
0435 //----------------------------------------------------------
0436 //
0437 // (private)
0438 //
0439 //----------------------------------------------------------
0440 
0441 template<class InputIt>
0442 void
0443 object::
0444 construct(
0445     InputIt first,
0446     InputIt last,
0447     std::size_t min_capacity,
0448     std::input_iterator_tag)
0449 {
0450     reserve(min_capacity);
0451     revert_construct r(*this);
0452     while(first != last)
0453     {
0454         insert(*first);
0455         ++first;
0456     }
0457     r.commit();
0458 }
0459 
0460 template<class InputIt>
0461 void
0462 object::
0463 construct(
0464     InputIt first,
0465     InputIt last,
0466     std::size_t min_capacity,
0467     std::forward_iterator_tag)
0468 {
0469     auto n = static_cast<
0470         std::size_t>(std::distance(
0471             first, last));
0472     if( n < min_capacity)
0473         n = min_capacity;
0474     reserve(n);
0475     revert_construct r(*this);
0476     while(first != last)
0477     {
0478         insert(*first);
0479         ++first;
0480     }
0481     r.commit();
0482 }
0483 
0484 template<class InputIt>
0485 void
0486 object::
0487 insert(
0488     InputIt first,
0489     InputIt last,
0490     std::input_iterator_tag)
0491 {
0492     // Since input iterators cannot be rewound,
0493     // we keep inserted elements on an exception.
0494     //
0495     while(first != last)
0496     {
0497         insert(*first);
0498         ++first;
0499     }
0500 }
0501 
0502 template<class InputIt>
0503 void
0504 object::
0505 insert(
0506     InputIt first,
0507     InputIt last,
0508     std::forward_iterator_tag)
0509 {
0510     auto const n =
0511         static_cast<std::size_t>(
0512             std::distance(first, last));
0513     auto const n0 = size();
0514     if(n > max_size() - n0)
0515     {
0516         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0517         detail::throw_system_error( error::object_too_large, &loc );
0518     }
0519     revert_insert r( *this, n0 + n );
0520     while(first != last)
0521     {
0522         insert(*first);
0523         ++first;
0524     }
0525     r.commit();
0526 }
0527 
0528 template< class... Args >
0529 std::pair<object::iterator, bool>
0530 object::
0531 emplace_impl( string_view key, Args&& ... args )
0532 {
0533     std::pair<iterator, std::size_t> search_result(nullptr, 0);
0534     if( !empty() )
0535     {
0536         search_result = detail::find_in_object(*this, key);
0537         if( search_result.first )
0538             return { search_result.first, false };
0539     }
0540 
0541     // we create the new value before reserving, in case it is a reference to
0542     // a subobject of the current object
0543     key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
0544     // the key might get deallocated too
0545     key = kv.key();
0546 
0547     std::size_t const old_capacity = capacity();
0548     reserve(size() + 1);
0549     if( (empty() && capacity() > detail::small_object_size_)
0550             || (capacity() != old_capacity) )
0551         search_result.second = detail::digest(
0552             key.begin(), key.end(), t_->salt);
0553 
0554     BOOST_ASSERT(
0555         t_->is_small() ||
0556         (search_result.second ==
0557             detail::digest(key.begin(), key.end(), t_->salt)) );
0558 
0559     return { insert_impl(pilfer(kv), search_result.second), true };
0560 }
0561 
0562 //----------------------------------------------------------
0563 
0564 namespace detail {
0565 
0566 unchecked_object::
0567 ~unchecked_object()
0568 {
0569     if(! data_)
0570         return;
0571     if(sp_.is_not_shared_and_deallocate_is_trivial())
0572         return;
0573     value* p = data_;
0574     while(size_--)
0575     {
0576         p[0].~value();
0577         p[1].~value();
0578         p += 2;
0579     }
0580 }
0581 
0582 } // detail
0583 
0584 } // namespace json
0585 } // namespace boost
0586 
0587 #endif