HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
Grapheme.hpp
1// Copyright 2019, 2020 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/strings.hpp"
7#include "TTauri/Foundation/numeric_cast.hpp"
8#include "TTauri/Foundation/hash.hpp"
9#include <array>
10
11namespace tt {
12
13// "Compatibility mappings are guaranteed to be no longer than 18 characters, although most consist of just a few characters."
14// https://unicode.org/reports/tr44/ (TR44 5.7.3)
15using long_Grapheme = std::array<char32_t,18>;
16
20class Grapheme {
37 uint64_t value;
38
39public:
40 tt_force_inline Grapheme() noexcept : value(1) {}
41
42 tt_force_inline ~Grapheme() {
43 delete_pointer();
44 }
45
46 tt_force_inline Grapheme(const Grapheme& other) noexcept {
47 value = other.value;
48 if (other.has_pointer()) {
49 value = create_pointer(other.get_pointer()->data(), other.size());
50 }
51 }
52
53 tt_force_inline Grapheme& operator=(const Grapheme& other) noexcept {
54 if (this != &other) {
55 delete_pointer();
56 value = other.value;
57 if (other.has_pointer()) {
58 value = create_pointer(other.get_pointer()->data(), other.size());
59 }
60 }
61 return *this;
62 }
63
64 tt_force_inline Grapheme(Grapheme&& other) noexcept {
65 value = other.value;
66 other.value = 1;
67 }
68
69 tt_force_inline Grapheme& operator=(Grapheme&& other) noexcept {
70 delete_pointer();
71 value = other.value;
72 other.value = 1;
73 return *this;
74 }
75
76 explicit Grapheme(std::u32string_view codePoints) noexcept;
77
78 tt_force_inline explicit Grapheme(char32_t codePoint) noexcept :
79 Grapheme(std::u32string_view{&codePoint, 1}) {}
80
81 Grapheme& operator=(std::u32string_view codePoints) noexcept {
82 *this = Grapheme(codePoints);
83 return *this;
84 }
85
86 Grapheme& operator=(char32_t codePoint) noexcept {
87 *this = Grapheme(codePoint);
88 return *this;
89 }
90
91 explicit operator std::u32string () const noexcept {
92 if (has_pointer()) {
93 return {get_pointer()->data(), size()};
94 } else {
95 auto r = std::u32string{};
96 auto tmp = value >> 1;
97 for (size_t i = 0; i < 3; i++, tmp >>= 21) {
98 if (auto codePoint = static_cast<char32_t>(tmp & 0x1f'ffff)) {
99 r += codePoint;
100 } else {
101 return r;
102 }
103 }
104 return r;
105 }
106 }
107
108 operator bool () const noexcept {
109 return value != 1;
110 }
111
112 [[nodiscard]] size_t hash() const noexcept {
113 size_t r = 0;
114 for (ssize_t i = 0; i != ssize(*this); ++i) {
115 r = hash_mix_two(r, std::hash<char32_t>{}((*this)[i]));
116 }
117 return r;
118 }
119
120 [[nodiscard]] tt_force_inline size_t size() const noexcept {
121 if (has_pointer()) {
122 return value >> 48;
123 } else {
124 auto tmp = value >> 1;
125 size_t i;
126 for (i = 0; i < 3; i++, tmp >>= 21) {
127 if ((tmp & 0x1f'ffff) == 0) {
128 return i;
129 }
130 }
131 return i;
132 }
133 }
134
135 [[nodiscard]] char32_t front() const noexcept {
136 if (size() == 0) {
137 return 0;
138 } else {
139 return (*this)[0];
140 }
141 }
142
143 [[nodiscard]] char32_t operator[](size_t i) const noexcept {
144 if (has_pointer()) {
145 tt_assume(i < std::tuple_size_v<long_Grapheme>);
146 return (*get_pointer())[i];
147
148 } else {
149 tt_assume(i < 3);
150 return (value >> ((i * 21) + 1)) & 0x1f'ffff;
151 }
152 }
153
154 [[nodiscard]] std::u32string NFC() const noexcept {
156 r.reserve(ssize(*this));
157 for (ssize_t i = 0; i != ssize(*this); ++i) {
158 r += (*this)[i];
159 }
160 return r;
161 }
162
163 [[nodiscard]] std::u32string NFD() const noexcept;
164
165 [[nodiscard]] std::u32string NFKC() const noexcept;
166
167 [[nodiscard]] std::u32string NFKD() const noexcept;
168
169 [[nodiscard]] friend std::string to_string(Grapheme const &g) noexcept {
170 return tt::to_string(g.NFC());
171 }
172
173 friend std::ostream &operator<<(std::ostream &lhs, Grapheme const &rhs) {
174 return lhs << to_string(rhs);
175 }
176
177private:
178 [[nodiscard]] tt_force_inline bool has_pointer() const noexcept {
179 return (value & 1) == 0;
180 }
181
182 [[nodiscard]] static uint64_t create_pointer(char32_t const *data, size_t size) noexcept {
183 tt_assert(size <= std::tuple_size<long_Grapheme>::value);
184
185 auto ptr = new long_Grapheme();
186 memcpy(ptr->data(), data, size);
187
188 auto iptr = reinterpret_cast<ptrdiff_t>(ptr);
189 auto uptr = static_cast<uint64_t>(iptr << 16) >> 16;
190 return (size << 48) | uptr;
191 }
192
193 [[nodiscard]] tt_force_inline long_Grapheme *get_pointer() const noexcept {
194 auto uptr = (value << 16);
195 auto iptr = static_cast<ptrdiff_t>(uptr) >> 16;
196 return std::launder(reinterpret_cast<long_Grapheme *>(iptr));
197 }
198
199 tt_force_inline void delete_pointer() noexcept {
200 if (has_pointer()) {
201 delete get_pointer();
202 }
203 }
204
205 [[nodiscard]] friend bool operator<(Grapheme const& a, Grapheme const& b) noexcept {
206 ttlet length = std::min(ssize(a), ssize(b));
207
208 for (ssize_t i = 0; i != length; ++i) {
209 if (a[i] < b[i]) {
210 return true;
211 }
212 }
213 return ssize(a) < ssize(b);
214 }
215
216 [[nodiscard]] friend bool operator==(Grapheme const& a, Grapheme const& b) noexcept {
217 if (a.value == b.value) {
218 return true;
219 }
220
221 if (ssize(a) != ssize(b)) {
222 return false;
223 }
224
225 for (ssize_t i = 0; i != ssize(a); ++i) {
226 if (a[i] != b[i]) {
227 return false;
228 }
229 }
230 return true;
231 }
232
233 [[nodiscard]] friend bool operator==(Grapheme const &lhs, char32_t const &rhs) noexcept {
234 return (ssize(lhs) == 1) && (lhs[0] == rhs);
235 }
236
237 [[nodiscard]] friend bool operator!=(Grapheme const &lhs, char32_t const &rhs) noexcept {
238 return !(lhs == rhs);
239 }
240
241 [[nodiscard]] friend bool operator==(Grapheme const &lhs, char const &rhs) noexcept {
242 return lhs == static_cast<char32_t>(rhs);
243 }
244
245 [[nodiscard]] friend bool operator!=(Grapheme const &lhs, char const &rhs) noexcept {
246 return !(lhs == rhs);
247 }
248
249};
250
251}
252
253namespace std {
254
255template<>
256struct hash<tt::Grapheme> {
257 [[nodiscard]] size_t operator() (tt::Grapheme const &rhs) const noexcept {
258 return rhs.hash();
259 }
260};
261
262}
STL namespace.
Definition Grapheme.hpp:20
T data(T... args)
T min(T... args)
T operator()(T... args)
T reserve(T... args)