File indexing completed on 2025-01-18 09:39:00
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) &
0208 {
0209 auto const& self = *this;
0210 return const_cast< value& >( self.at(pos) );
0211 }
0212
0213 value&&
0214 array::
0215 at(std::size_t pos) &&
0216 {
0217 return std::move( at(pos) );
0218 }
0219
0220 value const&
0221 array::
0222 at(std::size_t pos) const&
0223 {
0224 if(pos >= t_->size)
0225 {
0226 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0227 detail::throw_system_error( error::out_of_range, &loc );
0228 }
0229 return (*t_)[pos];
0230 }
0231
0232 value&
0233 array::
0234 operator[](std::size_t pos) & noexcept
0235 {
0236 BOOST_ASSERT(pos < t_->size);
0237 return (*t_)[pos];
0238 }
0239
0240 value&&
0241 array::
0242 operator[](std::size_t pos) && noexcept
0243 {
0244 return std::move( (*this)[pos] );
0245 }
0246
0247 value const&
0248 array::
0249 operator[](std::size_t pos) const& noexcept
0250 {
0251 BOOST_ASSERT(pos < t_->size);
0252 return (*t_)[pos];
0253 }
0254
0255 value&
0256 array::
0257 front() & noexcept
0258 {
0259 BOOST_ASSERT(t_->size > 0);
0260 return (*t_)[0];
0261 }
0262
0263 value&&
0264 array::
0265 front() && noexcept
0266 {
0267 return std::move( front() );
0268 }
0269
0270 value const&
0271 array::
0272 front() const& noexcept
0273 {
0274 BOOST_ASSERT(t_->size > 0);
0275 return (*t_)[0];
0276 }
0277
0278 value&
0279 array::
0280 back() & noexcept
0281 {
0282 BOOST_ASSERT(
0283 t_->size > 0);
0284 return (*t_)[t_->size - 1];
0285 }
0286
0287 value&&
0288 array::
0289 back() && noexcept
0290 {
0291 return std::move( back() );
0292 }
0293
0294 value const&
0295 array::
0296 back() const& noexcept
0297 {
0298 BOOST_ASSERT(
0299 t_->size > 0);
0300 return (*t_)[t_->size - 1];
0301 }
0302
0303 value*
0304 array::
0305 data() noexcept
0306 {
0307 return &(*t_)[0];
0308 }
0309
0310 value const*
0311 array::
0312 data() const noexcept
0313 {
0314 return &(*t_)[0];
0315 }
0316
0317 value const*
0318 array::
0319 if_contains(
0320 std::size_t pos) const noexcept
0321 {
0322 if( pos < t_->size )
0323 return &(*t_)[pos];
0324 return nullptr;
0325 }
0326
0327 value*
0328 array::
0329 if_contains(
0330 std::size_t pos) noexcept
0331 {
0332 if( pos < t_->size )
0333 return &(*t_)[pos];
0334 return nullptr;
0335 }
0336
0337
0338
0339
0340
0341
0342
0343 auto
0344 array::
0345 begin() noexcept ->
0346 iterator
0347 {
0348 return &(*t_)[0];
0349 }
0350
0351 auto
0352 array::
0353 begin() const noexcept ->
0354 const_iterator
0355 {
0356 return &(*t_)[0];
0357 }
0358
0359 auto
0360 array::
0361 cbegin() const noexcept ->
0362 const_iterator
0363 {
0364 return &(*t_)[0];
0365 }
0366
0367 auto
0368 array::
0369 end() noexcept ->
0370 iterator
0371 {
0372 return &(*t_)[t_->size];
0373 }
0374
0375 auto
0376 array::
0377 end() const noexcept ->
0378 const_iterator
0379 {
0380 return &(*t_)[t_->size];
0381 }
0382
0383 auto
0384 array::
0385 cend() const noexcept ->
0386 const_iterator
0387 {
0388 return &(*t_)[t_->size];
0389 }
0390
0391 auto
0392 array::
0393 rbegin() noexcept ->
0394 reverse_iterator
0395 {
0396 return reverse_iterator(end());
0397 }
0398
0399 auto
0400 array::
0401 rbegin() const noexcept ->
0402 const_reverse_iterator
0403 {
0404 return const_reverse_iterator(end());
0405 }
0406
0407 auto
0408 array::
0409 crbegin() const noexcept ->
0410 const_reverse_iterator
0411 {
0412 return const_reverse_iterator(end());
0413 }
0414
0415 auto
0416 array::
0417 rend() noexcept ->
0418 reverse_iterator
0419 {
0420 return reverse_iterator(begin());
0421 }
0422
0423 auto
0424 array::
0425 rend() const noexcept ->
0426 const_reverse_iterator
0427 {
0428 return const_reverse_iterator(begin());
0429 }
0430
0431 auto
0432 array::
0433 crend() const noexcept ->
0434 const_reverse_iterator
0435 {
0436 return const_reverse_iterator(begin());
0437 }
0438
0439
0440
0441
0442
0443
0444
0445 std::size_t
0446 array::
0447 size() const noexcept
0448 {
0449 return t_->size;
0450 }
0451
0452 constexpr
0453 std::size_t
0454 array::
0455 max_size() noexcept
0456 {
0457
0458 using min = std::integral_constant<std::size_t,
0459 (std::size_t(-1) - sizeof(table)) / sizeof(value)>;
0460 return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
0461 min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
0462 }
0463
0464 std::size_t
0465 array::
0466 capacity() const noexcept
0467 {
0468 return t_->capacity;
0469 }
0470
0471 bool
0472 array::
0473 empty() const noexcept
0474 {
0475 return t_->size == 0;
0476 }
0477
0478 void
0479 array::
0480 reserve(
0481 std::size_t new_capacity)
0482 {
0483
0484 if(new_capacity <= t_->capacity)
0485 return;
0486 reserve_impl(new_capacity);
0487 }
0488
0489
0490
0491
0492
0493
0494
0495 template<class InputIt>
0496 array::
0497 array(
0498 InputIt first, InputIt last,
0499 storage_ptr sp,
0500 std::input_iterator_tag)
0501 : sp_(std::move(sp))
0502 , t_(&empty_)
0503 {
0504 revert_construct r(*this);
0505 while(first != last)
0506 {
0507 reserve(size() + 1);
0508 ::new(end()) value(
0509 *first++, sp_);
0510 ++t_->size;
0511 }
0512 r.commit();
0513 }
0514
0515 template<class InputIt>
0516 array::
0517 array(
0518 InputIt first, InputIt last,
0519 storage_ptr sp,
0520 std::forward_iterator_tag)
0521 : sp_(std::move(sp))
0522 {
0523 std::size_t n =
0524 std::distance(first, last);
0525 if( n == 0 )
0526 {
0527 t_ = &empty_;
0528 return;
0529 }
0530
0531 t_ = table::allocate(n, sp_);
0532 t_->size = 0;
0533 revert_construct r(*this);
0534 while(n--)
0535 {
0536 ::new(end()) value(
0537 *first++, sp_);
0538 ++t_->size;
0539 }
0540 r.commit();
0541 }
0542
0543 template<class InputIt>
0544 auto
0545 array::
0546 insert(
0547 const_iterator pos,
0548 InputIt first, InputIt last,
0549 std::input_iterator_tag) ->
0550 iterator
0551 {
0552 BOOST_ASSERT(
0553 pos >= begin() && pos <= end());
0554 if(first == last)
0555 return data() + (pos - data());
0556 array temp(first, last, sp_);
0557 revert_insert r(
0558 pos, temp.size(), *this);
0559 relocate(
0560 r.p,
0561 temp.data(),
0562 temp.size());
0563 temp.t_->size = 0;
0564 return r.commit();
0565 }
0566
0567 template<class InputIt>
0568 auto
0569 array::
0570 insert(
0571 const_iterator pos,
0572 InputIt first, InputIt last,
0573 std::forward_iterator_tag) ->
0574 iterator
0575 {
0576 std::size_t n =
0577 std::distance(first, last);
0578 revert_insert r(pos, n, *this);
0579 while(n--)
0580 {
0581 ::new(r.p) value(*first++);
0582 ++r.p;
0583 }
0584 return r.commit();
0585 }
0586
0587 }
0588 }
0589
0590 #endif