File indexing completed on 2025-12-16 09:54:00
0001
0002
0003
0004
0005
0006
0007
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
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
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
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
0291 t_ = detail::exchange(
0292 other.t_, &empty_);
0293 return;
0294 }
0295 else if(other.empty())
0296 {
0297 t_ = &empty_;
0298 return;
0299 }
0300
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
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
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
0447 return;
0448 }
0449 #endif
0450 }
0451
0452
0453
0454
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
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
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
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;
0677 if(g < new_size)
0678 return new_size;
0679 return g;
0680 }
0681
0682
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
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
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
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
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 }
0796 }
0797
0798
0799
0800
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