File indexing completed on 2025-06-30 08:17:45
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 value&
0364 object::
0365 at(string_view key, source_location const& loc) &
0366 {
0367 auto const& self = *this;
0368 return const_cast< value& >( self.at(key, loc) );
0369 }
0370
0371 value&&
0372 object::
0373 at(string_view key, source_location const& loc) &&
0374 {
0375 return std::move( at(key, loc) );
0376 }
0377
0378
0379
0380 template<class P, class>
0381 auto
0382 object::
0383 insert(P&& p) ->
0384 std::pair<iterator, bool>
0385 {
0386 key_value_pair v(
0387 std::forward<P>(p), sp_);
0388 return emplace_impl( v.key(), pilfer(v) );
0389 }
0390
0391 template<class M>
0392 auto
0393 object::
0394 insert_or_assign(
0395 string_view key, M&& m) ->
0396 std::pair<iterator, bool>
0397 {
0398 std::pair<iterator, bool> result = emplace_impl(
0399 key, key, static_cast<M&&>(m) );
0400 if( !result.second )
0401 {
0402 value(static_cast<M>(m), sp_).swap(
0403 result.first->value());
0404 }
0405 return result;
0406 }
0407
0408 template<class Arg>
0409 auto
0410 object::
0411 emplace(
0412 string_view key,
0413 Arg&& arg) ->
0414 std::pair<iterator, bool>
0415 {
0416 return emplace_impl( key, key, static_cast<Arg&&>(arg) );
0417 }
0418
0419
0420
0421
0422
0423
0424
0425 template<class InputIt>
0426 void
0427 object::
0428 construct(
0429 InputIt first,
0430 InputIt last,
0431 std::size_t min_capacity,
0432 std::input_iterator_tag)
0433 {
0434 reserve(min_capacity);
0435 revert_construct r(*this);
0436 while(first != last)
0437 {
0438 insert(*first);
0439 ++first;
0440 }
0441 r.commit();
0442 }
0443
0444 template<class InputIt>
0445 void
0446 object::
0447 construct(
0448 InputIt first,
0449 InputIt last,
0450 std::size_t min_capacity,
0451 std::forward_iterator_tag)
0452 {
0453 auto n = static_cast<
0454 std::size_t>(std::distance(
0455 first, last));
0456 if( n < min_capacity)
0457 n = min_capacity;
0458 reserve(n);
0459 revert_construct r(*this);
0460 while(first != last)
0461 {
0462 insert(*first);
0463 ++first;
0464 }
0465 r.commit();
0466 }
0467
0468 template<class InputIt>
0469 void
0470 object::
0471 insert(
0472 InputIt first,
0473 InputIt last,
0474 std::input_iterator_tag)
0475 {
0476
0477
0478
0479 while(first != last)
0480 {
0481 insert(*first);
0482 ++first;
0483 }
0484 }
0485
0486 template<class InputIt>
0487 void
0488 object::
0489 insert(
0490 InputIt first,
0491 InputIt last,
0492 std::forward_iterator_tag)
0493 {
0494 auto const n =
0495 static_cast<std::size_t>(
0496 std::distance(first, last));
0497 auto const n0 = size();
0498 if(n > max_size() - n0)
0499 {
0500 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0501 detail::throw_system_error( error::object_too_large, &loc );
0502 }
0503 revert_insert r( *this, n0 + n );
0504 while(first != last)
0505 {
0506 insert(*first);
0507 ++first;
0508 }
0509 r.commit();
0510 }
0511
0512 template< class... Args >
0513 std::pair<object::iterator, bool>
0514 object::
0515 emplace_impl( string_view key, Args&& ... args )
0516 {
0517 std::pair<iterator, std::size_t> search_result(nullptr, 0);
0518 if( !empty() )
0519 {
0520 search_result = detail::find_in_object(*this, key);
0521 if( search_result.first )
0522 return { search_result.first, false };
0523 }
0524
0525
0526
0527 key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
0528
0529 key = kv.key();
0530
0531 std::size_t const old_capacity = capacity();
0532 reserve(size() + 1);
0533 if( (empty() && capacity() > detail::small_object_size_)
0534 || (capacity() != old_capacity) )
0535 search_result.second = detail::digest(
0536 key.begin(), key.end(), t_->salt);
0537
0538 BOOST_ASSERT(
0539 t_->is_small() ||
0540 (search_result.second ==
0541 detail::digest(key.begin(), key.end(), t_->salt)) );
0542
0543 return { insert_impl(pilfer(kv), search_result.second), true };
0544 }
0545
0546
0547
0548 namespace detail {
0549
0550 unchecked_object::
0551 ~unchecked_object()
0552 {
0553 if(! data_)
0554 return;
0555 if(sp_.is_not_shared_and_deallocate_is_trivial())
0556 return;
0557 value* p = data_;
0558 while(size_--)
0559 {
0560 p[0].~value();
0561 p[1].~value();
0562 p += 2;
0563 }
0564 }
0565
0566 }
0567
0568 }
0569 }
0570
0571 #endif