LCOV - code coverage report
Current view: top level - json/impl - value_stack.ipp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 99.5 % 199 198
Test Date: 2025-12-23 17:20:51 Functions: 100.0 % 41 41

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/boostorg/json
       8              : //
       9              : 
      10              : #ifndef BOOST_JSON_IMPL_VALUE_STACK_IPP
      11              : #define BOOST_JSON_IMPL_VALUE_STACK_IPP
      12              : 
      13              : #include <boost/json/value_stack.hpp>
      14              : #include <cstring>
      15              : #include <stdexcept>
      16              : #include <utility>
      17              : 
      18              : namespace boost {
      19              : namespace json {
      20              : 
      21              : //--------------------------------------
      22              : 
      23      2076892 : value_stack::
      24              : stack::
      25              : ~stack()
      26              : {
      27      2076892 :     clear();
      28      2076892 :     if( begin_ != temp_ &&
      29        75338 :         begin_ != nullptr)
      30        75330 :         sp_->deallocate(
      31        75330 :             begin_,
      32        75330 :             (end_ - begin_) *
      33              :                 sizeof(value));
      34      2076892 : }
      35              : 
      36      2076892 : value_stack::
      37              : stack::
      38              : stack(
      39              :     storage_ptr sp,
      40              :     void* temp,
      41      2076892 :     std::size_t size) noexcept
      42      2076892 :     : sp_(std::move(sp))
      43      2076892 :     , temp_(temp)
      44              : {
      45      2076892 :     if(size >= min_size_ *
      46              :         sizeof(value))
      47              :     {
      48      2001516 :         begin_ = reinterpret_cast<
      49              :             value*>(temp);
      50      2001516 :         top_ = begin_;
      51      2001516 :         end_ = begin_ +
      52      2001516 :             size / sizeof(value);
      53              :     }
      54              :     else
      55              :     {
      56        75376 :         begin_ = nullptr;
      57        75376 :         top_ = nullptr;
      58        75376 :         end_ = nullptr;
      59              :     }
      60      2076892 : }
      61              : 
      62              : void
      63      4153128 : value_stack::
      64              : stack::
      65              : run_dtors(bool b) noexcept
      66              : {
      67      4153128 :     run_dtors_ = b;
      68      4153128 : }
      69              : 
      70              : std::size_t
      71      4213790 : value_stack::
      72              : stack::
      73              : size() const noexcept
      74              : {
      75      4213790 :     return top_ - begin_;
      76              : }
      77              : 
      78              : bool
      79        64464 : value_stack::
      80              : stack::
      81              : has_chars()
      82              : {
      83        64464 :     return chars_ != 0;
      84              : }
      85              : 
      86              : //--------------------------------------
      87              : 
      88              : // destroy the values but
      89              : // not the stack allocation.
      90              : void
      91      6230020 : value_stack::
      92              : stack::
      93              : clear() noexcept
      94              : {
      95      6230020 :     if(top_ != begin_)
      96              :     {
      97           84 :         if(run_dtors_)
      98           84 :             for(auto it = top_;
      99          335 :                 it-- != begin_;)
     100          251 :                 it->~value();
     101           84 :         top_ = begin_;
     102              :     }
     103      6230020 :     chars_ = 0;
     104      6230020 : }
     105              : 
     106              : void
     107         1868 : value_stack::
     108              : stack::
     109              : maybe_grow()
     110              : {
     111         1868 :     if(top_ >= end_)
     112          266 :         grow_one();
     113         1868 : }
     114              : 
     115              : // make room for at least one more value
     116              : void
     117        66499 : value_stack::
     118              : stack::
     119              : grow_one()
     120              : {
     121        66499 :     BOOST_ASSERT(chars_ == 0);
     122        66499 :     std::size_t const capacity =
     123        66499 :         end_ - begin_;
     124        66499 :     std::size_t new_cap = min_size_;
     125              :     // VFALCO check overflow here
     126        66541 :     while(new_cap < capacity + 1)
     127           42 :         new_cap <<= 1;
     128              :     auto const begin =
     129              :         reinterpret_cast<value*>(
     130        66499 :             sp_->allocate(
     131              :                 new_cap * sizeof(value)));
     132        66499 :     std::size_t const cur_size = top_ - begin_;
     133        66499 :     if(begin_)
     134              :     {
     135           11 :         std::memcpy(
     136              :             reinterpret_cast<char*>(begin),
     137           11 :             reinterpret_cast<char*>(begin_),
     138           11 :             size() * sizeof(value));
     139           11 :         if(begin_ != temp_)
     140            9 :             sp_->deallocate(begin_,
     141              :                 capacity * sizeof(value));
     142              :     }
     143              :     // book-keeping
     144        66499 :     top_ = begin + cur_size;
     145        66499 :     end_ = begin + new_cap;
     146        66499 :     begin_ = begin;
     147        66499 : }
     148              : 
     149              : // make room for nchars additional characters.
     150              : void
     151        16168 : value_stack::
     152              : stack::
     153              : grow(std::size_t nchars)
     154              : {
     155              :     // needed capacity in values
     156              :     std::size_t const needed =
     157        16168 :         size() +
     158        16168 :         1 +
     159        16168 :         ((chars_ + nchars +
     160        16168 :             sizeof(value) - 1) /
     161        16168 :                 sizeof(value));
     162        16168 :     std::size_t const capacity =
     163        16168 :         end_ - begin_;
     164        16168 :     BOOST_ASSERT(
     165              :         needed > capacity);
     166        16168 :     std::size_t new_cap = min_size_;
     167              :     // VFALCO check overflow here
     168        57815 :     while(new_cap < needed)
     169        41647 :         new_cap <<= 1;
     170              :     auto const begin =
     171              :         reinterpret_cast<value*>(
     172        16168 :             sp_->allocate(
     173              :                 new_cap * sizeof(value)));
     174        16168 :     std::size_t const cur_size = top_ - begin_;
     175        16168 :     if(begin_)
     176              :     {
     177              :         std::size_t amount =
     178         7328 :             size() * sizeof(value);
     179         7328 :         if(chars_ > 0)
     180            0 :             amount += sizeof(value) + chars_;
     181         7328 :         std::memcpy(
     182              :             reinterpret_cast<char*>(begin),
     183         7328 :             reinterpret_cast<char*>(begin_),
     184              :             amount);
     185         7328 :         if(begin_ != temp_)
     186         7328 :             sp_->deallocate(begin_,
     187              :                 capacity * sizeof(value));
     188              :     }
     189              :     // book-keeping
     190        16168 :     top_ = begin + cur_size;
     191        16168 :     end_ = begin + new_cap;
     192        16168 :     begin_ = begin;
     193        16168 : }
     194              : 
     195              : //--------------------------------------
     196              : 
     197              : void
     198        17145 : value_stack::
     199              : stack::
     200              : append(string_view s)
     201              : {
     202        17145 :     std::size_t const bytes_avail =
     203              :         reinterpret_cast<
     204        17145 :             char const*>(end_) -
     205              :         reinterpret_cast<
     206        17145 :             char const*>(top_);
     207              :     // make sure there is room for
     208              :     // pushing one more value without
     209              :     // clobbering the string.
     210        34290 :     if(sizeof(value) + chars_ +
     211        17145 :             s.size() > bytes_avail)
     212        16168 :         grow(s.size());
     213              : 
     214              :     // copy the new piece
     215        17145 :     std::memcpy(
     216              :         reinterpret_cast<char*>(
     217        17145 :             top_ + 1) + chars_,
     218        17145 :         s.data(), s.size());
     219        17145 :     chars_ += s.size();
     220              : 
     221              :     // ensure a pushed value cannot
     222              :     // clobber the released string.
     223        17145 :     BOOST_ASSERT(
     224              :         reinterpret_cast<char*>(
     225              :             top_ + 1) + chars_ <=
     226              :         reinterpret_cast<char*>(
     227              :             end_));
     228        17145 : }
     229              : 
     230              : string_view
     231        17020 : value_stack::
     232              : stack::
     233              : release_string() noexcept
     234              : {
     235              :     // ensure a pushed value cannot
     236              :     // clobber the released string.
     237        17020 :     BOOST_ASSERT(
     238              :         reinterpret_cast<char*>(
     239              :             top_ + 1) + chars_ <=
     240              :         reinterpret_cast<char*>(
     241              :             end_));
     242        17020 :     auto const n = chars_;
     243        17020 :     chars_ = 0;
     244              :     return { reinterpret_cast<
     245        17020 :         char const*>(top_ + 1), n };
     246              : }
     247              : 
     248              : // transfer ownership of the top n
     249              : // elements of the stack to the caller
     250              : value*
     251      2113641 : value_stack::
     252              : stack::
     253              : release(std::size_t n) noexcept
     254              : {
     255      2113641 :     BOOST_ASSERT(n <= size());
     256      2113641 :     BOOST_ASSERT(chars_ == 0);
     257      2113641 :     top_ -= n;
     258      2113641 :     return top_;
     259              : }
     260              : 
     261              : template<class... Args>
     262              : value&
     263      2119934 : value_stack::
     264              : stack::
     265              : push(Args&&... args)
     266              : {
     267      2119934 :     BOOST_ASSERT(chars_ == 0);
     268      2119934 :     if(top_ >= end_)
     269        66233 :         grow_one();
     270              :     value& jv = detail::access::
     271      2119934 :         construct_value(top_,
     272              :             std::forward<Args>(args)...);
     273      2119870 :     ++top_;
     274      2119870 :     return jv;
     275              : }
     276              : 
     277              : template<class Unchecked>
     278              : void
     279        36999 : value_stack::
     280              : stack::
     281              : exchange(Unchecked&& u)
     282              : {
     283        36999 :     BOOST_ASSERT(chars_ == 0);
     284              :     union U
     285              :     {
     286              :         value v;
     287        36999 :         U() {}
     288        36999 :         ~U() {}
     289        36999 :     } jv;
     290              :     // construct value on the stack
     291              :     // to avoid clobbering top_[0],
     292              :     // which belongs to `u`.
     293              :     detail::access::
     294        36999 :         construct_value(
     295        36999 :             &jv.v, std::move(u));
     296        36922 :     std::memcpy(
     297              :         reinterpret_cast<
     298        36922 :             char*>(top_),
     299              :         &jv.v, sizeof(value));
     300        36922 :     ++top_;
     301        36999 : }
     302              : 
     303              : //----------------------------------------------------------
     304              : 
     305      2076892 : value_stack::
     306              : ~value_stack()
     307              : {
     308              :     // default dtor is here so the
     309              :     // definition goes in the library
     310              :     // instead of the caller's TU.
     311      2076892 : }
     312              : 
     313      2076892 : value_stack::
     314              : value_stack(
     315              :     storage_ptr sp,
     316              :     unsigned char* temp_buffer,
     317      2076892 :     std::size_t temp_size) noexcept
     318      2076892 :     : st_(
     319      2076892 :         std::move(sp),
     320              :         temp_buffer,
     321      2076892 :         temp_size)
     322              : {
     323      2076892 : }
     324              : 
     325              : void
     326      4153128 : value_stack::
     327              : reset(storage_ptr sp) noexcept
     328              : {
     329      4153128 :     st_.clear();
     330              : 
     331      4153128 :     sp_.~storage_ptr();
     332     12459376 :     ::new(&sp_) storage_ptr(
     333      4153128 :         pilfer(sp));
     334              : 
     335              :     // `stack` needs this
     336              :     // to clean up correctly
     337      8306256 :     st_.run_dtors(
     338      4153128 :         ! sp_.is_not_shared_and_deallocate_is_trivial());
     339      4153128 : }
     340              : 
     341              : value
     342      2076642 : value_stack::
     343              : release() noexcept
     344              : {
     345              :     // This means the caller did not
     346              :     // cause a single top level element
     347              :     // to be produced.
     348      2076642 :     BOOST_ASSERT(st_.size() == 1);
     349              : 
     350              :     // give up shared ownership
     351      2076642 :     sp_ = {};
     352              : 
     353      2076642 :     return pilfer(*st_.release(1));
     354              : }
     355              : 
     356              : //----------------------------------------------------------
     357              : 
     358              : void
     359         2120 : value_stack::
     360              : push_array(std::size_t n)
     361              : {
     362              :     // we already have room if n > 0
     363         2120 :     if(BOOST_JSON_UNLIKELY(n == 0))
     364          819 :         st_.maybe_grow();
     365              :     detail::unchecked_array ua(
     366         2120 :         st_.release(n), n, sp_);
     367         2120 :     st_.exchange(std::move(ua));
     368         2120 : }
     369              : 
     370              : void
     371        34879 : value_stack::
     372              : push_object(std::size_t n)
     373              : {
     374              :     // we already have room if n > 0
     375        34879 :     if(BOOST_JSON_UNLIKELY(n == 0))
     376         1049 :         st_.maybe_grow();
     377              :     detail::unchecked_object uo(
     378        34879 :         st_.release(n * 2), n, sp_);
     379        34879 :     st_.exchange(std::move(uo));
     380        34879 : }
     381              : 
     382              : void
     383        17145 : value_stack::
     384              : push_chars(
     385              :     string_view s)
     386              : {
     387        17145 :     st_.append(s);
     388        17145 : }
     389              : 
     390              : void
     391        38356 : value_stack::
     392              : push_key(
     393              :     string_view s)
     394              : {
     395        38356 :     if(! st_.has_chars())
     396              :     {
     397        30296 :         st_.push(detail::key_t{}, s, sp_);
     398        30236 :         return;
     399              :     }
     400         8060 :     auto part = st_.release_string();
     401         8060 :     st_.push(detail::key_t{}, part, s, sp_);
     402              : }
     403              : 
     404              : void
     405        26108 : value_stack::
     406              : push_string(
     407              :     string_view s)
     408              : {
     409        26108 :     if(! st_.has_chars())
     410              :     {
     411              :         // fast path
     412        17148 :         st_.push(s, sp_);
     413        17144 :         return;
     414              :     }
     415              : 
     416              :     // VFALCO We could add a special
     417              :     // private ctor to string that just
     418              :     // creates uninitialized space,
     419              :     // to reduce member function calls.
     420         8960 :     auto part = st_.release_string();
     421        17920 :     auto& str = st_.push(
     422         8960 :         string_kind, sp_).get_string();
     423         8960 :     str.reserve(
     424         8960 :         part.size() + s.size());
     425         8960 :     std::memcpy(
     426         8960 :         str.data(),
     427         8960 :         part.data(), part.size());
     428         8960 :     std::memcpy(
     429         8960 :         str.data() + part.size(),
     430         8960 :         s.data(), s.size());
     431         8960 :     str.grow(part.size() + s.size());
     432              : }
     433              : 
     434              : void
     435         5815 : value_stack::
     436              : push_int64(
     437              :     int64_t i)
     438              : {
     439         5815 :     st_.push(i, sp_);
     440         5815 : }
     441              : 
     442              : void
     443           70 : value_stack::
     444              : push_uint64(
     445              :     uint64_t u)
     446              : {
     447           70 :     st_.push(u, sp_);
     448           70 : }
     449              : 
     450              : void
     451      2039817 : value_stack::
     452              : push_double(
     453              :     double d)
     454              : {
     455      2039817 :     st_.push(d, sp_);
     456      2039817 : }
     457              : 
     458              : void
     459          400 : value_stack::
     460              : push_bool(
     461              :     bool b)
     462              : {
     463          400 :     st_.push(b, sp_);
     464          400 : }
     465              : 
     466              : void
     467         9368 : value_stack::
     468              : push_null()
     469              : {
     470         9368 :     st_.push(nullptr, sp_);
     471         9368 : }
     472              : 
     473              : } // namespace json
     474              : } // namespace boost
     475              : 
     476              : #endif
        

Generated by: LCOV version 2.1