LCOV - code coverage report
Current view: top level - json/detail/impl - string_impl.ipp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 99.1 % 229 227
Test Date: 2025-12-23 17:20:51 Functions: 100.0 % 13 13

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

Generated by: LCOV version 2.1