Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:03

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/json
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 // destroy the values but
0089 // not the stack allocation.
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 // make room for at least one more value
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     // VFALCO check overflow here
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     // book-keeping
0144     top_ = begin + cur_size;
0145     end_ = begin + new_cap;
0146     begin_ = begin;
0147 }
0148 
0149 // make room for nchars additional characters.
0150 void
0151 value_stack::
0152 stack::
0153 grow(std::size_t nchars)
0154 {
0155     // needed capacity in values
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     // VFALCO check overflow here
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     // book-keeping
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     // make sure there is room for
0208     // pushing one more value without
0209     // clobbering the string.
0210     if(sizeof(value) + chars_ +
0211             s.size() > bytes_avail)
0212         grow(s.size());
0213 
0214     // copy the new piece
0215     std::memcpy(
0216         reinterpret_cast<char*>(
0217             top_ + 1) + chars_,
0218         s.data(), s.size());
0219     chars_ += s.size();
0220 
0221     // ensure a pushed value cannot
0222     // clobber the released string.
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     // ensure a pushed value cannot
0236     // clobber the released string.
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 // transfer ownership of the top n
0249 // elements of the stack to the caller
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     // construct value on the stack
0291     // to avoid clobbering top_[0],
0292     // which belongs to `u`.
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     // default dtor is here so the
0309     // definition goes in the library
0310     // instead of the caller's TU.
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     // `stack` needs this
0336     // to clean up correctly
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     // This means the caller did not
0346     // cause a single top level element
0347     // to be produced.
0348     BOOST_ASSERT(st_.size() == 1);
0349 
0350     // give up shared ownership
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     // we already have room if n > 0
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     // we already have room if n > 0
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         // fast path
0412         st_.push(s, sp_);
0413         return;
0414     }
0415 
0416     // VFALCO We could add a special
0417     // private ctor to string that just
0418     // creates uninitialized space,
0419     // to reduce member function calls.
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 } // namespace json
0474 } // namespace boost
0475 
0476 #endif