File indexing completed on 2025-01-18 09:39:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #ifndef BOOST_JSON_IMPL_VALUE_STACK_IPP
0011 #define BOOST_JSON_IMPL_VALUE_STACK_IPP
0012
0013 #include <boost/json/value_stack.hpp>
0014 #include <cstring>
0015 #include <stdexcept>
0016 #include <utility>
0017
0018 namespace boost {
0019 namespace json {
0020
0021
0022
0023 value_stack::
0024 stack::
0025 ~stack()
0026 {
0027 clear();
0028 if( begin_ != temp_ &&
0029 begin_ != nullptr)
0030 sp_->deallocate(
0031 begin_,
0032 (end_ - begin_) *
0033 sizeof(value));
0034 }
0035
0036 value_stack::
0037 stack::
0038 stack(
0039 storage_ptr sp,
0040 void* temp,
0041 std::size_t size) noexcept
0042 : sp_(std::move(sp))
0043 , temp_(temp)
0044 {
0045 if(size >= min_size_ *
0046 sizeof(value))
0047 {
0048 begin_ = reinterpret_cast<
0049 value*>(temp);
0050 top_ = begin_;
0051 end_ = begin_ +
0052 size / sizeof(value);
0053 }
0054 else
0055 {
0056 begin_ = nullptr;
0057 top_ = nullptr;
0058 end_ = nullptr;
0059 }
0060 }
0061
0062 void
0063 value_stack::
0064 stack::
0065 run_dtors(bool b) noexcept
0066 {
0067 run_dtors_ = b;
0068 }
0069
0070 std::size_t
0071 value_stack::
0072 stack::
0073 size() const noexcept
0074 {
0075 return top_ - begin_;
0076 }
0077
0078 bool
0079 value_stack::
0080 stack::
0081 has_chars()
0082 {
0083 return chars_ != 0;
0084 }
0085
0086
0087
0088
0089
0090 void
0091 value_stack::
0092 stack::
0093 clear() noexcept
0094 {
0095 if(top_ != begin_)
0096 {
0097 if(run_dtors_)
0098 for(auto it = top_;
0099 it-- != begin_;)
0100 it->~value();
0101 top_ = begin_;
0102 }
0103 chars_ = 0;
0104 }
0105
0106 void
0107 value_stack::
0108 stack::
0109 maybe_grow()
0110 {
0111 if(top_ >= end_)
0112 grow_one();
0113 }
0114
0115
0116 void
0117 value_stack::
0118 stack::
0119 grow_one()
0120 {
0121 BOOST_ASSERT(chars_ == 0);
0122 std::size_t const capacity =
0123 end_ - begin_;
0124 std::size_t new_cap = min_size_;
0125
0126 while(new_cap < capacity + 1)
0127 new_cap <<= 1;
0128 auto const begin =
0129 reinterpret_cast<value*>(
0130 sp_->allocate(
0131 new_cap * sizeof(value)));
0132 std::size_t const cur_size = top_ - begin_;
0133 if(begin_)
0134 {
0135 std::memcpy(
0136 reinterpret_cast<char*>(begin),
0137 reinterpret_cast<char*>(begin_),
0138 size() * sizeof(value));
0139 if(begin_ != temp_)
0140 sp_->deallocate(begin_,
0141 capacity * sizeof(value));
0142 }
0143
0144 top_ = begin + cur_size;
0145 end_ = begin + new_cap;
0146 begin_ = begin;
0147 }
0148
0149
0150 void
0151 value_stack::
0152 stack::
0153 grow(std::size_t nchars)
0154 {
0155
0156 std::size_t const needed =
0157 size() +
0158 1 +
0159 ((chars_ + nchars +
0160 sizeof(value) - 1) /
0161 sizeof(value));
0162 std::size_t const capacity =
0163 end_ - begin_;
0164 BOOST_ASSERT(
0165 needed > capacity);
0166 std::size_t new_cap = min_size_;
0167
0168 while(new_cap < needed)
0169 new_cap <<= 1;
0170 auto const begin =
0171 reinterpret_cast<value*>(
0172 sp_->allocate(
0173 new_cap * sizeof(value)));
0174 std::size_t const cur_size = top_ - begin_;
0175 if(begin_)
0176 {
0177 std::size_t amount =
0178 size() * sizeof(value);
0179 if(chars_ > 0)
0180 amount += sizeof(value) + chars_;
0181 std::memcpy(
0182 reinterpret_cast<char*>(begin),
0183 reinterpret_cast<char*>(begin_),
0184 amount);
0185 if(begin_ != temp_)
0186 sp_->deallocate(begin_,
0187 capacity * sizeof(value));
0188 }
0189
0190 top_ = begin + cur_size;
0191 end_ = begin + new_cap;
0192 begin_ = begin;
0193 }
0194
0195
0196
0197 void
0198 value_stack::
0199 stack::
0200 append(string_view s)
0201 {
0202 std::size_t const bytes_avail =
0203 reinterpret_cast<
0204 char const*>(end_) -
0205 reinterpret_cast<
0206 char const*>(top_);
0207
0208
0209
0210 if(sizeof(value) + chars_ +
0211 s.size() > bytes_avail)
0212 grow(s.size());
0213
0214
0215 std::memcpy(
0216 reinterpret_cast<char*>(
0217 top_ + 1) + chars_,
0218 s.data(), s.size());
0219 chars_ += s.size();
0220
0221
0222
0223 BOOST_ASSERT(
0224 reinterpret_cast<char*>(
0225 top_ + 1) + chars_ <=
0226 reinterpret_cast<char*>(
0227 end_));
0228 }
0229
0230 string_view
0231 value_stack::
0232 stack::
0233 release_string() noexcept
0234 {
0235
0236
0237 BOOST_ASSERT(
0238 reinterpret_cast<char*>(
0239 top_ + 1) + chars_ <=
0240 reinterpret_cast<char*>(
0241 end_));
0242 auto const n = chars_;
0243 chars_ = 0;
0244 return { reinterpret_cast<
0245 char const*>(top_ + 1), n };
0246 }
0247
0248
0249
0250 value*
0251 value_stack::
0252 stack::
0253 release(std::size_t n) noexcept
0254 {
0255 BOOST_ASSERT(n <= size());
0256 BOOST_ASSERT(chars_ == 0);
0257 top_ -= n;
0258 return top_;
0259 }
0260
0261 template<class... Args>
0262 value&
0263 value_stack::
0264 stack::
0265 push(Args&&... args)
0266 {
0267 BOOST_ASSERT(chars_ == 0);
0268 if(top_ >= end_)
0269 grow_one();
0270 value& jv = detail::access::
0271 construct_value(top_,
0272 std::forward<Args>(args)...);
0273 ++top_;
0274 return jv;
0275 }
0276
0277 template<class Unchecked>
0278 void
0279 value_stack::
0280 stack::
0281 exchange(Unchecked&& u)
0282 {
0283 BOOST_ASSERT(chars_ == 0);
0284 union U
0285 {
0286 value v;
0287 U() {}
0288 ~U() {}
0289 } jv;
0290
0291
0292
0293 detail::access::
0294 construct_value(
0295 &jv.v, std::move(u));
0296 std::memcpy(
0297 reinterpret_cast<
0298 char*>(top_),
0299 &jv.v, sizeof(value));
0300 ++top_;
0301 }
0302
0303
0304
0305 value_stack::
0306 ~value_stack()
0307 {
0308
0309
0310
0311 }
0312
0313 value_stack::
0314 value_stack(
0315 storage_ptr sp,
0316 unsigned char* temp_buffer,
0317 std::size_t temp_size) noexcept
0318 : st_(
0319 std::move(sp),
0320 temp_buffer,
0321 temp_size)
0322 {
0323 }
0324
0325 void
0326 value_stack::
0327 reset(storage_ptr sp) noexcept
0328 {
0329 st_.clear();
0330
0331 sp_.~storage_ptr();
0332 ::new(&sp_) storage_ptr(
0333 pilfer(sp));
0334
0335
0336
0337 st_.run_dtors(
0338 ! sp_.is_not_shared_and_deallocate_is_trivial());
0339 }
0340
0341 value
0342 value_stack::
0343 release() noexcept
0344 {
0345
0346
0347
0348 BOOST_ASSERT(st_.size() == 1);
0349
0350
0351 sp_ = {};
0352
0353 return pilfer(*st_.release(1));
0354 }
0355
0356
0357
0358 void
0359 value_stack::
0360 push_array(std::size_t n)
0361 {
0362
0363 if(BOOST_JSON_UNLIKELY(n == 0))
0364 st_.maybe_grow();
0365 detail::unchecked_array ua(
0366 st_.release(n), n, sp_);
0367 st_.exchange(std::move(ua));
0368 }
0369
0370 void
0371 value_stack::
0372 push_object(std::size_t n)
0373 {
0374
0375 if(BOOST_JSON_UNLIKELY(n == 0))
0376 st_.maybe_grow();
0377 detail::unchecked_object uo(
0378 st_.release(n * 2), n, sp_);
0379 st_.exchange(std::move(uo));
0380 }
0381
0382 void
0383 value_stack::
0384 push_chars(
0385 string_view s)
0386 {
0387 st_.append(s);
0388 }
0389
0390 void
0391 value_stack::
0392 push_key(
0393 string_view s)
0394 {
0395 if(! st_.has_chars())
0396 {
0397 st_.push(detail::key_t{}, s, sp_);
0398 return;
0399 }
0400 auto part = st_.release_string();
0401 st_.push(detail::key_t{}, part, s, sp_);
0402 }
0403
0404 void
0405 value_stack::
0406 push_string(
0407 string_view s)
0408 {
0409 if(! st_.has_chars())
0410 {
0411
0412 st_.push(s, sp_);
0413 return;
0414 }
0415
0416
0417
0418
0419
0420 auto part = st_.release_string();
0421 auto& str = st_.push(
0422 string_kind, sp_).get_string();
0423 str.reserve(
0424 part.size() + s.size());
0425 std::memcpy(
0426 str.data(),
0427 part.data(), part.size());
0428 std::memcpy(
0429 str.data() + part.size(),
0430 s.data(), s.size());
0431 str.grow(part.size() + s.size());
0432 }
0433
0434 void
0435 value_stack::
0436 push_int64(
0437 int64_t i)
0438 {
0439 st_.push(i, sp_);
0440 }
0441
0442 void
0443 value_stack::
0444 push_uint64(
0445 uint64_t u)
0446 {
0447 st_.push(u, sp_);
0448 }
0449
0450 void
0451 value_stack::
0452 push_double(
0453 double d)
0454 {
0455 st_.push(d, sp_);
0456 }
0457
0458 void
0459 value_stack::
0460 push_bool(
0461 bool b)
0462 {
0463 st_.push(b, sp_);
0464 }
0465
0466 void
0467 value_stack::
0468 push_null()
0469 {
0470 st_.push(nullptr, sp_);
0471 }
0472
0473 }
0474 }
0475
0476 #endif