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

            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        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.1