1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
#ifndef U16_HH
#define U16_HH
#include <cstdint> // IWYU pragma: export
#include <expected>
#include <iterator>
#include <type_traits>
#include "u.hh" // IWYU pragma: export
namespace u16 {
template<std::forward_iterator T>
requires std::is_same_v<std::iter_value_t<T>, uint16_t>
std::expected<uint32_t, u::ReadError> read(T& start, const T& end) {
if (start == end) return std::unexpected(u::ReadError::End);
uint16_t u = *start;
if (u >= 0xd800 && u <= 0xdbff) {
if (std::distance(start, end) < 2) {
return std::unexpected(u::ReadError::Incomplete);
}
std::advance(start, 1);
if (*start >= 0xdc00 && *start <= 0xdfff) {
uint16_t v = *start;
std::advance(start, 1);
return 0x10000 + (((u - 0xd800) << 10) | (v - 0xdc00));
}
return std::unexpected(u::ReadError::Invalid);
}
std::advance(start, 1);
if (u >= 0xdc00 && u <= 0xdfff) {
return std::unexpected(u::ReadError::Invalid);
}
return u;
}
template<std::forward_iterator T>
requires std::is_same_v<std::iter_value_t<T>, uint16_t>
std::expected<uint32_t, u::ReadErrorReplace> read_replace(T& start,
const T& end) {
auto ret = read(start, end);
if (ret.has_value())
return *ret;
switch (ret.error()) {
case u::ReadError::Incomplete:
return std::unexpected(u::ReadErrorReplace::Incomplete);
case u::ReadError::End:
return std::unexpected(u::ReadErrorReplace::End);
case u::ReadError::Invalid:
return 0xfffd;
}
}
template<std::forward_iterator T>
requires std::is_same_v<std::iter_value_t<T>, uint16_t>
bool write(T& start, const T& end, uint32_t code) {
if (code < 0x10000) {
if (start == end) return false;
*start = static_cast<uint16_t>(code);
} else {
if (std::distance(start, end) < 2) return false;
code -= 0x10000;
*start = static_cast<uint16_t>(0xd800 + (code >> 10));
std::advance(start, 1);
*start = static_cast<uint16_t>(0xdc00 + (code & 0x3ff));
}
std::advance(start, 1);
return true;
}
template<std::forward_iterator T>
requires std::is_same_v<std::iter_value_t<T>, uint16_t>
bool skip(T& start, const T& end) {
if (start == end) return false;
if (*start >= 0xd800 && *start <= 0xdbff) {
if (std::distance(start, end) < 2) return false;
std::advance(start, 2);
return true;
}
std::advance(start, 1);
return true;
}
} // namespace u16
#endif // U16_HH
|