10 #include <string_view>
16 using type = std::uint32_t;
35 for (
auto& b : data_) {
45 data_[0] =
first & 0xFF;
46 data_[1] = (
first >> 8) & 0xFF;
47 data_[2] = (
first >> 16) & 0x1F;
49 data_[2] |= (
last & 0x7) << 5;
50 data_[3] = (
last >> 3) & 0xFF;
51 data_[4] = (
last >> 11) & 0xFF;
52 data_[5] = (
last >> 19) & 0x3;
54 data_[5] |= (
meta & 0x3F) << 2;
65 auto value =
type{data_[0]};
66 value |= data_[1] << 8;
67 value |= (data_[2] & 0x1F) << 16;
77 [[nodiscard]] constexpr
type last() const noexcept
80 type value = (data_[2] >> 5) & 0x7;
81 value |= data_[3] << 3;
82 value |= data_[4] << 11;
83 value |= (data_[5] & 0x3) << 19;
93 [[nodiscard]] constexpr std::uint8_t
meta() const noexcept
96 return (data_[5] >> 2) & 0x3F;
106 if (
first() == other.first()) {
107 return last() < other.last();
109 return first() < other.first();
120 constexpr
static auto bytes_per_cp = std::size_t{6};
121 std::array<std::uint8_t, bytes_per_cp> data_;
129 [[nodiscard]]
inline constexpr std::size_t
count(std::string_view str) noexcept
132 constexpr
auto high_2_bit_mask = std::uint8_t{0xC0};
133 constexpr
auto high_bit = std::uint8_t{0x80};
135 auto result = std::size_t{0};
137 result += (c & high_2_bit_mask) != high_bit;
148 [[nodiscard]]
inline constexpr std::size_t
size(std::string_view str) noexcept
154 const auto first_byte =
static_cast<std::uint8_t
>(str[0]);
157 constexpr
auto is_ascii_mask = std::uint8_t{0b1000'0000};
158 if ((first_byte & is_ascii_mask) == 0) {
164 constexpr
auto max_2_byte_header = std::uint8_t{0b1101'1111};
165 if (first_byte < max_2_byte_header) {
169 constexpr
auto max_3_byte_header = std::uint8_t{0b1110'1111};
170 if (first_byte < max_3_byte_header) {
184 [[nodiscard]]
inline constexpr std::optional<type>
decode(std::string_view str) noexcept
186 const auto bytes_to_read =
size(str);
187 if (bytes_to_read == 0) {
191 if (bytes_to_read == 1) {
196 if (str.size() < bytes_to_read) {
200 constexpr
auto subsequent_byte_data_bits = 6;
201 constexpr
auto subsequent_byte_mask =
type{(1 << subsequent_byte_data_bits) - 1};
202 constexpr
auto maximum_first_byte_data_mask =
type{0b0001'1111};
204 const auto first_byte =
static_cast<std::uint8_t
>(str[0]);
206 auto result = first_byte & (maximum_first_byte_data_mask >> (bytes_to_read - 2));
207 for (
auto i = 1u; i < bytes_to_read; ++i) {
208 const auto subsequent_byte =
static_cast<type>(str[i]);
211 result <<= subsequent_byte_data_bits;
212 result |= subsequent_byte & subsequent_byte_mask;
260 constexpr
explicit range_t(std::string_view str) noexcept : str_{str} {}
262 std::string_view str_;
270 [[nodiscard]] constexpr
static range_t range(std::string_view str) noexcept
286 constexpr explicit
iterator(std::string_view str) noexcept : str_{str} {}
296 if (str_.empty() && other.str_.empty()) {
299 return (str_.data() == other.str_.data()) && (str_.size() == other.str_.size());
309 return !(*
this == other);
319 return str_.substr(0, num_bytes);
329 str_.remove_prefix(num_bytes);
346 std::string_view str_;
constexpr iterator begin() noexcept
constexpr static iterator end() noexcept
constexpr iterator operator++(int) noexcept
const value_type * pointer
constexpr bool operator!=(iterator other) const noexcept
constexpr iterator() noexcept=default
std::forward_iterator_tag iterator_category
std::string_view value_type
constexpr static range_t range(std::string_view str) noexcept
std::string_view::difference_type difference_type
const value_type & reference
constexpr iterator & operator++() noexcept
constexpr value_type operator*() const noexcept
constexpr bool operator==(iterator other) const noexcept
constexpr type first() const noexcept
constexpr range(type first, type last, std::uint8_t meta=0) noexcept
constexpr std::uint8_t meta() const noexcept
constexpr bool operator<(type cp) const noexcept
constexpr type last() const noexcept
constexpr bool operator<(range other) const noexcept
constexpr std::optional< type > decode(std::string_view str) noexcept
constexpr std::size_t count(std::string_view str) noexcept
constexpr std::size_t size(std::string_view str) noexcept