LCOV - code coverage report
Current view: top level - json/detail - string_impl.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 92 92
Test Date: 2026-07-17 09:08:41 Functions: 100.0 % 34 34

           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_STRING_IMPL_HPP
      12                 : #define BOOST_JSON_DETAIL_STRING_IMPL_HPP
      13                 : 
      14                 : #include <boost/core/detail/static_assert.hpp>
      15                 : #include <boost/json/detail/config.hpp>
      16                 : #include <boost/json/kind.hpp>
      17                 : #include <boost/json/storage_ptr.hpp>
      18                 : #include <boost/json/detail/value.hpp>
      19                 : #include <algorithm>
      20                 : #include <iterator>
      21                 : 
      22                 : namespace boost {
      23                 : namespace json {
      24                 : 
      25                 : class value;
      26                 : class string;
      27                 : 
      28                 : namespace detail {
      29                 : 
      30                 : inline
      31                 : bool
      32 HIT          78 : ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
      33                 : {
      34             113 :     return std::less<char const*>()(ptr, last) &&
      35             113 :         std::greater_equal<char const*>()(ptr, first);
      36                 : }
      37                 : 
      38                 : 
      39                 : class string_impl
      40                 : {
      41                 :     struct table
      42                 :     {
      43                 :         std::uint32_t size;
      44                 :         std::uint32_t capacity;
      45                 :     };
      46                 : 
      47                 : #if BOOST_JSON_ARCH == 64
      48                 :     static constexpr std::size_t sbo_chars_ = 14;
      49                 : #elif BOOST_JSON_ARCH == 32
      50                 :     static constexpr std::size_t sbo_chars_ = 10;
      51                 : #else
      52                 : # error Unknown architecture
      53                 : #endif
      54                 : 
      55                 :     static constexpr
      56                 :     unsigned char
      57                 :     short_flag = 0x80;
      58                 : 
      59                 :     static constexpr
      60                 :     unsigned char
      61                 :     key_flag = 0x40;
      62                 : 
      63                 :     static constexpr
      64                 :     unsigned char
      65                 :     seamless_flag = 0x20;
      66                 : 
      67                 :     void
      68               2 :     set_storage_kind(unsigned char storage_kind)
      69                 :     {
      70               2 :         unsigned char current = static_cast<unsigned char>(s_.k);
      71               2 :         current = current & 0x2F;
      72               2 :         s_.k = static_cast<kind>(current | storage_kind);
      73               2 :     }
      74                 : 
      75                 :     static
      76                 :     constexpr
      77                 :     kind
      78                 :     short_string_ =
      79                 :         static_cast<kind>(
      80                 :             ((unsigned char)
      81                 :             kind::string) | short_flag);
      82                 : 
      83                 :     static
      84                 :     constexpr
      85                 :     kind
      86                 :     key_string_ =
      87                 :         static_cast<kind>(
      88                 :             ((unsigned char)
      89                 :             kind::string) | key_flag);
      90                 : 
      91                 :     struct sbo
      92                 :     {
      93                 :         kind k; // must come first
      94                 :         char buf[sbo_chars_ + 1];
      95                 :     };
      96                 : 
      97                 :     struct pointer
      98                 :     {
      99                 :         kind k; // must come first
     100                 :         table* t;
     101                 :     };
     102                 : 
     103                 :     struct key
     104                 :     {
     105                 :         kind k; // must come first
     106                 :         std::uint32_t n;
     107                 :         char* s;
     108                 :     };
     109                 : 
     110                 :     union
     111                 :     {
     112                 :         sbo s_;
     113                 :         pointer p_;
     114                 :         key k_;
     115                 :     };
     116                 : 
     117                 : #if BOOST_JSON_ARCH == 64
     118                 :     BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
     119                 :     BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
     120                 :     BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
     121                 : #elif BOOST_JSON_ARCH == 32
     122                 :     BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
     123                 :     BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
     124                 :     BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
     125                 : #endif
     126                 : 
     127                 : public:
     128                 :     static
     129                 :     constexpr
     130                 :     std::size_t
     131          154259 :     max_size() noexcept
     132                 :     {
     133                 :         // max_size depends on the address model
     134                 :         using min = std::integral_constant<std::size_t,
     135                 :             std::size_t(-1) - sizeof(table)>;
     136                 :         return min::value < BOOST_JSON_MAX_STRING_SIZE ?
     137          154259 :             min::value : BOOST_JSON_MAX_STRING_SIZE;
     138                 :     }
     139                 : 
     140                 :     BOOST_JSON_DECL
     141                 :     string_impl() noexcept;
     142                 : 
     143                 :     BOOST_JSON_DECL
     144                 :     string_impl(
     145                 :         std::size_t new_size,
     146                 :         storage_ptr const& sp);
     147                 : 
     148                 :     BOOST_JSON_DECL
     149                 :     string_impl(
     150                 :         key_t,
     151                 :         string_view s,
     152                 :         storage_ptr const& sp);
     153                 : 
     154                 :     BOOST_JSON_DECL
     155                 :     string_impl(
     156                 :         key_t,
     157                 :         string_view s1,
     158                 :         string_view s2,
     159                 :         storage_ptr const& sp);
     160                 : 
     161                 :     BOOST_JSON_DECL
     162                 :     string_impl(
     163                 :         char** dest,
     164                 :         std::size_t len,
     165                 :         storage_ptr const& sp);
     166                 : 
     167                 :     template<class InputIt>
     168               8 :     string_impl(
     169                 :         InputIt first,
     170                 :         InputIt last,
     171                 :         storage_ptr const& sp,
     172                 :         std::random_access_iterator_tag)
     173               8 :         : string_impl(last - first, sp)
     174                 :     {
     175               7 :         char* out = data();
     176                 : #if defined(_MSC_VER) && _MSC_VER <= 1900
     177                 :         while( first != last )
     178                 :             *out++ = *first++;
     179                 : #else
     180               7 :         std::copy(first, last, out);
     181                 : #endif
     182               7 :     }
     183                 : 
     184                 :     template<class InputIt>
     185              38 :     string_impl(
     186                 :         InputIt first,
     187                 :         InputIt last,
     188                 :         storage_ptr const& sp,
     189                 :         std::input_iterator_tag)
     190              38 :         : string_impl(0, sp)
     191                 :     {
     192                 :         struct undo
     193                 :         {
     194                 :             string_impl* s;
     195                 :             storage_ptr const& sp;
     196                 : 
     197              38 :             ~undo()
     198                 :             {
     199              38 :                 if(s)
     200               3 :                     s->destroy(sp);
     201              38 :             }
     202                 :         };
     203                 : 
     204              38 :         undo u{this, sp};
     205              38 :         auto dest = data();
     206             313 :         while(first != last)
     207                 :         {
     208             278 :             if(size() < capacity())
     209             267 :                 size(size() + 1);
     210                 :             else
     211              11 :                 dest = append(1, sp);
     212             275 :             *dest++ = *first++;
     213                 :         }
     214              35 :         term(size());
     215              35 :         u.s = nullptr;
     216              38 :     }
     217                 : 
     218                 :     std::size_t
     219           99932 :     size() const noexcept
     220                 :     {
     221           99932 :         return s_.k == kind::string ?
     222           65016 :             p_.t->size :
     223                 :             sbo_chars_ -
     224           99932 :                 s_.buf[sbo_chars_];
     225                 :     }
     226                 : 
     227                 :     std::size_t
     228           92398 :     capacity() const noexcept
     229                 :     {
     230           92398 :         return s_.k == kind::string ?
     231           11962 :             p_.t->capacity :
     232           92398 :             sbo_chars_;
     233                 :     }
     234                 : 
     235                 :     void
     236           10059 :     size(std::size_t n)
     237                 :     {
     238           10059 :         if(s_.k == kind::string)
     239            9776 :             p_.t->size = static_cast<
     240                 :                 std::uint32_t>(n);
     241                 :         else
     242             283 :             s_.buf[sbo_chars_] =
     243                 :                 static_cast<char>(
     244             283 :                     sbo_chars_ - n);
     245           10059 :     }
     246                 : 
     247                 :     BOOST_JSON_DECL
     248                 :     static
     249                 :     std::uint32_t
     250                 :     growth(
     251                 :         std::size_t new_size,
     252                 :         std::size_t capacity);
     253                 : 
     254                 :     char const*
     255           38154 :     release_key(
     256                 :         std::size_t& n) noexcept
     257                 :     {
     258           38154 :         BOOST_ASSERT( is_key() );
     259           38154 :         BOOST_ASSERT( ! is_seamless() );
     260           38154 :         n = k_.n;
     261           38154 :         auto const s = k_.s;
     262                 :         // prevent deallocate
     263           38154 :         k_.k = short_string_;
     264           38154 :         return s;
     265                 :     }
     266                 : 
     267                 :     void
     268           57834 :     destroy(storage_ptr const& sp) noexcept
     269                 :     {
     270           57834 :         if( is_short() )
     271                 :         {
     272                 :             // do nothing
     273                 :         }
     274           26885 :         else if( is_key() )
     275                 :         {
     276                 :             // VFALCO unfortunately the key string
     277                 :             // kind increases the cost of the destructor.
     278                 :             // This function should be skipped when using
     279                 :             // monotonic_resource.
     280             146 :             sp->deallocate(k_.s, k_.n + 1);
     281                 :         }
     282                 :         else
     283                 :         {
     284           26739 :             sp->deallocate(
     285           26739 :                 p_.t, sizeof(table) + p_.t->capacity + 1, alignof(table));
     286                 :         }
     287           57834 :     }
     288                 : 
     289                 :     BOOST_JSON_DECL
     290                 :     char*
     291                 :     assign(
     292                 :         std::size_t new_size,
     293                 :         storage_ptr const& sp);
     294                 : 
     295                 :     BOOST_JSON_DECL
     296                 :     char*
     297                 :     append(
     298                 :         std::size_t n,
     299                 :         storage_ptr const& sp);
     300                 : 
     301                 :     BOOST_JSON_DECL
     302                 :     void
     303                 :     insert(
     304                 :         std::size_t pos,
     305                 :         const char* s,
     306                 :         std::size_t n,
     307                 :         storage_ptr const& sp);
     308                 : 
     309                 :     BOOST_JSON_DECL
     310                 :     char*
     311                 :     insert_unchecked(
     312                 :         std::size_t pos,
     313                 :         std::size_t n,
     314                 :         storage_ptr const& sp);
     315                 : 
     316                 :     BOOST_JSON_DECL
     317                 :     void
     318                 :     replace(
     319                 :         std::size_t pos,
     320                 :         std::size_t n1,
     321                 :         const char* s,
     322                 :         std::size_t n2,
     323                 :         storage_ptr const& sp);
     324                 : 
     325                 :     BOOST_JSON_DECL
     326                 :     char*
     327                 :     replace_unchecked(
     328                 :         std::size_t pos,
     329                 :         std::size_t n1,
     330                 :         std::size_t n2,
     331                 :         storage_ptr const& sp);
     332                 : 
     333                 :     BOOST_JSON_DECL
     334                 :     void
     335                 :     shrink_to_fit(
     336                 :         storage_ptr const& sp) noexcept;
     337                 : 
     338                 :     void
     339           33801 :     term(std::size_t n) noexcept
     340                 :     {
     341           33801 :         if( is_short() )
     342                 :         {
     343            5177 :             s_.buf[sbo_chars_] = static_cast<char>(sbo_chars_ - n);
     344            5177 :             s_.buf[n] = 0;
     345                 :         }
     346                 :         else
     347                 :         {
     348           28624 :             p_.t->size = static_cast<std::uint32_t>(n);
     349           28624 :             data()[n] = 0;
     350                 :         }
     351           33801 :     }
     352                 : 
     353                 :     char*
     354          117954 :     data() noexcept
     355                 :     {
     356          117954 :         if( is_short() )
     357           15495 :             return s_.buf;
     358          102459 :         return reinterpret_cast<char*>(p_.t + 1);
     359                 :     }
     360                 : 
     361                 :     char const*
     362           44202 :     data() const noexcept
     363                 :     {
     364           44202 :         if( is_short() )
     365            4684 :             return s_.buf;
     366           39518 :         return reinterpret_cast<char const*>(p_.t + 1);
     367                 :     }
     368                 : 
     369                 :     char*
     370             241 :     end() noexcept
     371                 :     {
     372             241 :         return data() + size();
     373                 :     }
     374                 : 
     375                 :     char const*
     376              10 :     end() const noexcept
     377                 :     {
     378              10 :         return data() + size();
     379                 :     }
     380                 : 
     381                 :     inline
     382                 :     constexpr
     383                 :     bool
     384          253798 :     is_short() const noexcept
     385                 :     {
     386          253798 :         return static_cast<unsigned char>(s_.k) & short_flag;
     387                 :     }
     388                 : 
     389                 :     inline
     390                 :     constexpr
     391                 :     bool
     392           65039 :     is_key() const noexcept
     393                 :     {
     394           65039 :         return static_cast<unsigned char>(s_.k) & key_flag;
     395                 :     }
     396                 : 
     397                 :     inline
     398                 :     constexpr
     399                 :     bool
     400           52905 :     is_seamless() const noexcept
     401                 :     {
     402           52905 :         return static_cast<unsigned char>(s_.k) & seamless_flag;
     403                 :     }
     404                 : 
     405                 :     void
     406               4 :     set_seamless(bool on) noexcept
     407                 :     {
     408               4 :         unsigned char const seamless = on ? seamless_flag : 0;
     409               4 :         unsigned char current = static_cast<unsigned char>(s_.k);
     410               4 :         current = current & 0xCF;
     411               4 :         s_.k = static_cast<kind>(current | seamless);
     412               4 :     }
     413                 : };
     414                 : 
     415                 : template<class T>
     416                 : string_view
     417            2530 : to_string_view(T const& t) noexcept
     418                 : {
     419            2530 :     return string_view(t);
     420                 : }
     421                 : 
     422                 : template<class T, class U>
     423                 : using string_and_stringlike = std::integral_constant<bool,
     424                 :     std::is_same<T, string>::value &&
     425                 :     std::is_convertible<U const&, string_view>::value>;
     426                 : 
     427                 : template<class T, class U>
     428                 : using string_comp_op_requirement
     429                 :     = typename std::enable_if<
     430                 :         string_and_stringlike<T, U>::value ||
     431                 :         string_and_stringlike<U, T>::value,
     432                 :         bool>::type;
     433                 : 
     434                 : } // detail
     435                 : } // namespace json
     436                 : } // namespace boost
     437                 : 
     438                 : #endif
        

Generated by: LCOV version 2.3