LCOV - code coverage report
Current view: top level - json/detail/impl - string_impl.ipp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 230 230
Test Date: 2026-10-04 16:43:37 Functions: 100.0 % 12 12

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3                 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
       4                 : //
       5                 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       6                 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       7                 : //
       8                 : // Official repository: https://github.com/boostorg/json
       9                 : //
      10                 : 
      11                 : #ifndef BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
      12                 : #define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
      13                 : 
      14                 : #include <boost/json/detail/string_impl.hpp>
      15                 : #include <boost/json/detail/except.hpp>
      16                 : #include <cstring>
      17                 : #include <functional>
      18                 : 
      19                 : namespace boost {
      20                 : namespace json {
      21                 : namespace detail {
      22                 : 
      23 HIT       31070 : string_impl::
      24           31070 : string_impl() noexcept
      25           31070 :     : s_{}
      26                 : {
      27           31070 :     s_.k = short_string_;
      28           31070 :     s_.buf[sbo_chars_] =
      29                 :         static_cast<char>(
      30                 :             sbo_chars_);
      31           31070 :     s_.buf[0] = 0;
      32           31070 : }
      33                 : 
      34           26968 : string_impl::
      35                 : string_impl(
      36                 :     std::size_t size,
      37           26968 :     storage_ptr const& sp)
      38           26968 :     : s_{}
      39                 : {
      40           26968 :     if(size <= sbo_chars_)
      41                 :     {
      42              41 :         s_.k = short_string_;
      43              41 :         s_.buf[sbo_chars_] =
      44                 :             static_cast<char>(
      45              41 :                 sbo_chars_ - size);
      46              41 :         s_.buf[size] = 0;
      47                 :     }
      48                 :     else
      49                 :     {
      50           26927 :         s_.k = kind::string;
      51           26927 :         auto const n = growth(
      52                 :             size, sbo_chars_ + 1);
      53           26927 :         p_.t = ::new(sp->allocate(
      54                 :             sizeof(table) +
      55           26927 :                 n + 1,
      56                 :             alignof(table))) table{
      57                 :                 static_cast<
      58                 :                     std::uint32_t>(size),
      59                 :                 static_cast<
      60           26725 :                     std::uint32_t>(n)};
      61           26725 :         data()[n] = 0;
      62                 :     }
      63           26766 : }
      64                 : 
      65                 : // construct a key, unchecked
      66           30297 : string_impl::
      67                 : string_impl(
      68                 :     key_t,
      69                 :     string_view s,
      70           30297 :     storage_ptr const& sp)
      71                 : {
      72           30297 :     BOOST_ASSERT(
      73                 :         s.size() <= max_size());
      74           30297 :     k_.k = key_string_;
      75           30297 :     k_.n = static_cast<
      76           30297 :         std::uint32_t>(s.size());
      77           30237 :     k_.s = reinterpret_cast<char*>(
      78           30297 :         sp->allocate(s.size() + 1,
      79                 :             alignof(char)));
      80           30237 :     k_.s[s.size()] = 0; // null term
      81           30237 :     std::memcpy(&k_.s[0],
      82           30237 :         s.data(), s.size());
      83           30237 : }
      84                 : 
      85                 : // construct a key, unchecked
      86            8061 : string_impl::
      87                 : string_impl(
      88                 :     key_t,
      89                 :     string_view s1,
      90                 :     string_view s2,
      91            8061 :     storage_ptr const& sp)
      92                 : {
      93            8061 :     auto len = s1.size() + s2.size();
      94            8061 :     BOOST_ASSERT(len <= max_size());
      95            8061 :     k_.k = key_string_;
      96            8061 :     k_.n = static_cast<
      97                 :         std::uint32_t>(len);
      98            8061 :     k_.s = reinterpret_cast<char*>(
      99            8061 :         sp->allocate(len + 1,
     100                 :             alignof(char)));
     101            8061 :     k_.s[len] = 0; // null term
     102            8061 :     std::memcpy(&k_.s[0],
     103            8061 :         s1.data(), s1.size());
     104           16122 :     std::memcpy(&k_.s[s1.size()],
     105            8061 :         s2.data(), s2.size());
     106            8061 : }
     107                 : 
     108                 : std::uint32_t
     109           53847 : string_impl::
     110                 : growth(
     111                 :     std::size_t new_size,
     112                 :     std::size_t capacity)
     113                 : {
     114           53847 :     if(new_size > max_size())
     115                 :     {
     116                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     117               1 :         detail::throw_system_error( error::string_too_large, &loc );
     118                 :     }
     119                 :     // growth factor 2
     120           53846 :     if( capacity >
     121           53846 :         max_size() - capacity)
     122                 :         return static_cast<
     123               1 :             std::uint32_t>(max_size()); // overflow
     124                 :     return static_cast<std::uint32_t>(
     125           53845 :         (std::max)(capacity * 2, new_size));
     126                 : }
     127                 : 
     128                 : char*
     129           18500 : string_impl::
     130                 : assign(
     131                 :     std::size_t new_size,
     132                 :     storage_ptr const& sp)
     133                 : {
     134           18500 :     if(new_size > capacity())
     135                 :     {
     136           17135 :         string_impl tmp(growth(
     137                 :             new_size,
     138           17135 :             capacity()), sp);
     139           16986 :         destroy(sp);
     140           16986 :         *this = tmp;
     141                 :     }
     142           18351 :     term(new_size);
     143           18351 :     return data();
     144                 : }
     145                 : 
     146                 : char*
     147             259 : string_impl::
     148                 : append(
     149                 :     std::size_t n,
     150                 :     storage_ptr const& sp)
     151                 : {
     152             259 :     if(n > max_size() - size())
     153                 :     {
     154                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     155               1 :         detail::throw_system_error( error::string_too_large, &loc );
     156                 :     }
     157             258 :     if(n <= capacity() - size())
     158                 :     {
     159             199 :         term(size() + n);
     160             199 :         return end() - n;
     161                 :     }
     162             118 :     string_impl tmp(growth(
     163             118 :         size() + n, capacity()), sp);
     164              36 :     std::memcpy(
     165              36 :         tmp.data(), data(), size());
     166              36 :     tmp.term(size() + n);
     167              36 :     destroy(sp);
     168              36 :     *this = tmp;
     169              36 :     return end() - n;
     170                 : }
     171                 : 
     172                 : void
     173              27 : string_impl::
     174                 : insert(
     175                 :     std::size_t pos,
     176                 :     const char* s,
     177                 :     std::size_t n,
     178                 :     storage_ptr const& sp)
     179                 : {
     180              27 :     const auto curr_size = size();
     181              27 :     if(pos > curr_size)
     182                 :     {
     183                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     184               2 :         detail::throw_system_error( error::out_of_range, &loc );
     185                 :     }
     186              25 :     const auto curr_data = data();
     187              25 :     if(n <= capacity() - curr_size)
     188                 :     {
     189              10 :         const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
     190              10 :         if (!inside || (inside && ((s - curr_data) + n <= pos)))
     191                 :         {
     192               8 :             std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
     193               8 :             std::memcpy(&curr_data[pos], s, n);
     194                 :         }
     195                 :         else
     196                 :         {
     197               2 :             const std::size_t offset = s - curr_data;
     198               2 :             std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
     199               2 :             if (offset < pos)
     200                 :             {
     201               1 :                 const std::size_t diff = pos - offset;
     202               1 :                 std::memcpy(&curr_data[pos], &curr_data[offset], diff);
     203               1 :                 std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
     204                 :             }
     205                 :             else
     206                 :             {
     207               1 :                 std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
     208                 :             }
     209                 :         }
     210              10 :         size(curr_size + n);
     211                 :     }
     212                 :     else
     213                 :     {
     214              15 :         if(n > max_size() - curr_size)
     215                 :         {
     216                 :             BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     217               1 :             detail::throw_system_error( error::string_too_large, &loc );
     218                 :         }
     219              14 :         string_impl tmp(growth(
     220              14 :             curr_size + n, capacity()), sp);
     221               7 :         tmp.size(curr_size + n);
     222               7 :         std::memcpy(
     223               7 :             tmp.data(),
     224                 :             curr_data,
     225                 :             pos);
     226              14 :         std::memcpy(
     227              14 :             tmp.data() + pos + n,
     228                 :             curr_data + pos,
     229               7 :             curr_size + 1 - pos);
     230               7 :         std::memcpy(
     231               7 :             tmp.data() + pos,
     232                 :             s,
     233                 :             n);
     234               7 :         destroy(sp);
     235               7 :         *this = tmp;
     236                 :     }
     237              17 : }
     238                 : 
     239                 : char*
     240              18 : string_impl::
     241                 : insert_unchecked(
     242                 :     std::size_t pos,
     243                 :     std::size_t n,
     244                 :     storage_ptr const& sp)
     245                 : {
     246              18 :     const auto curr_size = size();
     247              18 :     if(pos > curr_size)
     248                 :     {
     249                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     250               1 :         detail::throw_system_error( error::out_of_range, &loc );
     251                 :     }
     252              17 :     const auto curr_data = data();
     253              17 :     if(n <= capacity() - size())
     254                 :     {
     255               5 :         auto const dest =
     256                 :             curr_data + pos;
     257               5 :         std::memmove(
     258                 :             dest + n,
     259                 :             dest,
     260               5 :             curr_size + 1 - pos);
     261               5 :         size(curr_size + n);
     262               5 :         return dest;
     263                 :     }
     264              12 :     if(n > max_size() - curr_size)
     265                 :     {
     266                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     267               1 :         detail::throw_system_error( error::string_too_large, &loc );
     268                 :     }
     269              11 :     string_impl tmp(growth(
     270              11 :         curr_size + n, capacity()), sp);
     271               6 :     tmp.size(curr_size + n);
     272               6 :     std::memcpy(
     273               6 :         tmp.data(),
     274                 :         curr_data,
     275                 :         pos);
     276              12 :     std::memcpy(
     277              12 :         tmp.data() + pos + n,
     278                 :         curr_data + pos,
     279               6 :         curr_size + 1 - pos);
     280               6 :     destroy(sp);
     281               6 :     *this = tmp;
     282               6 :     return data() + pos;
     283                 : }
     284                 : 
     285                 : void
     286              19 : string_impl::
     287                 : replace(
     288                 :     std::size_t pos,
     289                 :     std::size_t n1,
     290                 :     const char* s,
     291                 :     std::size_t n2,
     292                 :     storage_ptr const& sp)
     293                 : {
     294              19 :     const auto curr_size = size();
     295              19 :     if (pos > curr_size)
     296                 :     {
     297                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     298               1 :         detail::throw_system_error( error::out_of_range, &loc );
     299                 :     }
     300              18 :     const auto curr_data = data();
     301              18 :     n1 = (std::min)(n1, curr_size - pos);
     302              18 :     const auto delta = (std::max)(n1, n2) -
     303              18 :         (std::min)(n1, n2);
     304                 :     // if we are shrinking in size or we have enough
     305                 :     // capacity, dont reallocate
     306              18 :     if (n1 > n2 || delta <= capacity() - curr_size)
     307                 :     {
     308              13 :         const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
     309                 :         // there is nothing to replace; return
     310              13 :         if (inside && s == curr_data + pos && n1 == n2)
     311               1 :             return;
     312              12 :         if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
     313                 :         {
     314                 :             // source outside
     315               6 :             std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
     316               6 :             std::memcpy(&curr_data[pos], s, n2);
     317                 :         }
     318                 :         else
     319                 :         {
     320                 :             // source inside
     321               6 :             const std::size_t offset = s - curr_data;
     322               6 :             if (n2 >= n1)
     323                 :             {
     324                 :                 // grow/unchanged
     325               4 :                 const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
     326                 :                 // shift all right of splice point by n2 - n1 to the right
     327               4 :                 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
     328                 :                 // copy all before splice point
     329               4 :                 std::memmove(&curr_data[pos], &curr_data[offset], diff);
     330                 :                 // copy all after splice point
     331               4 :                 std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
     332                 :             }
     333                 :             else
     334                 :             {
     335                 :                 // shrink
     336                 :                 // copy all elements into place
     337               2 :                 std::memmove(&curr_data[pos], &curr_data[offset], n2);
     338                 :                 // shift all elements after splice point left
     339               2 :                 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
     340                 :             }
     341                 :         }
     342              12 :         size((curr_size - n1) + n2);
     343                 :     }
     344                 :     else
     345                 :     {
     346               5 :         if (delta > max_size() - curr_size)
     347                 :         {
     348                 :             BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     349               1 :             detail::throw_system_error( error::string_too_large, &loc );
     350                 :         }
     351                 :         // would exceed capacity, reallocate
     352               4 :         string_impl tmp(growth(
     353               4 :             curr_size + delta, capacity()), sp);
     354               2 :         tmp.size(curr_size + delta);
     355               2 :         std::memcpy(
     356               2 :             tmp.data(),
     357                 :             curr_data,
     358                 :             pos);
     359               4 :         std::memcpy(
     360               4 :             tmp.data() + pos + n2,
     361               2 :             curr_data + pos + n1,
     362               2 :             curr_size - pos - n1 + 1);
     363               4 :         std::memcpy(
     364               2 :             tmp.data() + pos,
     365                 :             s,
     366                 :             n2);
     367               2 :         destroy(sp);
     368               2 :         *this = tmp;
     369                 :     }
     370                 : }
     371                 : 
     372                 : // unlike the replace overload, this function does
     373                 : // not move any characters
     374                 : char*
     375              11 : string_impl::
     376                 : replace_unchecked(
     377                 :     std::size_t pos,
     378                 :     std::size_t n1,
     379                 :     std::size_t n2,
     380                 :     storage_ptr const& sp)
     381                 : {
     382              11 :     const auto curr_size = size();
     383              11 :     if(pos > curr_size)
     384                 :     {
     385                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     386               1 :         detail::throw_system_error( error::out_of_range, &loc );
     387                 :     }
     388              10 :     const auto curr_data = data();
     389              10 :     n1 = (std::min)(n1, curr_size - pos);
     390              10 :     const auto delta = (std::max)(n1, n2) -
     391              10 :         (std::min)(n1, n2);
     392                 :     // if the size doesn't change, we don't need to
     393                 :     // do anything
     394              10 :     if (!delta)
     395               1 :       return curr_data + pos;
     396                 :     // if we are shrinking in size or we have enough
     397                 :     // capacity, dont reallocate
     398               9 :     if(n1 > n2 || delta <= capacity() - curr_size)
     399                 :     {
     400               4 :         auto const replace_pos = curr_data + pos;
     401               4 :         std::memmove(
     402               4 :             replace_pos + n2,
     403               4 :             replace_pos + n1,
     404               4 :             curr_size - pos - n1 + 1);
     405               4 :         size((curr_size - n1) + n2);
     406               4 :         return replace_pos;
     407                 :     }
     408               5 :     if(delta > max_size() - curr_size)
     409                 :     {
     410                 :         BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
     411               1 :         detail::throw_system_error( error::string_too_large, &loc );
     412                 :     }
     413                 :     // would exceed capacity, reallocate
     414               4 :     string_impl tmp(growth(
     415               4 :         curr_size + delta, capacity()), sp);
     416               2 :     tmp.size(curr_size + delta);
     417               2 :     std::memcpy(
     418               2 :         tmp.data(),
     419                 :         curr_data,
     420                 :         pos);
     421               4 :     std::memcpy(
     422               4 :         tmp.data() + pos + n2,
     423               2 :         curr_data + pos + n1,
     424               2 :         curr_size - pos - n1 + 1);
     425               2 :     destroy(sp);
     426               2 :     *this = tmp;
     427               2 :     return data() + pos;
     428                 : }
     429                 : 
     430                 : void
     431              11 : string_impl::
     432                 : shrink_to_fit(
     433                 :     storage_ptr const& sp) noexcept
     434                 : {
     435              11 :     if(s_.k == short_string_)
     436               3 :         return;
     437               8 :     auto const t = p_.t;
     438               8 :     if(t->size <= sbo_chars_)
     439                 :     {
     440               6 :         std::memcpy(
     441               3 :             s_.buf, data(), t->size);
     442               3 :         s_.k = short_string_;
     443               3 :         s_.buf[sbo_chars_] =
     444                 :             static_cast<char>(
     445               3 :                 sbo_chars_ - t->size);
     446               3 :         s_.buf[t->size] = 0;
     447               3 :         sp->deallocate(t,
     448                 :             sizeof(table) +
     449               3 :                 t->capacity + 1,
     450                 :             alignof(table));
     451               3 :         return;
     452                 :     }
     453               5 :     if(t->size >= t->capacity)
     454               2 :         return;
     455                 : #ifndef BOOST_NO_EXCEPTIONS
     456                 :     try
     457                 :     {
     458                 : #endif
     459               3 :         string_impl tmp(t->size, sp);
     460               4 :         std::memcpy(
     461               2 :             tmp.data(),
     462               2 :             data(),
     463               2 :             size() + 1);
     464               2 :         destroy(sp);
     465               2 :         *this = tmp;
     466                 : #ifndef BOOST_NO_EXCEPTIONS
     467                 :     }
     468               1 :     catch(std::exception const&)
     469                 :     {
     470                 :         // eat the exception
     471               1 :     }
     472                 : #endif
     473                 : }
     474                 : 
     475                 : } // detail
     476                 : } // namespace json
     477                 : } // namespace boost
     478                 : 
     479                 : #endif
        

Generated by: LCOV version 2.3