HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
gstring.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "grapheme.hpp"
8#include "unicode_normalization.hpp"
9#include "unicode_grapheme_cluster_break.hpp"
10#include "../utility/utility.hpp"
11#include "../i18n/i18n.hpp"
12#include "../time/time.hpp" // XXX #616
13#include "../macros.hpp"
14#include <vector>
15#include <string>
16#include <string_view>
17#include <type_traits>
18#include <iterator>
19#include <concepts>
20#include <ios>
21#include <cuchar>
22#include <cwchar>
23#include <compare>
24
25hi_export_module(hikogui.unicode.gstring);
26
27hi_export namespace std {
28
29template<>
30struct char_traits<hi::grapheme> {
31 using char_type = hi::grapheme;
32 using int_type = std::make_signed_t<char_type::value_type>;
36 using comparison_category = std::strong_ordering;
37
38 constexpr static void assign(char_type& r, char_type const& a) noexcept
39 {
40 r = a;
41 }
42
43 constexpr static char_type *assign(char_type *p, std::size_t count, char_type a) noexcept
44 {
45 hi_axiom_not_null(p);
46 for (std::size_t i = 0; i != count; ++i) {
47 p[i] = a;
48 }
49 return p;
50 }
51
52 [[nodiscard]] constexpr static bool eq(char_type a, char_type b) noexcept
53 {
54 return a == b;
55 }
56
57 [[nodiscard]] constexpr static bool lt(char_type a, char_type b) noexcept
58 {
59 return a < b;
60 }
61
62 constexpr static char_type *move(char_type *dst, char_type const *src, std::size_t count) noexcept
63 {
64 hi_axiom_not_null(src);
65 hi_axiom_not_null(dst);
66
67 if (src >= dst) {
68 for (std::size_t i = 0; i != count; ++i) {
69 dst[i] = src[i];
70 }
71 } else {
72 for (std::size_t i = count; i != 0; --i) {
73 dst[i - 1] = src[i - 1];
74 }
75 }
76 return dst;
77 }
78
79 constexpr static char_type *copy(char_type *dst, char_type const *src, std::size_t count) noexcept
80 {
81 hi_axiom_not_null(src);
82 hi_axiom_not_null(dst);
83
84 for (std::size_t i = 0; i != count; ++i) {
85 dst[i] = src[i];
86 }
87 return dst;
88 }
89
90 constexpr static int compare(char_type const *s1, char_type const *s2, std::size_t count) noexcept
91 {
92 hi_axiom_not_null(s1);
93 hi_axiom_not_null(s2);
94
95 for (std::size_t i = 0; i != count; ++i) {
96 if (s1[i] != s2[i]) {
97 return s1[i] < s2[i] ? -1 : 1;
98 }
99 }
100 return 0;
101 }
102
103 constexpr static std::size_t length(char_type const *s) noexcept
104 {
105 hi_axiom_not_null(s);
106
107 std::size_t i = 0;
108 while (s[i] != '\0') {
109 ++i;
110 }
111 return i;
112 }
113
114 constexpr static char_type const *find(const char_type *p, std::size_t count, const char_type& ch) noexcept
115 {
116 hi_axiom_not_null(p);
117
118 for (std::size_t i = 0; i != count; ++i, ++p) {
119 if (*p == ch) {
120 return p;
121 }
122 }
123 return nullptr;
124 }
125
126 constexpr static char_type to_char_type(int_type c) noexcept
127 {
128 return c < 0 ? char_type{U'\ufffd'} : char_type{std::in_place, hi::char_cast<char_type::value_type>(c)};
129 }
130
131 constexpr static int_type to_int_type(char_type c) noexcept
132 {
133 return hi::char_cast<int_type>(c.intrinsic());
134 }
135
136 constexpr static bool eq_int_type(int_type c1, int_type c2) noexcept
137 {
138 return c1 == c2;
139 }
140
141 constexpr static int_type eof() noexcept
142 {
143 return -1;
144 }
145
146 constexpr static int_type not_eof(int_type e) noexcept
147 {
148 return e < 0 ? 0 : e;
149 }
150};
151
152}
153
154hi_export namespace hi::inline v1 {
155
156using gstring = std::basic_string<grapheme>;
157using gstring_view = std::basic_string_view<grapheme>;
158
159
160[[nodiscard]] constexpr bool operator==(gstring_view const &lhs, std::string_view const &rhs) noexcept
161{
162 if (lhs.size() != rhs.size()) {
163 return false;
164 }
165
166 auto l_it = lhs.begin();
167 auto l_last = lhs.end();
168 auto r_it = rhs.begin();
169
170 for (; l_it != l_last; ++l_it, ++r_it) {
171 if (*l_it != *r_it) {
172 return false;
173 }
174 }
175 return true;
176}
177
186template<std::input_or_output_iterator It, std::sentinel_for<It> ItEnd>
187constexpr void set_language(It first, ItEnd last, language_tag language) noexcept
188{
189 language = language.expand();
190
191 for (auto it = first; it != last; ++it) {
192 it->set_language_tag(language);
193 }
194}
195
196[[nodiscard]] constexpr gstring set_language(gstring str, language_tag language) noexcept
197{
198 set_language(str.begin(), str.end(), language);
199 return str;
200}
201
219template<std::input_or_output_iterator It, std::sentinel_for<It> ItEnd>
220constexpr void fix_language(It first, ItEnd last, language_tag default_language_tag) noexcept
221 requires(std::is_same_v<std::iter_value_t<It>, grapheme>)
222{
223 if (first == last) {
224 return;
225 }
226
227 auto const first_language_it = std::find_if(first, last, [](auto &x) { return x.language(); });
228 if (first_language_it != last) {
229 default_language_tag = first_language_it->language_tag().expand();
230 } else {
231 default_language_tag = default_language_tag.expand();
232 }
233
234 for (auto it = first; it != first_language_it; ++it) {
235 it->set_language_tag(default_language_tag);
236 }
237
238 for (auto it = first_language_it; it != last; ++it) {
239 if (not it->language()) {
240 it->set_language_tag(default_language_tag);
241 } else {
242 it->set_language_tag(it->language_tag().expand());
243 }
244 }
245}
246
247[[nodiscard]] constexpr gstring fix_language(gstring str, language_tag default_language_tag) noexcept
248{
249 fix_language(str.begin(), str.end(), default_language_tag);
250 return str;
251}
252
262[[nodiscard]] constexpr gstring
263to_gstring(std::u32string_view rhs, unicode_normalize_config config = unicode_normalize_config::NFC()) noexcept
264{
265 auto const normalized_string = unicode_normalize(rhs, config);
266
267 auto r = gstring{};
268 auto break_state = detail::grapheme_break_state{};
269 auto cluster = std::u32string{};
270
271 for (auto const code_point : normalized_string) {
272 if (detail::breaks_grapheme(code_point, break_state)) {
273 if (cluster.size() > 0) {
274 r += grapheme(composed_t{}, cluster);
275 }
276 cluster.clear();
277 }
278
279 cluster += code_point;
280 }
281 if (ssize(cluster) != 0) {
282 r += grapheme(composed_t{}, cluster);
283 }
284 return r;
285}
286
296[[nodiscard]] constexpr gstring
297to_gstring(std::string_view rhs, unicode_normalize_config config = unicode_normalize_config::NFC()) noexcept
298{
299 return to_gstring(to_u32string(rhs), config);
300}
301
307[[nodiscard]] constexpr std::string to_string(gstring_view rhs) noexcept
308{
309 auto r = std::string{};
310 r.reserve(rhs.size());
311 for (auto const c : rhs) {
312 r += to_string(c);
313 }
314 return r;
315}
316
322[[nodiscard]] constexpr std::wstring to_wstring(gstring_view rhs) noexcept
323{
324 auto r = std::wstring{};
325 r.reserve(rhs.size());
326 for (auto const c : rhs) {
327 r += to_wstring(c);
328 }
329 return r;
330}
331
337[[nodiscard]] constexpr std::u32string to_u32string(gstring_view rhs) noexcept
338{
339 auto r = std::u32string{};
340 r.reserve(rhs.size());
341 for (auto const c : rhs) {
342 r += to_u32string(c);
343 }
344 return r;
345}
346
352[[nodiscard]] constexpr std::string to_string(gstring const& rhs) noexcept
353{
354 return to_string(gstring_view{rhs});
355}
356
357} // namespace hi::inline v1
358
359hi_export namespace std {
360
361template<>
362struct hash<hi::gstring> {
363 [[nodiscard]] std::size_t operator()(hi::gstring const& rhs) noexcept
364 {
365 auto r = std::hash<std::size_t>{}(rhs.size());
366 for (auto const c : rhs) {
367 r = hi::hash_mix_two(r, std::hash<hi::grapheme>{}(c));
368 }
369 return r;
370 }
371};
372
373}
constexpr std::u32string to_u32string(std::u32string_view rhs) noexcept
Identity conversion from UTF-32 to UTF-32.
Definition to_string.hpp:28
constexpr std::wstring to_wstring(std::u32string_view rhs) noexcept
Conversion from UTF-32 to wide-string (UTF-16/32).
Definition to_string.hpp:160
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
constexpr void fix_language(It first, ItEnd last, language_tag default_language_tag) noexcept
Fix the language for the string.
Definition gstring.hpp:220
constexpr gstring to_gstring(std::u32string_view rhs, unicode_normalize_config config=unicode_normalize_config::NFC()) noexcept
Convert a UTF-32 string-view to a grapheme-string.
Definition gstring.hpp:263
constexpr void set_language(It first, ItEnd last, language_tag language) noexcept
Set the language for the string.
Definition gstring.hpp:187
constexpr std::u32string unicode_normalize(std::u32string_view text, unicode_normalize_config config=unicode_normalize_config::NFC()) noexcept
Convert text to a Unicode composed normal form.
Definition unicode_normalization.hpp:308
Definition grapheme.hpp:154
A grapheme-cluster, what a user thinks a character is.
Definition grapheme.hpp:167
Definition unicode_normalization.hpp:24
T assign(T... args)
T eq(T... args)
T compare(T... args)
T copy(T... args)
T count(T... args)
T eof(T... args)
T eq_int_type(T... args)
T find(T... args)
T length(T... args)
T move(T... args)
T not_eof(T... args)
T operator()(T... args)
T reserve(T... args)
T to_char_type(T... args)
T to_int_type(T... args)