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

Generated by: LCOV version 2.3