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 "../macros.hpp"
12#include <vector>
13#include <string>
14#include <type_traits>
15#include <iterator>
16
17
18hi_export template<>
19struct std::char_traits<hi::grapheme> {
20 using char_type = hi::grapheme;
21 using int_type = std::make_signed_t<char_type::value_type>;
25 using comparison_category = std::strong_ordering;
26
27 constexpr static void assign(char_type& r, char_type const& a) noexcept
28 {
29 r = a;
30 }
31
32 constexpr static char_type *assign(char_type *p, std::size_t count, char_type a) noexcept
33 {
34 hi_axiom_not_null(p);
35 for (std::size_t i = 0; i != count; ++i) {
36 p[i] = a;
37 }
38 return p;
39 }
40
41 [[nodiscard]] constexpr static bool eq(char_type a, char_type b) noexcept
42 {
43 return a == b;
44 }
45
46 [[nodiscard]] constexpr static bool lt(char_type a, char_type b) noexcept
47 {
48 return a < b;
49 }
50
51 constexpr static char_type *move(char_type *dst, char_type const *src, std::size_t count) noexcept
52 {
53 hi_axiom_not_null(src);
54 hi_axiom_not_null(dst);
55
56 if (src >= dst) {
57 for (std::size_t i = 0; i != count; ++i) {
58 dst[i] = src[i];
59 }
60 } else {
61 for (std::size_t i = count; i != 0; --i) {
62 dst[i - 1] = src[i - 1];
63 }
64 }
65 return dst;
66 }
67
68 constexpr static char_type *copy(char_type *dst, char_type const *src, std::size_t count) noexcept
69 {
70 hi_axiom_not_null(src);
71 hi_axiom_not_null(dst);
72
73 for (std::size_t i = 0; i != count; ++i) {
74 dst[i] = src[i];
75 }
76 return dst;
77 }
78
79 constexpr static int compare(char_type const *s1, char_type const *s2, std::size_t count) noexcept
80 {
81 hi_axiom_not_null(s1);
82 hi_axiom_not_null(s2);
83
84 for (std::size_t i = 0; i != count; ++i) {
85 if (s1[i] != s2[i]) {
86 return s1[i] < s2[i] ? -1 : 1;
87 }
88 }
89 return 0;
90 }
91
92 constexpr static std::size_t length(char_type const *s) noexcept
93 {
94 hi_axiom_not_null(s);
95
96 std::size_t i = 0;
97 while (s[i] != '\0') {
98 ++i;
99 }
100 return i;
101 }
102
103 constexpr static char_type const *find(const char_type *p, std::size_t count, const char_type& ch) noexcept
104 {
105 hi_axiom_not_null(p);
106
107 for (std::size_t i = 0; i != count; ++i, ++p) {
108 if (*p == ch) {
109 return p;
110 }
111 }
112 return nullptr;
113 }
114
115 constexpr static char_type to_char_type(int_type c) noexcept
116 {
117 return c < 0 ? char_type{U'\ufffd'} : char_type{hi::intrinsic_t{}, hi::char_cast<char_type::value_type>(c)};
118 }
119
120 constexpr static int_type to_int_type(char_type c) noexcept
121 {
122 return hi::char_cast<int_type>(c.intrinsic());
123 }
124
125 constexpr static bool eq_int_type(int_type c1, int_type c2) noexcept
126 {
127 return c1 == c2;
128 }
129
130 constexpr static int_type eof() noexcept
131 {
132 return -1;
133 }
134
135 constexpr static int_type not_eof(int_type e) noexcept
136 {
137 return e < 0 ? 0 : e;
138 }
139};
140
141namespace hi::inline v1 {
142
143hi_export using gstring = std::basic_string<grapheme>;
144hi_export using gstring_view = std::basic_string_view<grapheme>;
145
146namespace pmr {
147hi_export using gstring = std::pmr::basic_string<grapheme>;
148}
149
150
151[[nodiscard]] constexpr bool operator==(gstring_view const &lhs, std::string_view const &rhs) noexcept
152{
153 if (lhs.size() != rhs.size()) {
154 return false;
155 }
156
157 auto l_it = lhs.begin();
158 auto l_last = lhs.end();
159 auto r_it = rhs.begin();
160
161 for (; l_it != l_last; ++l_it, ++r_it) {
162 if (*l_it != *r_it) {
163 return false;
164 }
165 }
166 return true;
167}
168
177hi_export template<std::input_or_output_iterator It, std::sentinel_for<It> ItEnd>
178constexpr void set_language(It first, ItEnd last, language_tag language) noexcept
179{
180 language = language.expand();
181
182 for (auto it = first; it != last; ++it) {
183 it->set_language_tag(language);
184 }
185}
186
187hi_export [[nodiscard]] constexpr gstring set_language(gstring str, language_tag language) noexcept
188{
189 set_language(str.begin(), str.end(), language);
190 return str;
191}
192
210hi_export template<std::input_or_output_iterator It, std::sentinel_for<It> ItEnd>
211constexpr void fix_language(It first, ItEnd last, language_tag default_language_tag) noexcept
212 requires(std::is_same_v<std::iter_value_t<It>, grapheme>)
213{
214 if (first == last) {
215 return;
216 }
217
218 hilet first_language_it = std::find_if(first, last, [](auto &x) { return x.language(); });
219 if (first_language_it != last) {
220 default_language_tag = first_language_it->language_tag().expand();
221 } else {
223 }
224
225 for (auto it = first; it != first_language_it; ++it) {
226 it->set_language_tag(default_language_tag);
227 }
228
229 for (auto it = first_language_it; it != last; ++it) {
230 if (not it->language()) {
231 it->set_language_tag(default_language_tag);
232 } else {
233 it->set_language_tag(it->language_tag().expand());
234 }
235 }
236}
237
238hi_export [[nodiscard]] constexpr gstring fix_language(gstring str, language_tag default_language_tag) noexcept
239{
240 fix_language(str.begin(), str.end(), default_language_tag);
241 return str;
242}
243
253hi_export [[nodiscard]] constexpr gstring
254to_gstring(std::u32string_view rhs, unicode_normalize_config config = unicode_normalize_config::NFC()) noexcept
255{
257
258 auto r = gstring{};
259 auto break_state = detail::grapheme_break_state{};
260 auto cluster = std::u32string{};
261
262 for (hilet code_point : normalized_string) {
263 if (detail::breaks_grapheme(code_point, break_state)) {
264 if (cluster.size() > 0) {
265 r += grapheme(composed_t{}, cluster);
266 }
267 cluster.clear();
268 }
269
270 cluster += code_point;
271 }
272 if (ssize(cluster) != 0) {
273 r += grapheme(composed_t{}, cluster);
274 }
275 return r;
276}
277
287hi_export [[nodiscard]] constexpr gstring
288to_gstring(std::string_view rhs, unicode_normalize_config config = unicode_normalize_config::NFC()) noexcept
289{
290 return to_gstring(to_u32string(rhs), config);
291}
292
298hi_export [[nodiscard]] constexpr std::string to_string(gstring_view rhs) noexcept
299{
300 auto r = std::string{};
301 r.reserve(rhs.size());
302 for (hilet c : rhs) {
303 r += to_string(c);
304 }
305 return r;
306}
307
313hi_export [[nodiscard]] constexpr std::wstring to_wstring(gstring_view rhs) noexcept
314{
315 auto r = std::wstring{};
316 r.reserve(rhs.size());
317 for (hilet c : rhs) {
318 r += to_wstring(c);
319 }
320 return r;
321}
322
328hi_export [[nodiscard]] constexpr std::u32string to_u32string(gstring_view rhs) noexcept
329{
330 auto r = std::u32string{};
331 r.reserve(rhs.size());
332 for (hilet c : rhs) {
333 r += to_u32string(c);
334 }
335 return r;
336}
337
343hi_export [[nodiscard]] constexpr std::string to_string(gstring const& rhs) noexcept
344{
345 return to_string(gstring_view{rhs});
346}
347
348} // namespace hi::inline v1
349
350hi_export template<>
351struct std::hash<hi::gstring> {
352 [[nodiscard]] std::size_t operator()(hi::gstring const& rhs) noexcept
353 {
354 auto r = std::hash<std::size_t>{}(rhs.size());
355 for (hilet c : rhs) {
356 r = hi::hash_mix_two(r, std::hash<hi::grapheme>{}(c));
357 }
358 return r;
359 }
360};
361
362hi_export template<>
363struct std::hash<hi::pmr::gstring> {
364 [[nodiscard]] std::size_t operator()(hi::pmr::gstring const& rhs) noexcept
365 {
366 auto r = std::hash<std::size_t>{}(rhs.size());
367 for (hilet c : rhs) {
368 r = hi::hash_mix_two(r, std::hash<hi::grapheme>{}(c));
369 }
370 return r;
371 }
372};
constexpr std::u32string to_u32string(std::u32string_view rhs) noexcept
Identity conversion from UTF-32 to UTF-32.
Definition to_string.hpp:24
constexpr std::wstring to_wstring(std::u32string_view rhs) noexcept
Conversion from UTF-32 to wide-string (UTF-16/32).
Definition to_string.hpp:156
DOXYGEN BUG.
Definition algorithm.hpp:16
hi_export constexpr void fix_language(It first, ItEnd last, language_tag default_language_tag) noexcept
Fix the language for the string.
Definition gstring.hpp:211
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:306
hi_export constexpr void set_language(It first, ItEnd last, language_tag language) noexcept
Set the language for the string.
Definition gstring.hpp:178
hi_export 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:254
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition grapheme.hpp:147
A grapheme-cluster, what a user thinks a character is.
Definition grapheme.hpp:160
Definition unicode_normalization.hpp:22
Tag used in constructors to set the intrinsic value of that object.
Definition misc.hpp:86
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)