LCOV - code coverage report
Current view: top level - json/detail - utf8.hpp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 62 62
Test Date: 2026-02-25 20:43:10 Functions: 100.0 % 13 13

           TLA  Line data    Source code
       1                 : //
       2                 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@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_DETAIL_UTF8_HPP
      11                 : #define BOOST_JSON_DETAIL_UTF8_HPP
      12                 : 
      13                 : #include <boost/endian/conversion.hpp>
      14                 : #include <boost/json/detail/config.hpp>
      15                 : 
      16                 : #include <cstddef>
      17                 : #include <cstring>
      18                 : #include <cstdint>
      19                 : 
      20                 : namespace boost {
      21                 : namespace json {
      22                 : namespace detail {
      23                 : 
      24                 : template<int N>
      25                 : std::uint32_t
      26 HIT       21733 : load_little_endian(void const* p)
      27                 : {
      28           21733 :     std::uint32_t v = 0;
      29           21733 :     std::memcpy(&v, p, N);
      30           21733 :     endian::little_to_native_inplace(v);
      31           21733 :     return v;
      32                 : }
      33                 : 
      34                 : inline
      35                 : uint16_t
      36           16690 : classify_utf8(char c)
      37                 : {
      38                 :     // 0x000 = invalid
      39                 :     // 0x102 = 2 bytes, second byte [80, BF]
      40                 :     // 0x203 = 3 bytes, second byte [A0, BF]
      41                 :     // 0x303 = 3 bytes, second byte [80, BF]
      42                 :     // 0x403 = 3 bytes, second byte [80, 9F]
      43                 :     // 0x504 = 4 bytes, second byte [90, BF]
      44                 :     // 0x604 = 4 bytes, second byte [80, BF]
      45                 :     // 0x704 = 4 bytes, second byte [80, 8F]
      46                 :     static constexpr uint16_t first[128]
      47                 :     {
      48                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      49                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      50                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      51                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      52                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      53                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      54                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      55                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      56                 : 
      57                 :        0x000, 0x000, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
      58                 :        0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
      59                 :        0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
      60                 :        0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102, 0x102,
      61                 :        0x203, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303, 0x303,
      62                 :        0x303, 0x303, 0x303, 0x303, 0x303, 0x403, 0x303, 0x303,
      63                 :        0x504, 0x604, 0x604, 0x604, 0x704, 0x000, 0x000, 0x000,
      64                 :        0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000,
      65                 :     };
      66           16690 :     return first[static_cast<unsigned char>(c & 0x7F)];
      67                 : }
      68                 : 
      69                 : inline
      70                 : bool
      71           13177 : is_valid_utf8(const char* p, uint16_t first)
      72                 : {
      73                 :     uint32_t v;
      74           13177 :     switch(first >> 8)
      75                 :     {
      76             362 :     default:
      77             362 :         return false;
      78                 : 
      79                 :     // 2 bytes, second byte [80, BF]
      80            2348 :     case 1:
      81            2348 :         v = load_little_endian<2>(p);
      82            2348 :         return (v & 0xC000) == 0x8000;
      83                 : 
      84                 :     // 3 bytes, second byte [A0, BF]
      85             665 :     case 2:
      86             665 :         v = load_little_endian<3>(p);
      87             665 :         return (v & 0xC0E000) == 0x80A000;
      88                 : 
      89                 :     // 3 bytes, second byte [80, BF]
      90            3882 :     case 3:
      91            3882 :         v = load_little_endian<3>(p);
      92            3882 :         return (v & 0xC0C000) == 0x808000;
      93                 : 
      94                 :     // 3 bytes, second byte [80, 9F]
      95             725 :     case 4:
      96             725 :         v = load_little_endian<3>(p);
      97             725 :         return (v & 0xC0E000) == 0x808000;
      98                 : 
      99                 :     // 4 bytes, second byte [90, BF]
     100            1310 :     case 5:
     101            1310 :         v = load_little_endian<4>(p);
     102            1310 :         return (v & 0xC0C0FF00) + 0x7F7F7000 <= 0x2F00;
     103                 : 
     104                 :     // 4 bytes, second byte [80, BF]
     105            2346 :     case 6:
     106            2346 :         v = load_little_endian<4>(p);
     107            2346 :         return (v & 0xC0C0C000) == 0x80808000;
     108                 : 
     109                 :     // 4 bytes, second byte [80, 8F]
     110            1539 :     case 7:
     111            1539 :         v = load_little_endian<4>(p);
     112            1539 :         return (v & 0xC0C0F000) == 0x80808000;
     113                 :     }
     114                 : }
     115                 : 
     116                 : class utf8_sequence
     117                 : {
     118                 :     char seq_[4];
     119                 :     uint16_t first_;
     120                 :     uint8_t size_;
     121                 : 
     122                 : public:
     123                 :     void
     124            3466 :     save(
     125                 :         const char* p,
     126                 :         std::size_t remain) noexcept
     127                 :     {
     128            3466 :         first_ = classify_utf8(*p );
     129            3466 :         if(remain >= length())
     130            1560 :             size_ = length();
     131                 :         else
     132            1906 :             size_ = static_cast<uint8_t>(remain);
     133            3466 :         std::memcpy(seq_, p, size_);
     134            3466 :     }
     135                 : 
     136                 :     uint8_t
     137           21338 :     length() const noexcept
     138                 :     {
     139           21338 :         return first_ & 0xFF;
     140                 :     }
     141                 : 
     142                 :     bool
     143            3469 :     complete() const noexcept
     144                 :     {
     145            3469 :         return size_ >= length();
     146                 :     }
     147                 : 
     148                 :     // returns true if complete
     149                 :     bool
     150            1864 :     append(
     151                 :         const char* p,
     152                 :         std::size_t remain) noexcept
     153                 :     {
     154            1864 :         if(BOOST_JSON_UNLIKELY(needed() == 0))
     155               1 :             return true;
     156            1863 :         if(BOOST_JSON_LIKELY(remain >= needed()))
     157                 :         {
     158            1862 :             std::memcpy(
     159            1862 :                 seq_ + size_, p, needed());
     160            1862 :             size_ = length();
     161            1862 :             return true;
     162                 :         }
     163               1 :         if(BOOST_JSON_LIKELY(remain > 0))
     164                 :         {
     165               1 :             std::memcpy(seq_ + size_, p, remain);
     166               1 :             size_ += static_cast<uint8_t>(remain);
     167                 :         }
     168               1 :         return false;
     169                 :     }
     170                 : 
     171                 :     const char*
     172            1658 :     data() const noexcept
     173                 :     {
     174            1658 :         return seq_;
     175                 :     }
     176                 : 
     177                 :     uint8_t
     178            7457 :     needed() const noexcept
     179                 :     {
     180            7457 :         return length() - size_;
     181                 :     }
     182                 : 
     183                 :     bool
     184            1866 :     valid() const noexcept
     185                 :     {
     186            1866 :         BOOST_ASSERT(size_ >= length());
     187            1866 :         return is_valid_utf8(seq_, first_);
     188                 :     }
     189                 : };
     190                 : 
     191                 : } // detail
     192                 : } // namespace json
     193                 : } // namespace boost
     194                 : 
     195                 : #endif
        

Generated by: LCOV version 2.3