LCOV - code coverage report
Current view: top level - json/impl - value_stack.ipp (source / functions) Coverage Total Hit Missed
Test: coverage_remapped.info Lines: 99.5 % 199 198 1
Test Date: 2026-02-25 20:43:10 Functions: 100.0 % 41 41

           TLA  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 HIT     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 MIS           0 :             amount += sizeof(value) + chars_;
     181 HIT        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.3