File indexing completed on 2025-07-02 08:16:04
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_JSON_IMPL_ARRAY_HPP
0011 #define BOOST_JSON_IMPL_ARRAY_HPP
0012
0013 #include <boost/json/value.hpp>
0014 #include <boost/json/detail/except.hpp>
0015 #include <algorithm>
0016 #include <stdexcept>
0017 #include <type_traits>
0018
0019 namespace boost {
0020 namespace json {
0021
0022
0023
0024 struct alignas(value)
0025 array::table
0026 {
0027 std::uint32_t size = 0;
0028 std::uint32_t capacity = 0;
0029
0030 constexpr table();
0031
0032 value&
0033 operator[](std::size_t pos) noexcept
0034 {
0035 return (reinterpret_cast<
0036 value*>(this + 1))[pos];
0037 }
0038
0039 BOOST_JSON_DECL
0040 static
0041 table*
0042 allocate(
0043 std::size_t capacity,
0044 storage_ptr const& sp);
0045
0046 BOOST_JSON_DECL
0047 static
0048 void
0049 deallocate(
0050 table* p,
0051 storage_ptr const& sp);
0052 };
0053
0054
0055
0056 class array::revert_construct
0057 {
0058 array* arr_;
0059
0060 public:
0061 explicit
0062 revert_construct(
0063 array& arr) noexcept
0064 : arr_(&arr)
0065 {
0066 }
0067
0068 ~revert_construct()
0069 {
0070 if(! arr_)
0071 return;
0072 arr_->destroy();
0073 }
0074
0075 void
0076 commit() noexcept
0077 {
0078 arr_ = nullptr;
0079 }
0080 };
0081
0082
0083
0084 class array::revert_insert
0085 {
0086 array* arr_;
0087 std::size_t const i_;
0088 std::size_t const n_;
0089
0090 public:
0091 value* p;
0092
0093 BOOST_JSON_DECL
0094 revert_insert(
0095 const_iterator pos,
0096 std::size_t n,
0097 array& arr);
0098
0099 BOOST_JSON_DECL
0100 ~revert_insert();
0101
0102 value*
0103 commit() noexcept
0104 {
0105 auto it =
0106 arr_->data() + i_;
0107 arr_ = nullptr;
0108 return it;
0109 }
0110 };
0111
0112
0113
0114 void
0115 array::
0116 relocate(
0117 value* dest,
0118 value* src,
0119 std::size_t n) noexcept
0120 {
0121 if(n == 0)
0122 return;
0123 std::memmove(
0124 static_cast<void*>(dest),
0125 static_cast<void const*>(src),
0126 n * sizeof(value));
0127 }
0128
0129
0130
0131
0132
0133
0134
0135 template<class InputIt, class>
0136 array::
0137 array(
0138 InputIt first, InputIt last,
0139 storage_ptr sp)
0140 : array(
0141 first, last,
0142 std::move(sp),
0143 iter_cat<InputIt>{})
0144 {
0145 BOOST_STATIC_ASSERT(
0146 std::is_constructible<value,
0147 decltype(*first)>::value);
0148 }
0149
0150
0151
0152
0153
0154
0155
0156 template<class InputIt, class>
0157 auto
0158 array::
0159 insert(
0160 const_iterator pos,
0161 InputIt first, InputIt last) ->
0162 iterator
0163 {
0164 BOOST_STATIC_ASSERT(
0165 std::is_constructible<value,
0166 decltype(*first)>::value);
0167 return insert(pos, first, last,
0168 iter_cat<InputIt>{});
0169 }
0170
0171 template<class Arg>
0172 auto
0173 array::
0174 emplace(
0175 const_iterator pos,
0176 Arg&& arg) ->
0177 iterator
0178 {
0179 BOOST_ASSERT(
0180 pos >= begin() &&
0181 pos <= end());
0182 value jv(
0183 std::forward<Arg>(arg),
0184 storage());
0185 return insert(pos, pilfer(jv));
0186 }
0187
0188 template<class Arg>
0189 value&
0190 array::
0191 emplace_back(Arg&& arg)
0192 {
0193 value jv(
0194 std::forward<Arg>(arg),
0195 storage());
0196 return push_back(pilfer(jv));
0197 }
0198
0199
0200
0201
0202
0203
0204
0205 value&
0206 array::
0207 at(std::size_t pos, source_location const& loc) &
0208 {
0209 auto const& self = *this;
0210 return const_cast< value& >( self.at(pos, loc) );
0211 }
0212
0213 value&&
0214 array::
0215 at(std::size_t pos, source_location const& loc) &&
0216 {
0217 return std::move( at(pos, loc) );
0218 }
0219
0220 value&
0221 array::
0222 operator[](std::size_t pos) & noexcept
0223 {
0224 BOOST_ASSERT(pos < t_->size);
0225 return (*t_)[pos];
0226 }
0227
0228 value&&
0229 array::
0230 operator[](std::size_t pos) && noexcept
0231 {
0232 return std::move( (*this)[pos] );
0233 }
0234
0235 value const&
0236 array::
0237 operator[](std::size_t pos) const& noexcept
0238 {
0239 BOOST_ASSERT(pos < t_->size);
0240 return (*t_)[pos];
0241 }
0242
0243 value&
0244 array::
0245 front() & noexcept
0246 {
0247 BOOST_ASSERT(t_->size > 0);
0248 return (*t_)[0];
0249 }
0250
0251 value&&
0252 array::
0253 front() && noexcept
0254 {
0255 return std::move( front() );
0256 }
0257
0258 value const&
0259 array::
0260 front() const& noexcept
0261 {
0262 BOOST_ASSERT(t_->size > 0);
0263 return (*t_)[0];
0264 }
0265
0266 value&
0267 array::
0268 back() & noexcept
0269 {
0270 BOOST_ASSERT(
0271 t_->size > 0);
0272 return (*t_)[t_->size - 1];
0273 }
0274
0275 value&&
0276 array::
0277 back() && noexcept
0278 {
0279 return std::move( back() );
0280 }
0281
0282 value const&
0283 array::
0284 back() const& noexcept
0285 {
0286 BOOST_ASSERT(
0287 t_->size > 0);
0288 return (*t_)[t_->size - 1];
0289 }
0290
0291 value*
0292 array::
0293 data() noexcept
0294 {
0295 return &(*t_)[0];
0296 }
0297
0298 value const*
0299 array::
0300 data() const noexcept
0301 {
0302 return &(*t_)[0];
0303 }
0304
0305 value const*
0306 array::
0307 if_contains(
0308 std::size_t pos) const noexcept
0309 {
0310 if( pos < t_->size )
0311 return &(*t_)[pos];
0312 return nullptr;
0313 }
0314
0315 value*
0316 array::
0317 if_contains(
0318 std::size_t pos) noexcept
0319 {
0320 if( pos < t_->size )
0321 return &(*t_)[pos];
0322 return nullptr;
0323 }
0324
0325
0326
0327
0328
0329
0330
0331 auto
0332 array::
0333 begin() noexcept ->
0334 iterator
0335 {
0336 return &(*t_)[0];
0337 }
0338
0339 auto
0340 array::
0341 begin() const noexcept ->
0342 const_iterator
0343 {
0344 return &(*t_)[0];
0345 }
0346
0347 auto
0348 array::
0349 cbegin() const noexcept ->
0350 const_iterator
0351 {
0352 return &(*t_)[0];
0353 }
0354
0355 auto
0356 array::
0357 end() noexcept ->
0358 iterator
0359 {
0360 return &(*t_)[t_->size];
0361 }
0362
0363 auto
0364 array::
0365 end() const noexcept ->
0366 const_iterator
0367 {
0368 return &(*t_)[t_->size];
0369 }
0370
0371 auto
0372 array::
0373 cend() const noexcept ->
0374 const_iterator
0375 {
0376 return &(*t_)[t_->size];
0377 }
0378
0379 auto
0380 array::
0381 rbegin() noexcept ->
0382 reverse_iterator
0383 {
0384 return reverse_iterator(end());
0385 }
0386
0387 auto
0388 array::
0389 rbegin() const noexcept ->
0390 const_reverse_iterator
0391 {
0392 return const_reverse_iterator(end());
0393 }
0394
0395 auto
0396 array::
0397 crbegin() const noexcept ->
0398 const_reverse_iterator
0399 {
0400 return const_reverse_iterator(end());
0401 }
0402
0403 auto
0404 array::
0405 rend() noexcept ->
0406 reverse_iterator
0407 {
0408 return reverse_iterator(begin());
0409 }
0410
0411 auto
0412 array::
0413 rend() const noexcept ->
0414 const_reverse_iterator
0415 {
0416 return const_reverse_iterator(begin());
0417 }
0418
0419 auto
0420 array::
0421 crend() const noexcept ->
0422 const_reverse_iterator
0423 {
0424 return const_reverse_iterator(begin());
0425 }
0426
0427
0428
0429
0430
0431
0432
0433 std::size_t
0434 array::
0435 size() const noexcept
0436 {
0437 return t_->size;
0438 }
0439
0440 constexpr
0441 std::size_t
0442 array::
0443 max_size() noexcept
0444 {
0445
0446 using min = std::integral_constant<std::size_t,
0447 (std::size_t(-1) - sizeof(table)) / sizeof(value)>;
0448 return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
0449 min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
0450 }
0451
0452 std::size_t
0453 array::
0454 capacity() const noexcept
0455 {
0456 return t_->capacity;
0457 }
0458
0459 bool
0460 array::
0461 empty() const noexcept
0462 {
0463 return t_->size == 0;
0464 }
0465
0466 void
0467 array::
0468 reserve(
0469 std::size_t new_capacity)
0470 {
0471
0472 if(new_capacity <= t_->capacity)
0473 return;
0474 reserve_impl(new_capacity);
0475 }
0476
0477
0478
0479
0480
0481
0482
0483 template<class InputIt>
0484 array::
0485 array(
0486 InputIt first, InputIt last,
0487 storage_ptr sp,
0488 std::input_iterator_tag)
0489 : sp_(std::move(sp))
0490 , t_(&empty_)
0491 {
0492 revert_construct r(*this);
0493 while(first != last)
0494 {
0495 reserve(size() + 1);
0496 ::new(end()) value(
0497 *first++, sp_);
0498 ++t_->size;
0499 }
0500 r.commit();
0501 }
0502
0503 template<class InputIt>
0504 array::
0505 array(
0506 InputIt first, InputIt last,
0507 storage_ptr sp,
0508 std::forward_iterator_tag)
0509 : sp_(std::move(sp))
0510 {
0511 std::size_t n =
0512 std::distance(first, last);
0513 if( n == 0 )
0514 {
0515 t_ = &empty_;
0516 return;
0517 }
0518
0519 t_ = table::allocate(n, sp_);
0520 t_->size = 0;
0521 revert_construct r(*this);
0522 while(n--)
0523 {
0524 ::new(end()) value(
0525 *first++, sp_);
0526 ++t_->size;
0527 }
0528 r.commit();
0529 }
0530
0531 template<class InputIt>
0532 auto
0533 array::
0534 insert(
0535 const_iterator pos,
0536 InputIt first, InputIt last,
0537 std::input_iterator_tag) ->
0538 iterator
0539 {
0540 BOOST_ASSERT(
0541 pos >= begin() && pos <= end());
0542 if(first == last)
0543 return data() + (pos - data());
0544 array temp(first, last, sp_);
0545 revert_insert r(
0546 pos, temp.size(), *this);
0547 relocate(
0548 r.p,
0549 temp.data(),
0550 temp.size());
0551 temp.t_->size = 0;
0552 return r.commit();
0553 }
0554
0555 template<class InputIt>
0556 auto
0557 array::
0558 insert(
0559 const_iterator pos,
0560 InputIt first, InputIt last,
0561 std::forward_iterator_tag) ->
0562 iterator
0563 {
0564 std::size_t n =
0565 std::distance(first, last);
0566 revert_insert r(pos, n, *this);
0567 while(n--)
0568 {
0569 ::new(r.p) value(*first++);
0570 ++r.p;
0571 }
0572 return r.commit();
0573 }
0574
0575 }
0576 }
0577
0578 #endif