A11 (C++ runtime)
Native C++ implementation of the A11 streaming action runtime
Loading...
Searching...
No Matches
utf8.h
Go to the documentation of this file.
1/*
2 * Copyright 2026 The A11 Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
27#ifndef A11_UTF8_H_
28#define A11_UTF8_H_
29
30#include <cstddef>
31#include <cstdint>
32#include <string_view>
33
34namespace a11::utf8 {
35
37inline bool IsContinuation(char byte) {
38 return (static_cast<unsigned char>(byte) & 0xC0U) == 0x80U;
39}
40
48inline size_t SequenceWidth(char lead) {
49 const auto byte = static_cast<unsigned char>(lead);
50 if (byte >= 0xF0U) {
51 return 4;
52 }
53 if (byte >= 0xE0U) {
54 return 3;
55 }
56 if (byte >= 0xC0U) {
57 return 2;
58 }
59 return 1;
60}
61
64inline size_t Utf16Units(char lead) {
65 return static_cast<unsigned char>(lead) >= 0xF0U ? 2 : 1;
66}
67
77inline bool IsValid(std::string_view text) {
78 // The smallest code point each width may encode; anything smaller is an
79 // overlong form of a shorter sequence.
80 static constexpr std::uint32_t kSmallest[] = {0, 0, 0x80, 0x800, 0x10000};
81 size_t at = 0;
82 while (at < text.size()) {
83 const auto lead = static_cast<unsigned char>(text[at]);
84 if (lead < 0x80U) {
85 ++at;
86 continue;
87 }
88 size_t width = 0;
89 std::uint32_t point = 0;
90 if ((lead & 0xE0U) == 0xC0U) {
91 width = 2;
92 point = lead & 0x1FU;
93 } else if ((lead & 0xF0U) == 0xE0U) {
94 width = 3;
95 point = lead & 0x0FU;
96 } else if ((lead & 0xF8U) == 0xF0U) {
97 width = 4;
98 point = lead & 0x07U;
99 } else {
100 // A continuation byte with no lead, or a 5-byte form UTF-8 has not had
101 // since 2003.
102 return false;
103 }
104 if (text.size() - at < width) {
105 return false;
106 }
107 for (size_t index = 1; index < width; ++index) {
108 if (!IsContinuation(text[at + index])) {
109 return false;
110 }
111 point = (point << 6U) |
112 (static_cast<unsigned char>(text[at + index]) & 0x3FU);
113 }
114 if (point < kSmallest[width] || point > 0x10FFFFU ||
115 (point >= 0xD800U && point <= 0xDFFFU)) {
116 return false;
117 }
118 at += width;
119 }
120 return true;
121}
122
123} // namespace a11::utf8
124
125#endif // A11_UTF8_H_
std::optional< std::string > text
The text, where the value is a string literal or a name bound to one.
Definition discover.cc:612
Definition utf8.h:34
bool IsContinuation(char byte)
Whether byte is a continuation byte – the middle of a character.
Definition utf8.h:37
size_t SequenceWidth(char lead)
Bytes in the sequence lead starts, from the lead byte alone.
Definition utf8.h:48
size_t Utf16Units(char lead)
UTF-16 code units the character at lead occupies: 2 above the BMP, else.
Definition utf8.h:64
bool IsValid(std::string_view text)
Whether text is well-formed UTF-8.
Definition utf8.h:77