File indexing completed on 2025-01-18 09:39:01
0001
0002
0003
0004
0005
0006
0007
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
0025
0026
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 }
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
0049
0050
0051 BOOST_STATIC_ASSERT(
0052 sizeof(key_value_pair) == 32);
0053 char pad[4] = {};
0054 #endif
0055
0056 constexpr table();
0057
0058
0059
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
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
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
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
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
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
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
0493
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
0542
0543 key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
0544
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 }
0583
0584 }
0585 }
0586
0587 #endif