Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:54: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_ARRAY_IPP
0011 #define BOOST_JSON_IMPL_ARRAY_IPP
0012 
0013 #include <boost/container_hash/hash.hpp>
0014 #include <boost/json/array.hpp>
0015 #include <boost/json/pilfer.hpp>
0016 #include <boost/json/detail/except.hpp>
0017 #include <cstdlib>
0018 #include <limits>
0019 #include <new>
0020 #include <utility>
0021 
0022 namespace boost {
0023 namespace json {
0024 
0025 //----------------------------------------------------------
0026 
0027 constexpr array::table::table() = default;
0028 
0029 // empty arrays point here
0030 BOOST_JSON_REQUIRE_CONST_INIT
0031 array::table array::empty_;
0032 
0033 auto
0034 array::
0035 table::
0036 allocate(
0037     std::size_t capacity,
0038     storage_ptr const& sp) ->
0039         table*
0040 {
0041     BOOST_ASSERT(capacity > 0);
0042     if(capacity > array::max_size())
0043     {
0044         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0045         detail::throw_system_error( error::array_too_large, &loc );
0046     }
0047     auto p = reinterpret_cast<
0048         table*>(sp->allocate(
0049             sizeof(table) +
0050                 capacity * sizeof(value),
0051             alignof(value)));
0052     p->capacity = static_cast<
0053         std::uint32_t>(capacity);
0054     return p;
0055 }
0056 
0057 void
0058 array::
0059 table::
0060 deallocate(
0061     table* p,
0062     storage_ptr const& sp)
0063 {
0064     if(p->capacity == 0)
0065         return;
0066     sp->deallocate(p,
0067         sizeof(table) +
0068             p->capacity * sizeof(value),
0069         alignof(value));
0070 }
0071 
0072 //----------------------------------------------------------
0073 
0074 array::
0075 revert_insert::
0076 revert_insert(
0077     const_iterator pos,
0078     std::size_t n,
0079     array& arr)
0080     : arr_(&arr)
0081     , i_(pos - arr_->data())
0082     , n_(n)
0083 {
0084     BOOST_ASSERT(
0085         pos >= arr_->begin() &&
0086         pos <= arr_->end());
0087     if( n_ <= arr_->capacity() -
0088         arr_->size())
0089     {
0090         // fast path
0091         p = arr_->data() + i_;
0092         if(n_ == 0)
0093             return;
0094         relocate(
0095             p + n_,
0096             p,
0097             arr_->size() - i_);
0098         arr_->t_->size = static_cast<
0099             std::uint32_t>(
0100                 arr_->t_->size + n_);
0101         return;
0102     }
0103     if(n_ > max_size() - arr_->size())
0104     {
0105         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0106         detail::throw_system_error( error::array_too_large, &loc );
0107     }
0108     auto t = table::allocate(
0109         arr_->growth(arr_->size() + n_),
0110             arr_->sp_);
0111     t->size = static_cast<std::uint32_t>(
0112         arr_->size() + n_);
0113     p = &(*t)[0] + i_;
0114     relocate(
0115         &(*t)[0],
0116         arr_->data(),
0117         i_);
0118     relocate(
0119         &(*t)[i_ + n_],
0120         arr_->data() + i_,
0121         arr_->size() - i_);
0122     t = detail::exchange(arr_->t_, t);
0123     table::deallocate(t, arr_->sp_);
0124 }
0125 
0126 array::
0127 revert_insert::
0128 ~revert_insert()
0129 {
0130     if(! arr_)
0131         return;
0132     BOOST_ASSERT(n_ != 0);
0133     auto const pos =
0134         arr_->data() + i_;
0135     arr_->destroy(pos, p);
0136     arr_->t_->size = static_cast<
0137         std::uint32_t>(
0138             arr_->t_->size - n_);
0139     relocate(
0140         pos,
0141         pos + n_,
0142         arr_->size() - i_);
0143 }
0144 
0145 //----------------------------------------------------------
0146 
0147 void
0148 array::
0149 destroy(
0150     value* first, value* last) noexcept
0151 {
0152     if(sp_.is_not_shared_and_deallocate_is_trivial())
0153         return;
0154     while(last-- != first)
0155         last->~value();
0156 }
0157 
0158 void
0159 array::
0160 destroy() noexcept
0161 {
0162     if(sp_.is_not_shared_and_deallocate_is_trivial())
0163         return;
0164     auto last = end();
0165     auto const first = begin();
0166     while(last-- != first)
0167         last->~value();
0168     table::deallocate(t_, sp_);
0169 }
0170 
0171 //----------------------------------------------------------
0172 //
0173 // Special Members
0174 //
0175 //----------------------------------------------------------
0176 
0177 array::
0178 array(detail::unchecked_array&& ua)
0179     : sp_(ua.storage())
0180 {
0181     BOOST_STATIC_ASSERT(
0182         alignof(table) == alignof(value));
0183     if(ua.size() == 0)
0184     {
0185         t_ = &empty_;
0186         return;
0187     }
0188     t_= table::allocate(
0189         ua.size(), sp_);
0190     t_->size = static_cast<
0191         std::uint32_t>(ua.size());
0192     ua.relocate(data());
0193 }
0194 
0195 array::
0196 ~array() noexcept
0197 {
0198     destroy();
0199 }
0200 
0201 array::
0202 array(
0203     std::size_t count,
0204     value const& v,
0205     storage_ptr sp)
0206     : sp_(std::move(sp))
0207 {
0208     if(count == 0)
0209     {
0210         t_ = &empty_;
0211         return;
0212     }
0213     t_= table::allocate(
0214         count, sp_);
0215     t_->size = 0;
0216     revert_construct r(*this);
0217     while(count--)
0218     {
0219         ::new(end()) value(v, sp_);
0220         ++t_->size;
0221     }
0222     r.commit();
0223 }
0224 
0225 array::
0226 array(
0227     std::size_t count,
0228     storage_ptr sp)
0229     : sp_(std::move(sp))
0230 {
0231     if(count == 0)
0232     {
0233         t_ = &empty_;
0234         return;
0235     }
0236     t_ = table::allocate(
0237         count, sp_);
0238     t_->size = static_cast<
0239         std::uint32_t>(count);
0240     auto p = data();
0241     do
0242     {
0243         ::new(p++) value(sp_);
0244     }
0245     while(--count);
0246 }
0247 
0248 array::
0249 array(array const& other)
0250     : array(other, other.sp_)
0251 {
0252 }
0253 
0254 array::
0255 array(
0256     array const& other,
0257     storage_ptr sp)
0258     : sp_(std::move(sp))
0259 {
0260     if(other.empty())
0261     {
0262         t_ = &empty_;
0263         return;
0264     }
0265     t_ = table::allocate(
0266         other.size(), sp_);
0267     t_->size = 0;
0268     revert_construct r(*this);
0269     auto src = other.data();
0270     auto dest = data();
0271     auto const n = other.size();
0272     do
0273     {
0274         ::new(dest++) value(
0275             *src++, sp_);
0276         ++t_->size;
0277     }
0278     while(t_->size < n);
0279     r.commit();
0280 }
0281 
0282 array::
0283 array(
0284     array&& other,
0285     storage_ptr sp)
0286     : sp_(std::move(sp))
0287 {
0288     if(*sp_ == *other.sp_)
0289     {
0290         // same resource
0291         t_ = detail::exchange(
0292             other.t_, &empty_);
0293         return;
0294     }
0295     else if(other.empty())
0296     {
0297         t_ = &empty_;
0298         return;
0299     }
0300     // copy
0301     t_ = table::allocate(
0302         other.size(), sp_);
0303     t_->size = 0;
0304     revert_construct r(*this);
0305     auto src = other.data();
0306     auto dest = data();
0307     auto const n = other.size();
0308     do
0309     {
0310         ::new(dest++) value(
0311             *src++, sp_);
0312         ++t_->size;
0313     }
0314     while(t_->size < n);
0315     r.commit();
0316 }
0317 
0318 array::
0319 array(
0320     std::initializer_list<
0321         value_ref> init,
0322     storage_ptr sp)
0323     : sp_(std::move(sp))
0324 {
0325     if(init.size() == 0)
0326     {
0327         t_ = &empty_;
0328         return;
0329     }
0330     t_ = table::allocate(
0331         init.size(), sp_);
0332     t_->size = 0;
0333     revert_construct r(*this);
0334     value_ref::write_array(
0335         data(), init, sp_);
0336     t_->size = static_cast<
0337         std::uint32_t>(init.size());
0338     r.commit();
0339 }
0340 
0341 //----------------------------------------------------------
0342 
0343 array&
0344 array::
0345 operator=(array const& other)
0346 {
0347     array(other,
0348         storage()).swap(*this);
0349     return *this;
0350 }
0351 
0352 array&
0353 array::
0354 operator=(array&& other)
0355 {
0356     array(std::move(other),
0357         storage()).swap(*this);
0358     return *this;
0359 }
0360 
0361 array&
0362 array::
0363 operator=(
0364     std::initializer_list<value_ref> init)
0365 {
0366     array(init,
0367         storage()).swap(*this);
0368     return *this;
0369 }
0370 
0371 //----------------------------------------------------------
0372 //
0373 // Element access
0374 //
0375 //----------------------------------------------------------
0376 
0377 system::result<value&>
0378 array::try_at(std::size_t pos) noexcept
0379 {
0380     if(pos >= t_->size)
0381     {
0382         system::error_code ec;
0383         BOOST_JSON_FAIL(ec, error::out_of_range);
0384         return ec;
0385     }
0386     return (*t_)[pos];
0387 }
0388 
0389 system::result<value const&>
0390 array::try_at(std::size_t pos) const noexcept
0391 {
0392     if(pos >= t_->size)
0393     {
0394         system::error_code ec;
0395         BOOST_JSON_FAIL(ec, error::out_of_range);
0396         return ec;
0397     }
0398     return (*t_)[pos];
0399 }
0400 
0401 value const&
0402 array::
0403 array::at(std::size_t pos, source_location const& loc) const&
0404 {
0405     return try_at(pos).value(loc);
0406 }
0407 
0408 //----------------------------------------------------------
0409 //
0410 // Capacity
0411 //
0412 //----------------------------------------------------------
0413 
0414 void
0415 array::
0416 shrink_to_fit() noexcept
0417 {
0418     if(capacity() <= size())
0419         return;
0420     if(size() == 0)
0421     {
0422         table::deallocate(t_, sp_);
0423         t_ = &empty_;
0424         return;
0425     }
0426 
0427 #ifndef BOOST_NO_EXCEPTIONS
0428     try
0429     {
0430 #endif
0431         auto t = table::allocate(
0432             size(), sp_);
0433         relocate(
0434             &(*t)[0],
0435             data(),
0436             size());
0437         t->size = static_cast<
0438             std::uint32_t>(size());
0439         t = detail::exchange(
0440             t_, t);
0441         table::deallocate(t, sp_);
0442 #ifndef BOOST_NO_EXCEPTIONS
0443     }
0444     catch(...)
0445     {
0446         // eat the exception
0447         return;
0448     }
0449 #endif
0450 }
0451 
0452 //----------------------------------------------------------
0453 //
0454 // Modifiers
0455 //
0456 //----------------------------------------------------------
0457 
0458 void
0459 array::
0460 clear() noexcept
0461 {
0462     if(size() == 0)
0463         return;
0464     destroy(
0465         begin(), end());
0466     t_->size = 0;
0467 }
0468 
0469 auto
0470 array::
0471 insert(
0472     const_iterator pos,
0473     value const& v) ->
0474         iterator
0475 {
0476     return emplace(pos, v);
0477 }
0478 
0479 auto
0480 array::
0481 insert(
0482     const_iterator pos,
0483     value&& v) ->
0484         iterator
0485 {
0486     return emplace(pos, std::move(v));
0487 }
0488 
0489 auto
0490 array::
0491 insert(
0492     const_iterator pos,
0493     std::size_t count,
0494     value const& v) ->
0495         iterator
0496 {
0497     revert_insert r(
0498         pos, count, *this);
0499     while(count--)
0500     {
0501         ::new(r.p) value(v, sp_);
0502         ++r.p;
0503     }
0504     return r.commit();
0505 }
0506 
0507 auto
0508 array::
0509 insert(
0510     const_iterator pos,
0511     std::initializer_list<
0512         value_ref> init) ->
0513     iterator
0514 {
0515     revert_insert r(
0516         pos, init.size(), *this);
0517     value_ref::write_array(
0518         r.p, init, sp_);
0519     return r.commit();
0520 }
0521 
0522 auto
0523 array::
0524 erase(
0525     const_iterator pos) noexcept ->
0526     iterator
0527 {
0528     BOOST_ASSERT(
0529         pos >= begin() &&
0530         pos <= end());
0531     return erase(pos, pos + 1);
0532 }
0533 
0534 auto
0535 array::
0536 erase(
0537     const_iterator first,
0538     const_iterator last) noexcept ->
0539         iterator
0540 {
0541     BOOST_ASSERT(
0542         first >= begin() &&
0543         last >= first &&
0544         last <= end());
0545     std::size_t const n =
0546         last - first;
0547     auto const p = &(*t_)[0] +
0548         (first - &(*t_)[0]);
0549     destroy(p, p + n);
0550     relocate(p, p + n,
0551         t_->size - (last -
0552             &(*t_)[0]));
0553     t_->size = static_cast<
0554         std::uint32_t>(t_->size - n);
0555     return p;
0556 }
0557 
0558 void
0559 array::
0560 push_back(value const& v)
0561 {
0562     emplace_back(v);
0563 }
0564 
0565 void
0566 array::
0567 push_back(value&& v)
0568 {
0569     emplace_back(std::move(v));
0570 }
0571 
0572 void
0573 array::
0574 pop_back() noexcept
0575 {
0576     auto const p = &back();
0577     destroy(p, p + 1);
0578     --t_->size;
0579 }
0580 
0581 void
0582 array::
0583 resize(std::size_t count)
0584 {
0585     if(count <= t_->size)
0586     {
0587         // shrink
0588         destroy(
0589             &(*t_)[0] + count,
0590             &(*t_)[0] + t_->size);
0591         t_->size = static_cast<
0592             std::uint32_t>(count);
0593         return;
0594     }
0595 
0596     reserve(count);
0597     auto p = &(*t_)[t_->size];
0598     auto const end = &(*t_)[count];
0599     while(p != end)
0600         ::new(p++) value(sp_);
0601     t_->size = static_cast<
0602         std::uint32_t>(count);
0603 }
0604 
0605 void
0606 array::
0607 resize(
0608     std::size_t count,
0609     value const& v)
0610 {
0611     if(count <= size())
0612     {
0613         // shrink
0614         destroy(
0615             data() + count,
0616             data() + size());
0617         t_->size = static_cast<
0618             std::uint32_t>(count);
0619         return;
0620     }
0621     count -= size();
0622     revert_insert r(
0623         end(), count, *this);
0624     while(count--)
0625     {
0626         ::new(r.p) value(v, sp_);
0627         ++r.p;
0628     }
0629     r.commit();
0630 }
0631 
0632 void
0633 array::
0634 swap(array& other)
0635 {
0636     if(*sp_ == *other.sp_)
0637     {
0638         t_ = detail::exchange(
0639             other.t_, t_);
0640         return;
0641     }
0642     array temp1(
0643         std::move(*this),
0644         other.storage());
0645     array temp2(
0646         std::move(other),
0647         this->storage());
0648     this->~array();
0649     ::new(this) array(
0650         pilfer(temp2));
0651     other.~array();
0652     ::new(&other) array(
0653         pilfer(temp1));
0654 }
0655 
0656 //----------------------------------------------------------
0657 //
0658 // Private
0659 //
0660 //----------------------------------------------------------
0661 
0662 std::size_t
0663 array::
0664 growth(
0665     std::size_t new_size) const
0666 {
0667     if(new_size > max_size())
0668     {
0669         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0670         detail::throw_system_error( error::array_too_large, &loc );
0671     }
0672     std::size_t const old = capacity();
0673     if(old > max_size() - old / 2)
0674         return new_size;
0675     std::size_t const g =
0676         old + old / 2; // 1.5x
0677     if(g < new_size)
0678         return new_size;
0679     return g;
0680 }
0681 
0682 // precondition: new_capacity > capacity()
0683 void
0684 array::
0685 reserve_impl(
0686     std::size_t new_capacity)
0687 {
0688     BOOST_ASSERT(
0689         new_capacity > t_->capacity);
0690     auto t = table::allocate(
0691         growth(new_capacity), sp_);
0692     relocate(
0693         &(*t)[0],
0694         &(*t_)[0],
0695         t_->size);
0696     t->size = t_->size;
0697     t = detail::exchange(t_, t);
0698     table::deallocate(t, sp_);
0699 }
0700 
0701 // precondition: pv is not aliased
0702 value&
0703 array::
0704 push_back(
0705     pilfered<value> pv)
0706 {
0707     auto const n = t_->size;
0708     if(n < t_->capacity)
0709     {
0710         // fast path
0711         auto& v = *::new(
0712             &(*t_)[n]) value(pv);
0713         ++t_->size;
0714         return v;
0715     }
0716     auto const t =
0717         detail::exchange(t_,
0718             table::allocate(
0719                 growth(n + 1),
0720                     sp_));
0721     auto& v = *::new(
0722         &(*t_)[n]) value(pv);
0723     relocate(
0724         &(*t_)[0],
0725         &(*t)[0],
0726         n);
0727     t_->size = n + 1;
0728     table::deallocate(t, sp_);
0729     return v;
0730 }
0731 
0732 // precondition: pv is not aliased
0733 auto
0734 array::
0735 insert(
0736     const_iterator pos,
0737     pilfered<value> pv) ->
0738         iterator
0739 {
0740     BOOST_ASSERT(
0741         pos >= begin() &&
0742         pos <= end());
0743     std::size_t const n =
0744         t_->size;
0745     std::size_t const i =
0746         pos - &(*t_)[0];
0747     if(n < t_->capacity)
0748     {
0749         // fast path
0750         auto const p =
0751             &(*t_)[i];
0752         relocate(
0753             p + 1,
0754             p,
0755             n - i);
0756         ::new(p) value(pv);
0757         ++t_->size;
0758         return p;
0759     }
0760     auto t =
0761         table::allocate(
0762             growth(n + 1), sp_);
0763     auto const p = &(*t)[i];
0764     ::new(p) value(pv);
0765     relocate(
0766         &(*t)[0],
0767         &(*t_)[0],
0768         i);
0769     relocate(
0770         p + 1,
0771         &(*t_)[i],
0772         n - i);
0773     t->size = static_cast<
0774         std::uint32_t>(size() + 1);
0775     t = detail::exchange(t_, t);
0776     table::deallocate(t, sp_);
0777     return p;
0778 }
0779 
0780 //----------------------------------------------------------
0781 
0782 bool
0783 array::
0784 equal(
0785     array const& other) const noexcept
0786 {
0787     if(size() != other.size())
0788         return false;
0789     for(std::size_t i = 0; i < size(); ++i)
0790         if((*this)[i] != other[i])
0791             return false;
0792     return true;
0793 }
0794 
0795 } // namespace json
0796 } // namespace boost
0797 
0798 //----------------------------------------------------------
0799 //
0800 // std::hash specialization
0801 //
0802 //----------------------------------------------------------
0803 
0804 std::size_t
0805 std::hash<::boost::json::array>::operator()(
0806     ::boost::json::array const& ja) const noexcept
0807 {
0808     return ::boost::hash< ::boost::json::array >()( ja );
0809 }
0810 
0811 //----------------------------------------------------------
0812 
0813 #endif