CommonLib
Loading...
Searching...
No Matches
encoding.inl
Go to the documentation of this file.
1#include <type_traits>
2
3#include "../thirdparty/simdutf/singleheader/simdutf.h"
4#include "expr/encoding_expr.h"
5#include "expr/string_expr.h"
6#include "mem/mem.h"
8#include "preprocessor.h"
9
10#define __CMNLIB_INTERNAL_STATIC_LIB_ENROLMENT
11
12namespace hedgedev::csl::ut::encoding
13{
14 template <expr::basic_string T_result, expr::any_string T_str>
16 {
17 T_result result{};
18
19 try_convert<T_result, T_str>(in_str, result, in_dst_encoding, in_src_encoding);
20
21 return result;
22 }
23
24 template <encoding_type dst_encoding, expr::any_string T_str, expr::any_string T_result>
25 inline T_result convert(const T_str& in_str)
26 {
27 return convert<T_result, T_str>(in_str, dst_encoding, expr::get_char_encoding_type<T_str>());
28 }
29
31 {
32 switch (in_encoding)
33 {
34 case encoding::utf8:
35 return { 0xEF, 0xBB, 0xBF };
36
38 return { 0xFF, 0xFE };
39
41 return { 0xFE, 0xFF };
42
44 return { 0xFF, 0xFE, 0x00, 0x00 };
45
47 return { 0x00, 0x00, 0xFE, 0xFF };
48 }
49
50 return {};
51 }
52
54 {
55 switch (in_encoding)
56 {
57 case encoding::utf8:
58 return 3;
59
62 return 2;
63
66 return 4;
67 }
68
69 return 0;
70 }
71
72 template <encoding_type encoding>
73 inline constexpr size_t get_bom_length()
74 {
75 return get_bom_length(encoding);
76 }
77
78 template <expr::any_string... T_args, typename T_result>
79 inline std::array<T_result, sizeof...(T_args)> precedent_convert(const T_args&... in_args)
80 {
81 std::array<T_result, sizeof...(T_args)> result{};
82
83 const auto args = std::make_tuple(in_args...);
84 constexpr auto precedence = expr::get_string_type_precedence<T_args...>();
85
86 [&] <size_t... index>(std::index_sequence<index...>)
87 {
88 const auto convert_arg = [&] <expr::any_string T>(const size_t in_index, const T& in_str)
89 {
90 if constexpr (expr::is_all_same_v<T_args...>)
91 {
92 if constexpr (expr::any_raw_string<T>)
93 {
94 // Create inferred string from C string.
95 result[in_index] = T_result(in_str);
96 }
97 else
98 {
99 // Copy original string.
100 result[in_index] = in_str;
101 }
102 }
103 else
104 {
105 if constexpr (std::is_same_v<T, T_result>)
106 {
107 // Copy original string.
108 result[in_index] = in_str;
109 }
110 else
111 {
112 // Convert string to precedent type.
113 result[in_index] = convert<T_result>(in_str);
114 }
115 }
116 };
117
118 (convert_arg(index, std::get<index>(args)), ...);
119 }
120 (std::make_index_sequence<sizeof...(T_args)>{});
121
122 return result;
123 }
124
125 template <expr::basic_string T_result, expr::any_string T_str>
126 inline bool try_convert(const T_str& in_str, T_result& out_result, encoding_type in_dst_encoding, encoding_type in_src_encoding)
127 {
128 using src_char_t = expr::get_char_type_t<T_str>;
129 using dst_char_t = expr::get_char_type_t<T_result>;
130 using inferred_string_view_t = expr::inferred_string_view_t<T_str>;
131
132 inferred_string_view_t str_sv{};
133
134 if constexpr (std::ranges::range<T_str>)
135 {
136 str_sv = inferred_string_view_t(in_str.begin(), in_str.end());
137 }
138 else if constexpr (std::is_constructible_v<inferred_string_view_t, const T_str&>)
139 {
140 str_sv = inferred_string_view_t(in_str);
141 }
142 else
143 {
144 return false;
145 }
146
147 if constexpr (std::is_same_v<src_char_t, dst_char_t>)
148 {
149 // If the encoding types match the string character types, create
150 // an inferred string. Otherwise, perform an endian swap later.
151 if (expr::is_char_encoding_type<src_char_t>(in_src_encoding) &&
152 expr::is_char_encoding_type<dst_char_t>(in_dst_encoding))
153 {
154 out_result = T_result(str_sv);
155 return true;
156 }
157 }
158
159 if (str_sv.empty())
160 {
161 out_result = T_result();
162 return true;
163 }
164
165 const auto src_data = str_sv.data();
166 const auto src_length_in_chars = str_sv.size();
167 const auto src_length_in_bytes = src_length_in_chars * sizeof(src_char_t);
168
169 const auto transcode = [&](auto* out_buffer) -> size_t
170 {
171 if constexpr (sizeof(src_char_t) == 1)
172 {
173 const auto src = reinterpret_cast<const char*>(src_data);
174
175 if constexpr (sizeof(dst_char_t) == 1)
176 {
177 return src_length_in_bytes;
178 }
179 else if constexpr (sizeof(dst_char_t) == 2)
180 {
181 if (!out_buffer)
182 return simdutf::utf16_length_from_utf8(src, src_length_in_chars);
183
184 return simdutf::convert_utf8_to_utf16(src, src_length_in_chars, reinterpret_cast<char16_t*>(out_buffer));
185 }
186 else if constexpr (sizeof(dst_char_t) == 4)
187 {
188 if (!out_buffer)
189 return simdutf::utf32_length_from_utf8(src, src_length_in_chars);
190
191 return simdutf::convert_utf8_to_utf32(src, src_length_in_chars, reinterpret_cast<char32_t*>(out_buffer));
192 }
193 }
194 else if constexpr (sizeof(src_char_t) == 2)
195 {
196 const auto src = reinterpret_cast<const char16_t*>(src_data);
197
198 if constexpr (sizeof(dst_char_t) == 1)
199 {
200 if (!out_buffer)
201 return simdutf::utf8_length_from_utf16(src, src_length_in_chars);
202
203 return simdutf::convert_utf16_to_utf8(src, src_length_in_chars, reinterpret_cast<char*>(out_buffer));
204 }
205 else if constexpr (sizeof(dst_char_t) == 2)
206 {
207 return src_length_in_bytes;
208 }
209 else if constexpr (sizeof(dst_char_t) == 4)
210 {
211 if (!out_buffer)
212 return simdutf::utf32_length_from_utf16(src, src_length_in_chars);
213
214 return simdutf::convert_utf16_to_utf32(src, src_length_in_chars, reinterpret_cast<char32_t*>(out_buffer));
215 }
216 }
217 else if constexpr (sizeof(src_char_t) == 4)
218 {
219 const auto src = reinterpret_cast<const char32_t*>(src_data);
220
221 if constexpr (sizeof(dst_char_t) == 1)
222 {
223 if (!out_buffer)
224 return simdutf::utf8_length_from_utf32(src, src_length_in_chars);
225
226 return simdutf::convert_utf32_to_utf8(src, src_length_in_chars, reinterpret_cast<char*>(out_buffer));
227 }
228 else if constexpr (sizeof(dst_char_t) == 2)
229 {
230 if (!out_buffer)
231 return simdutf::utf16_length_from_utf32(src, src_length_in_chars);
232
233 return simdutf::convert_utf32_to_utf16(src, src_length_in_chars, reinterpret_cast<char16_t*>(out_buffer));
234 }
235 else if constexpr (sizeof(dst_char_t) == 4)
236 {
237 return src_length_in_bytes;
238 }
239 }
240
241 return 0;
242 };
243
244 const auto expected_length = transcode(static_cast<dst_char_t*>(nullptr));
245
246 if (!expected_length)
247 return false;
248
249 size_t transcode_length{};
250
251 // Matching lengths could be an attempt to endian swap instead.
252 if (expected_length == src_length_in_bytes)
253 {
254 out_result = expr::create_inferred_string<T_result>(str_sv);
255 transcode_length = expected_length;
256 }
257 else
258 {
259 out_result.resize(expected_length);
260 transcode_length = transcode(out_result.data());
261 }
262
263 if (!transcode_length)
264 {
265 out_result.clear();
266 return false;
267 }
268 else if (transcode_length < expected_length)
269 {
270 out_result.resize(transcode_length);
271 }
272
273 // Result hasn't been reserved, abort.
274 if (!out_result.capacity())
275 return false;
276
277 const auto dst_char_size = expr::get_encoding_char_size(in_dst_encoding);
278
279 // Skip endian swap if encoding is unknown or multi-byte.
280 if (in_dst_encoding == encoding::unknown || dst_char_size == sizeof(char))
281 return true;
282
283 auto needs_endian_swap = false;
284
285 const auto is_big_endian = expr::has_flag(in_src_encoding, encoding::utf16_be) ||
286 expr::has_flag(in_src_encoding, encoding::utf32_be) ||
287 expr::has_flag(in_dst_encoding, encoding::utf16_be) ||
288 expr::has_flag(in_dst_encoding, encoding::utf32_be);
289
290 if constexpr (std::endian::native == std::endian::little)
291 {
292 needs_endian_swap = is_big_endian;
293 }
294 else if constexpr (std::endian::native == std::endian::big)
295 {
296 needs_endian_swap = !is_big_endian;
297 }
298
299 if (needs_endian_swap)
300 {
301 if (dst_char_size == sizeof(char16_t))
302 {
303 auto chars = reinterpret_cast<const char16_t*>(out_result.data());
304 const auto chars_length = transcode_length;
305
306 for (size_t i = 0; i < chars_length; i++)
307 const_cast<char16_t*>(chars)[i] = mem::byteswap(chars[i]);
308 }
309 else if (dst_char_size == sizeof(char32_t))
310 {
311 auto chars = reinterpret_cast<const char32_t*>(out_result.data());
312 const auto chars_length = transcode_length;
313
314 for (size_t i = 0; i < chars_length; i++)
315 const_cast<char32_t*>(chars)[i] = mem::byteswap(chars[i]);
316 }
317 }
318
319 return true;
320 }
321
322 template <encoding_type dst_encoding, expr::any_string T_str, expr::any_string T_result>
323 inline bool try_convert(const T_str& in_str, T_result& out_result)
324 {
325 return try_convert<T_result, T_str>(in_str, out_result, dst_encoding, expr::get_char_encoding_type<T_str>());
326 }
327}
Definition mem.h:169
Definition encoding.h:10
constexpr size_t get_bom_length()
Definition encoding.inl:73
constexpr size_t get_bom_length(encoding_type in_encoding)
Definition encoding.inl:53
std::array< T_result, sizeof...(T_args)> precedent_convert(const T_args &... in_args)
Definition encoding.inl:79
bool try_convert(const T_str &in_str, T_result &out_result, encoding_type in_dst_encoding=expr::get_char_encoding_type< T_result >(), encoding_type in_src_encoding=expr::get_char_encoding_type< T_str >())
Definition encoding.inl:126
std::vector< uint8_t > get_bom(encoding_type in_encoding)
Definition encoding.inl:30
T_result convert(const T_str &in_str, encoding_type in_dst_encoding=expr::get_char_encoding_type< T_result >(), encoding_type in_src_encoding=expr::get_char_encoding_type< T_str >())
Definition encoding.inl:15
encoding_type
Definition encoding_type.h:6
@ utf32_be
Definition encoding_type.h:12
@ utf16_be
Definition encoding_type.h:10
@ unknown
Definition encoding_type.h:7
@ utf32_le
Definition encoding_type.h:11
@ utf8
Definition encoding_type.h:8
@ utf16_le
Definition encoding_type.h:9
Definition expr.h:7