xtd 0.2.0
Loading...
Searching...
No Matches
basic_string_.hpp
Go to the documentation of this file.
1
4#pragma once
6#if !defined(__XTD_BASIC_STRING_INTERNAL__)
7#error "Do not include this file: Internal use only. Include <xtd/basic_string> or <xtd/basic_string.hpp> instead."
8#endif
9
10#include "array.hpp"
11#include "to_string.hpp"
12//#include "formatter.hpp"
13
15template<class char_t, class traits_t, class allocator_t>
17 return index_of_any(values, 0, length());
18}
19
20template<class char_t, class traits_t, class allocator_t>
22 return index_of_any(values, start_index, length() - start_index);
23}
24
25template<class char_t, class traits_t, class allocator_t>
28 auto index = xtd::size {0};
29 for (const auto& item : self_) {
30 if (index++ < start_index) continue;
31 if (index - 1 > start_index + count) break;
32 if (std::find(values.items().begin(), values.items().end(), item) != values.items().end()) return index - 1;
33 }
34 return npos;
35}
36
37template<class char_t, class traits_t, class allocator_t>
38inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::index_of_any(const std::initializer_list<value_type>& values) const noexcept {
39 return index_of_any(xtd::array<value_type>(values));
40}
41
42template<class char_t, class traits_t, class allocator_t>
43inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::index_of_any(const std::initializer_list<value_type>& values, xtd::size start_index) const {
44 return index_of_any(xtd::array<value_type>(values), start_index);
45}
46
47template<class char_t, class traits_t, class allocator_t>
48inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::index_of_any(const std::initializer_list<value_type>& values, xtd::size start_index, xtd::size count) const {
49 return index_of_any(xtd::array<value_type>(values), start_index, count);
50}
51
52template<class char_t, class traits_t, class allocator_t>
54 return last_index_of_any(values, 0, length());
55}
56
57template<class char_t, class traits_t, class allocator_t>
59 return last_index_of_any(values, start_index, length() - start_index);
60}
61
62template<class char_t, class traits_t, class allocator_t>
65 auto index = length() - 1;
66 for (auto iterator = chars().crbegin(); iterator != chars().crend(); ++iterator) {
67 if (index-- > start_index + count) continue;
68 if (index + 1 < start_index) break;
69 if (std::find(values.items().begin(), values.items().end(), *iterator) != values.items().end()) return index + 1;
70 }
71 return npos;
72}
73
74template<class char_t, class traits_t, class allocator_t>
75inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::last_index_of_any(const std::initializer_list<value_type>& values) const noexcept {
76 return last_index_of_any(xtd::array<value_type>(values));
77}
78
79template<class char_t, class traits_t, class allocator_t>
80inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::last_index_of_any(const std::initializer_list<value_type>& values, xtd::size start_index) const {
81 return last_index_of_any(xtd::array<value_type>(values), start_index);
82}
83
84template<class char_t, class traits_t, class allocator_t>
85inline xtd::size xtd::basic_string<char_t, traits_t, allocator_t>::last_index_of_any(const std::initializer_list<value_type>& values, xtd::size start_index, xtd::size count) const {
86 return last_index_of_any(xtd::array<value_type>(values), start_index, count);
87}
88
89template<class char_t, class traits_t, class allocator_t>
91 return split(default_split_separators, std::numeric_limits<xtd::size>::max(), xtd::string_split_options::none);
92}
93
94template<class char_t, class traits_t, class allocator_t>
96 return split(xtd::array<value_type> {separator}, std::numeric_limits<xtd::size>::max(), xtd::string_split_options::none);
97}
98
99template<class char_t, class traits_t, class allocator_t>
101 return split(xtd::array<value_type> {separator}, std::numeric_limits<xtd::size>::max(), options);
102}
103
104template<class char_t, class traits_t, class allocator_t>
107}
108
109template<class char_t, class traits_t, class allocator_t>
111 return split(xtd::array<value_type> {separator}, count, options);
112}
113
114template<class char_t, class traits_t, class allocator_t>
116 return split(separators, std::numeric_limits<xtd::size>::max(), xtd::string_split_options::none);
117}
118
119template<class char_t, class traits_t, class allocator_t>
121 return split(separators, std::numeric_limits<xtd::size>::max(), options);
122}
123
124template<class char_t, class traits_t, class allocator_t>
126 return split(separators, count, xtd::string_split_options::none);
127}
128
129template<class char_t, class traits_t, class allocator_t>
131 if (count == 0) return {};
132 if (count == 1) return {self_};
133
134 auto result = std::vector<basic_string> {};
135 auto sub_string = basic_string {};
136 auto split_char_separators = separators.length() == 0 ? default_split_separators : separators;
137 for (auto it = chars().begin(); it != chars().end(); ++it) {
138 auto is_separator = std::find(split_char_separators.items().begin(), split_char_separators.items().end(), *it) != split_char_separators.items().end();
139 if (!is_separator) sub_string.chars_.append(basic_string(*it, 1));
140 auto is_last = (it + 1 == chars().end());
141 auto should_add = is_last || is_separator;
142 auto keep_empty = sub_string.length() > 0 || (options != xtd::string_split_options::remove_empty_entries);
143
144 if (should_add && keep_empty) {
145 if (result.size() == count - 1) {
146 result.push_back(sub_string + basic_string(chars().c_str() + (it - chars().begin() + (is_separator ? 0 : 1)), length() - (it - chars().begin()) + (is_separator ? 0 : 1)));
147 return result;
148 }
149 result.push_back(sub_string);
150 sub_string.chars_.clear();
151 }
152 }
153
154 if (length() > 0 && std::find(split_char_separators.items().begin(), split_char_separators.items().end(), self_[length() - 1]) != split_char_separators.items().end() && options != xtd::string_split_options::remove_empty_entries) result.push_back(basic_string {});
155
156 return result;
157}
158
159template<class char_t, class traits_t, class allocator_t>
161 return to_array(0, length());
162}
163
164template<class char_t, class traits_t, class allocator_t>
166 return to_array(start_index, length() - start_index);
167}
168
169template<class char_t, class traits_t, class allocator_t>
171 if (start_index >= self_.length()) return {};
172 if (start_index + length >= self_.length()) return {chars().begin() + start_index, chars().end()};
173 return {chars().begin() + start_index, chars().begin() + start_index + length};
174}
175
176template<class char_t, class traits_t, class allocator_t>
178 return to_array(0, length());
179}
180
181template<class char_t, class traits_t, class allocator_t>
183 return to_array(start_index, length);
184}
185
186template<class char_t, class traits_t, class allocator_t>
188 auto words = split({' '});
189 for (auto& word : words)
190 if (word.length() && word != word.to_upper()) word = static_cast<value_type>(toupper(word[0])) + word.substring(1).to_lower();
191 return basic_string::join(" ", words);
192}
193
194template<class char_t, class traits_t, class allocator_t>
196 return trim(xtd::array<value_type> {trim_char});
197}
198
199template<class char_t, class traits_t, class allocator_t>
201 return trim_start(trim_chars).trim_end(trim_chars);
202}
203
204template<class char_t, class traits_t, class allocator_t>
206 return trim_end(xtd::array<value_type> {trim_char});
207}
208
209template<class char_t, class traits_t, class allocator_t>
211 if (!length()) return self_;
212 auto result = chars_;
213 while (std::find(trim_chars.items().begin(), trim_chars.items().end(), result[result.size() - 1]) != trim_chars.items().end())
214 result.erase(result.size() - 1, 1);
215 return result;
216}
217
218template<class char_t, class traits_t, class allocator_t>
220
221template<class char_t, class traits_t, class allocator_t>
223 if (!length()) return self_;
224 auto result = chars_;
225 while (std::find(trim_chars.items().begin(), trim_chars.items().end(), result[0]) != trim_chars.items().end())
226 result.erase(0, 1);
227 return result;
228}
229
230template<class char_t, class traits_t, class allocator_t>
232 auto result = basic_string::empty_string;
233 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
234 return result;
235}
236
237template<class char_t, class traits_t, class allocator_t>
239 auto result = basic_string::empty_string;
240 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
241 return result;
242}
243
244template<class char_t, class traits_t, class allocator_t>
245template<class other_char_t>
247 auto result = basic_string::empty_string;
248 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
249 return result;
250}
251
252
253template<class char_t, class traits_t, class allocator_t>
254template<class object_t>
256 basic_string result;
257 for (const auto& arg : args)
258 result += format("{}", arg);
259 return result;
260}
261
262template<class char_t, class traits_t, class allocator_t>
263template<class ...args_t>
265 return format(std::locale {}, fmt, std::forward<args_t>(args)...);
266}
267
268template<class char_t, class traits_t, class allocator_t>
269template<class ...args_t>
270inline xtd::basic_string<char_t, traits_t, allocator_t> xtd::basic_string<char_t, traits_t, allocator_t>::format(const std::locale& loc, const basic_string<char>& fmt, args_t&& ... args) {
271 auto result = basic_string<char> {};
272 auto index = xtd::size {0};
273 auto formats = std::vector<__format_information<char>> {};
274 auto begin_format_iterator = fmt.end();
275 auto end_format_iterator = fmt.end();
276 for (auto iterator = fmt.begin(); iterator != fmt.end(); ++iterator) {
277 if (*iterator == '{') {
278 if (++iterator == fmt.end())
280 if (*iterator == '{')
281 result += *iterator;
282 else {
283 begin_format_iterator = iterator;
284 while (iterator != fmt.end() && *iterator != '}') ++iterator;
285 if (iterator == fmt.end())
287 end_format_iterator = iterator;
288 __format_information<char> fi;
289 fi.location = result.length();
290 auto format_str = std::basic_string<char> {begin_format_iterator, end_format_iterator};
291 if (format_str.length() == 0)
292 fi.index = index++;
293 else {
294 xtd::size index_alignment_separator = basic_string(format_str).index_of(',');
295 xtd::size index_format_separator = basic_string(format_str).index_of(u':');
296
297 if (index_alignment_separator != std::basic_string<char>::npos && index_format_separator != std::basic_string<char>::npos && index_alignment_separator > index_format_separator)
298 index_alignment_separator = std::basic_string<char>::npos;
299
300 if (index_alignment_separator != basic_string<char_t>::npos)
301 fi.alignment = format_str.substr(index_alignment_separator + 1, index_format_separator != std::basic_string<char>::npos ? index_format_separator - index_alignment_separator - 1 : std::basic_string<char>::npos);
302
303 if (index_format_separator != basic_string<char>::npos)
304 fi.format = format_str.substr(index_format_separator + 1);
305
306 if (index_alignment_separator == 0 || index_format_separator == 0)
307 fi.index = index++;
308 else {
309 auto index_str = std::basic_string<char> {};
310 if (index_alignment_separator != basic_string<char>::npos)
311 index_str = format_str.substr(0, index_alignment_separator);
312 else if (index_format_separator != basic_string<char>::npos)
313 index_str = format_str.substr(0, index_format_separator);
314 else
315 index_str = std::move(format_str);
316 try {
317 for (auto c : index_str)
319 fi.index = std::stoi(index_str);
320 } catch (...) {
322 }
323 }
324 }
325 formats.push_back(fi);
326 }
327 } else if (*iterator == '}') {
328 if (++iterator == fmt.end())
330 if (*iterator != '}')
332 result += *iterator;
333 } else
334 result += *iterator;
335 }
336
337 __basic_string_extract_format_arg(loc, result, formats, std::forward<args_t>(args)...);
338 return result.chars().c_str();
339}
340
341template<class char_t, class traits_t, class allocator_t>
342template<class value_t>
343inline xtd::basic_string<char_t, traits_t, allocator_t> xtd::basic_string<char_t, traits_t, allocator_t>::join(const basic_string& separator, const std::initializer_list<value_t>& values) noexcept {
344 return join(separator, xtd::array<value_t>(values));
345}
346
347template<class char_t, class traits_t, class allocator_t>
348template<class value_t>
349inline xtd::basic_string<char_t, traits_t, allocator_t> xtd::basic_string<char_t, traits_t, allocator_t>::join(const basic_string& separator, const std::initializer_list<value_t>& values, xtd::size index) {
350 return join(separator, xtd::array<value_t>(values), index);
351}
352
353template<class char_t, class traits_t, class allocator_t>
354template<class value_t>
355inline xtd::basic_string<char_t, traits_t, allocator_t> xtd::basic_string<char_t, traits_t, allocator_t>::join(const basic_string& separator, const std::initializer_list<value_t>& values, xtd::size index, xtd::size count) {
356 return join(separator, xtd::array<value_t>(values), index, count);
357}
358
359template<class char_t, class traits_t, class allocator_t>
361
362template<class char_t, class traits_t, class allocator_t>
363inline const xtd::array<typename xtd::basic_string<char_t, traits_t, allocator_t>::value_type> xtd::basic_string<char_t, traits_t, allocator_t>::default_split_separators = {9, 10, 11, 12, 13, 32};
364
365template<class char_t, class traits_t, class allocator_t>
366inline const xtd::array<typename xtd::basic_string<char_t, traits_t, allocator_t>::value_type> xtd::basic_string<char_t, traits_t, allocator_t>::default_trim_chars = {9, 10, 11, 12, 13, 32};
367
368template<class arg_t>
369void __basic_string_extract_format_arg(const std::locale& loc, std::basic_string<char>& fmt, xtd::size& index, std::vector<__format_information<char >>& formats, arg_t&& arg) {
370 //void __basic_string_extract_format_arg(const std::locale& loc, xtd::basic_string<char>& fmt, xtd::size& index, std::vector<__format_information<char>>& formats, arg_t&& arg) {
371 auto offset = xtd::size {0};
372 for (auto& format : formats) {
373 format.location += offset;
374 if (format.index == index) {
375 //xtd::basic_string<char> arg_str = xtd::formatter<arg_t> {}(arg, format.format, std::locale());
376 xtd::basic_string<char> arg_str = xtd::to_string(arg, format.format, loc);
377
378 if (!format.alignment.empty()) {
379 xtd::int32 alignment = 0;
380 try {
381 alignment = std::stoi(format.alignment);
382 } catch (...) {
384 }
385 if (alignment > 0) arg_str = arg_str.to_u32string().pad_left(alignment);
386 else if (alignment < 0) arg_str = arg_str.to_u32string().pad_right(-alignment);
387 }
388 fmt.insert(format.location, arg_str);
389 offset += arg_str.length();
390 }
391 }
392 ++index;
393}
394
395template<class ...args_t>
396void __basic_string_extract_format_arg(const std::locale& loc, xtd::basic_string<char>& fmt, std::vector<__format_information<char >>& formats, args_t&&... args) {
397 [[maybe_unused]] auto index = xtd::size {0};
398 (__basic_string_extract_format_arg(loc, const_cast<std::basic_string<char>& > (fmt.chars()), index, formats, args), ...);
399 //(__basic_string_extract_format_arg(loc, fmt, index, formats, args), ...);
400}
401
402template<class target_t, class source_t>
403inline std::basic_string<target_t> __xtd_convert_to_string(std::basic_string<source_t>&& str) noexcept {
404 auto out = std::basic_string<target_t> {};
405 auto codepoint = 0u;
406 for (const auto& character : str) {
407 if (character >= 0xd800 && character <= 0xdbff)
408 codepoint = ((character - 0xd800) << 10) + 0x10000;
409 else {
410 if (character >= 0xdc00 && character <= 0xdfff) codepoint |= character - 0xdc00;
411 else codepoint = character;
412
413 if (codepoint <= 0x7f)
414 out.append(1, static_cast<target_t>(codepoint));
415 else if (codepoint <= 0x7ff) {
416 out.append(1, static_cast<target_t>(0xc0 | ((codepoint >> 6) & 0x1f)));
417 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
418 } else if (codepoint <= 0xffff) {
419 out.append(1, static_cast<target_t>(0xe0 | ((codepoint >> 12) & 0x0f)));
420 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
421 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
422 } else {
423 out.append(1, static_cast<target_t>(0xf0 | ((codepoint >> 18) & 0x07)));
424 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 12) & 0x3f)));
425 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
426 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
427 }
428 codepoint = 0;
429 }
430 }
431 return out;
432}
433
437template<>
438inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, char>(std::basic_string<char>&& str) noexcept {
439 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
440 auto codepoint = 0u; // Current Unicode code point
441 auto expected_bytes = 0; // Number of continuation bytes expected
442 auto str_ptr = str.data(); // Pointer to traverse input string
443
444 while (*str_ptr != 0) {
445 auto ch = static_cast<unsigned char>(*str_ptr++);
446
447 if (expected_bytes == 0) {
448 // Determine the sequence length based on the first byte
449 if (ch <= 0x7f) {
450 codepoint = ch;
451 expected_bytes = 0;
452 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
453 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
454 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
455 else {
456 // Invalid first byte → replacement character
457 out.push_back(0xfffd);
458 continue;
459 }
460 } else {
461 // Continuation byte
462 if ((ch & 0xc0) != 0x80) {
463 // Unexpected byte → invalid sequence
464 out.push_back(0xfffd);
465 expected_bytes = 0;
466 --str_ptr; // Re-evaluate this byte as first byte
467 continue;
468 }
469 codepoint = (codepoint << 6) | (ch & 0x3f);
470 --expected_bytes;
471 }
472
473 // Sequence complete
474 if (expected_bytes == 0) {
475 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
476
477 if (codepoint > 0xffff) {
478 // Code point requires surrogate pair
479 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
480 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
481 out.push_back(static_cast<xtd::char16>(high));
482 out.push_back(static_cast<xtd::char16>(low));
483 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
484 else out.push_back(0xfffd); // Surrogate range in input → replace
485 }
486 }
487
488 // If string ends prematurely, insert replacement character
489 if (expected_bytes != 0) out.push_back(0xfffd);
490 return out;
491}
492
496template<>
497inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
498 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
499 auto codepoint = 0u; // Current Unicode code point
500 auto expected_bytes = 0; // Number of continuation bytes expected
501 auto str_ptr = str.data(); // Pointer to traverse input string
502
503 while (*str_ptr != 0) {
504 auto ch = static_cast<unsigned char>(*str_ptr++);
505
506 if (expected_bytes == 0) {
507 // Determine the sequence length based on the first byte
508 if (ch <= 0x7f) {
509 codepoint = ch;
510 expected_bytes = 0;
511 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
512 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
513 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
514 else {
515 // Invalid first byte → replacement character
516 out.push_back(0xfffd);
517 continue;
518 }
519 } else {
520 // Continuation byte
521 if ((ch & 0xc0) != 0x80) {
522 // Unexpected byte → invalid sequence
523 out.push_back(0xfffd);
524 expected_bytes = 0;
525 --str_ptr; // Re-evaluate this byte as first byte
526 continue;
527 }
528 codepoint = (codepoint << 6) | (ch & 0x3f);
529 --expected_bytes;
530 }
531
532 // Sequence complete
533 if (expected_bytes == 0) {
534 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
535
536 if (codepoint > 0xffff) {
537 // Code point requires surrogate pair
538 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
539 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
540 out.push_back(static_cast<xtd::char16>(high));
541 out.push_back(static_cast<xtd::char16>(low));
542 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
543 else out.push_back(0xfffd); // Surrogate range in input → replace
544 }
545 }
546
547 // If string ends prematurely, insert replacement character
548 if (expected_bytes != 0) out.push_back(0xfffd);
549 return out;
550}
551
555template<>
556inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, char>(std::basic_string<char>&& str) noexcept {
557 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
558 auto codepoint = 0u; // Current Unicode code point
559 auto expected_bytes = 0; // Continuation bytes expected
560 auto str_ptr = str.data(); // Pointer to traverse input
561
562 while (*str_ptr != 0) {
563 auto ch = static_cast<unsigned char>(*str_ptr++);
564
565 if (expected_bytes == 0) {
566 // Determine sequence length based on first byte
567 if (ch <= 0x7f) {
568 codepoint = ch;
569 expected_bytes = 0;
570 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
571 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
572 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
573 else {
574 out.push_back(0xfffd); // Invalid first byte → replace
575 continue;
576 }
577 } else {
578 // Continuation byte
579 if ((ch & 0xc0) != 0x80) {
580 // Unexpected byte → invalid sequence
581 out.push_back(0xfffd);
582 expected_bytes = 0;
583 --str_ptr; // Re-evaluate this byte as first byte
584 continue;
585 }
586 codepoint = (codepoint << 6) | (ch & 0x3f);
587 --expected_bytes;
588 }
589
590 // Sequence complete
591 if (expected_bytes == 0) {
592 if (codepoint > 0x10ffff) codepoint = 0xfffd;
593
594 if (sizeof(xtd::wchar) > 2) {
595 // UTF-32 capable
596 out.push_back(static_cast<xtd::wchar>(codepoint));
597 } else {
598 // UTF-16, may need surrogate pairs
599 if (codepoint > 0xffff) {
600 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
601 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
602 out.push_back(static_cast<xtd::wchar>(high));
603 out.push_back(static_cast<xtd::wchar>(low));
604 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
605 out.push_back(static_cast<xtd::wchar>(codepoint));
606 else {
607 // Surrogate range in input → replace
608 out.push_back(0xfffd);
609 }
610 }
611 }
612 }
613
614 // If string ends prematurely, insert replacement character
615 if (expected_bytes != 0) out.push_back(0xfffd);
616 return out;
617}
618
622template<>
623inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
624 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
625 auto codepoint = 0u; // Current Unicode code point
626 auto expected_bytes = 0; // Continuation bytes expected
627 auto str_ptr = str.data(); // Pointer to traverse input
628
629 while (*str_ptr != 0) {
630 auto ch = static_cast<unsigned char>(*str_ptr++);
631
632 if (expected_bytes == 0) {
633 // Determine sequence length based on first byte
634 if (ch <= 0x7f) {
635 codepoint = ch;
636 expected_bytes = 0;
637 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
638 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
639 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
640 else {
641 out.push_back(0xfffd); // Invalid first byte → replace
642 continue;
643 }
644 } else {
645 // Continuation byte
646 if ((ch & 0xc0) != 0x80) {
647 // Unexpected byte → invalid sequence
648 out.push_back(0xfffd);
649 expected_bytes = 0;
650 --str_ptr; // Re-evaluate this byte as first byte
651 continue;
652 }
653 codepoint = (codepoint << 6) | (ch & 0x3f);
654 --expected_bytes;
655 }
656
657 // Sequence complete
658 if (expected_bytes == 0) {
659 if (codepoint > 0x10ffff) codepoint = 0xfffd;
660
661 if (sizeof(xtd::wchar) > 2) {
662 // UTF-32 capable
663 out.push_back(static_cast<xtd::wchar>(codepoint));
664 } else {
665 // UTF-16, may need surrogate pairs
666 if (codepoint > 0xffff) {
667 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
668 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
669 out.push_back(static_cast<xtd::wchar>(high));
670 out.push_back(static_cast<xtd::wchar>(low));
671 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
672 out.push_back(static_cast<xtd::wchar>(codepoint));
673 else {
674 // Surrogate range in input → replace
675 out.push_back(0xfffd);
676 }
677 }
678 }
679 }
680
681 // If string ends prematurely, insert replacement character
682 if (expected_bytes != 0) out.push_back(0xfffd);
683 return out;
684}
685
689template<>
690inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, char>(std::basic_string<char>&& str) noexcept {
691 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
692 auto codepoint = 0u; // Current Unicode code point
693 auto expected_bytes = 0; // Number of continuation bytes expected
694 auto str_ptr = str.data(); // Pointer to traverse input string
695
696 while (*str_ptr != 0) {
697 auto ch = static_cast<unsigned char>(*str_ptr++);
698
699 if (expected_bytes == 0) {
700 // Determine sequence length based on first byte
701 if (ch <= 0x7f) {
702 codepoint = ch;
703 out.push_back(static_cast<xtd::char32>(codepoint));
704 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
705 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
706 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
707 else out.push_back(0xfffd); // Invalid first byte → replace
708 } else {
709 // Continuation byte
710 if ((ch & 0xc0) != 0x80) {
711 // Unexpected byte → invalid sequence
712 out.push_back(0xfffd);
713 expected_bytes = 0;
714 --str_ptr; // Re-evaluate this byte as first byte
715 continue;
716 }
717 codepoint = (codepoint << 6) | (ch & 0x3f);
718 --expected_bytes;
719
720 if (expected_bytes == 0) {
721 // Sequence complete, check valid Unicode range
722 if (codepoint > 0x10ffff) codepoint = 0xfffd;
723 out.push_back(static_cast<xtd::char32>(codepoint));
724 }
725 }
726 }
727
728 // If string ends prematurely, insert replacement character
729 if (expected_bytes != 0) out.push_back(0xfffd);
730 return out;
731}
732
736template<>
737inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
738 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
739 auto codepoint = 0u; // Current Unicode code point
740 auto expected_bytes = 0; // Number of continuation bytes expected
741 auto str_ptr = str.data(); // Pointer to traverse input string
742
743 while (*str_ptr != 0) {
744 auto ch = static_cast<unsigned char>(*str_ptr++);
745
746 if (expected_bytes == 0) {
747 // Determine sequence length based on first byte
748 if (ch <= 0x7f) {
749 codepoint = ch;
750 out.push_back(static_cast<xtd::char32>(codepoint));
751 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
752 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
753 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
754 else out.push_back(0xfffd); // Invalid first byte → replace
755 } else {
756 // Continuation byte
757 if ((ch & 0xc0) != 0x80) {
758 // Unexpected byte → invalid sequence
759 out.push_back(0xfffd);
760 expected_bytes = 0;
761 --str_ptr; // Re-evaluate this byte as first byte
762 continue;
763 }
764 codepoint = (codepoint << 6) | (ch & 0x3f);
765 --expected_bytes;
766
767 if (expected_bytes == 0) {
768 // Sequence complete, check valid Unicode range
769 if (codepoint > 0x10ffff) codepoint = 0xfffd;
770 out.push_back(static_cast<xtd::char32>(codepoint));
771 }
772 }
773 }
774
775 // If string ends prematurely, insert replacement character
776 if (expected_bytes != 0) out.push_back(0xfffd);
777 return out;
778}
779
780template<>
781inline std::basic_string<char> __xtd_convert_to_string<char, char>(std::basic_string<char>&& str) noexcept {
782 return std::move(str);
783}
784
785template<>
786inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
787 return std::move(str);
788}
789
790template<>
791inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
792 return std::move(str);
793}
794
795template<>
796inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
797 return std::move(str);
798}
799
800template<>
801inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
802 return std::move(str);
803}
804
805template<>
806inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, char>(std::basic_string<char>&& str) noexcept {
807 return std::basic_string<xtd::char8> {reinterpret_cast<const xtd::char8*>(str.c_str())};
808}
809
810template<>
811inline std::basic_string<char> __xtd_convert_to_string<char, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
812 return std::basic_string<char> {reinterpret_cast<const char*>(str.c_str())};
813}
814
815template<>
816inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
817 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(std::move(str)));
818}
819
820template<>
821inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
822 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(std::move(str)));
823}
824
825template<>
826inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
827 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(std::move(str)));
828}
829
830template<>
831inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
832 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(std::move(str)));
833}
834
835template<>
836inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
837 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(std::move(str)));
838}
839
840template<>
841inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
842 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(std::move(str)));
843}
844
845template<class target_t, class source_t>
846inline std::basic_string<target_t> __xtd_convert_to_string(const std::basic_string<source_t>& str) noexcept {
847 auto out = std::basic_string<target_t> {};
848 auto codepoint = 0u;
849 for (const auto& character : str) {
850 if (character >= 0xd800 && character <= 0xdbff)
851 codepoint = ((character - 0xd800) << 10) + 0x10000;
852 else {
853 if (character >= 0xdc00 && character <= 0xdfff) codepoint |= character - 0xdc00;
854 else codepoint = character;
855
856 if (codepoint <= 0x7f)
857 out.append(1, static_cast<target_t>(codepoint));
858 else if (codepoint <= 0x7ff) {
859 out.append(1, static_cast<target_t>(0xc0 | ((codepoint >> 6) & 0x1f)));
860 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
861 } else if (codepoint <= 0xffff) {
862 out.append(1, static_cast<target_t>(0xe0 | ((codepoint >> 12) & 0x0f)));
863 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
864 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
865 } else {
866 out.append(1, static_cast<target_t>(0xf0 | ((codepoint >> 18) & 0x07)));
867 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 12) & 0x3f)));
868 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
869 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
870 }
871 codepoint = 0;
872 }
873 }
874 return out;
875}
876
880template<>
881inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, char>(const std::basic_string<char>& str) noexcept {
882 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
883 auto codepoint = 0u; // Current Unicode code point
884 auto expected_bytes = 0; // Number of continuation bytes expected
885 auto str_ptr = str.data(); // Pointer to traverse input string
886
887 while (*str_ptr != 0) {
888 auto ch = static_cast<unsigned char>(*str_ptr++);
889
890 if (expected_bytes == 0) {
891 // Determine the sequence length based on the first byte
892 if (ch <= 0x7f) {
893 codepoint = ch;
894 expected_bytes = 0;
895 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
896 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
897 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
898 else {
899 // Invalid first byte → replacement character
900 out.push_back(0xfffd);
901 continue;
902 }
903 } else {
904 // Continuation byte
905 if ((ch & 0xc0) != 0x80) {
906 // Unexpected byte → invalid sequence
907 out.push_back(0xfffd);
908 expected_bytes = 0;
909 --str_ptr; // Re-evaluate this byte as first byte
910 continue;
911 }
912 codepoint = (codepoint << 6) | (ch & 0x3f);
913 --expected_bytes;
914 }
915
916 // Sequence complete
917 if (expected_bytes == 0) {
918 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
919
920 if (codepoint > 0xffff) {
921 // Code point requires surrogate pair
922 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
923 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
924 out.push_back(static_cast<xtd::char16>(high));
925 out.push_back(static_cast<xtd::char16>(low));
926 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
927 else out.push_back(0xfffd); // Surrogate range in input → replace
928 }
929 }
930
931 // If string ends prematurely, insert replacement character
932 if (expected_bytes != 0) out.push_back(0xfffd);
933 return out;
934}
935
939template<>
940inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
941 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
942 auto codepoint = 0u; // Current Unicode code point
943 auto expected_bytes = 0; // Number of continuation bytes expected
944 auto str_ptr = str.data(); // Pointer to traverse input string
945
946 while (*str_ptr != 0) {
947 auto ch = static_cast<unsigned char>(*str_ptr++);
948
949 if (expected_bytes == 0) {
950 // Determine the sequence length based on the first byte
951 if (ch <= 0x7f) {
952 codepoint = ch;
953 expected_bytes = 0;
954 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
955 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
956 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
957 else {
958 // Invalid first byte → replacement character
959 out.push_back(0xfffd);
960 continue;
961 }
962 } else {
963 // Continuation byte
964 if ((ch & 0xc0) != 0x80) {
965 // Unexpected byte → invalid sequence
966 out.push_back(0xfffd);
967 expected_bytes = 0;
968 --str_ptr; // Re-evaluate this byte as first byte
969 continue;
970 }
971 codepoint = (codepoint << 6) | (ch & 0x3f);
972 --expected_bytes;
973 }
974
975 // Sequence complete
976 if (expected_bytes == 0) {
977 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
978
979 if (codepoint > 0xffff) {
980 // Code point requires surrogate pair
981 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
982 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
983 out.push_back(static_cast<xtd::char16>(high));
984 out.push_back(static_cast<xtd::char16>(low));
985 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
986 else out.push_back(0xfffd); // Surrogate range in input → replace
987 }
988 }
989
990 // If string ends prematurely, insert replacement character
991 if (expected_bytes != 0) out.push_back(0xfffd);
992 return out;
993}
994
998template<>
999inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, char>(const std::basic_string<char>& str) noexcept {
1000 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
1001 auto codepoint = 0u; // Current Unicode code point
1002 auto expected_bytes = 0; // Continuation bytes expected
1003 auto str_ptr = str.data(); // Pointer to traverse input
1004
1005 while (*str_ptr != 0) {
1006 auto ch = static_cast<unsigned char>(*str_ptr++);
1007
1008 if (expected_bytes == 0) {
1009 // Determine sequence length based on first byte
1010 if (ch <= 0x7f) {
1011 codepoint = ch;
1012 expected_bytes = 0;
1013 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1014 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1015 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1016 else {
1017 out.push_back(0xfffd); // Invalid first byte → replace
1018 continue;
1019 }
1020 } else {
1021 // Continuation byte
1022 if ((ch & 0xc0) != 0x80) {
1023 // Unexpected byte → invalid sequence
1024 out.push_back(0xfffd);
1025 expected_bytes = 0;
1026 --str_ptr; // Re-evaluate this byte as first byte
1027 continue;
1028 }
1029 codepoint = (codepoint << 6) | (ch & 0x3f);
1030 --expected_bytes;
1031 }
1032
1033 // Sequence complete
1034 if (expected_bytes == 0) {
1035 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1036
1037 if (sizeof(xtd::wchar) > 2) {
1038 // UTF-32 capable
1039 out.push_back(static_cast<xtd::wchar>(codepoint));
1040 } else {
1041 // UTF-16, may need surrogate pairs
1042 if (codepoint > 0xffff) {
1043 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
1044 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
1045 out.push_back(static_cast<xtd::wchar>(high));
1046 out.push_back(static_cast<xtd::wchar>(low));
1047 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
1048 out.push_back(static_cast<xtd::wchar>(codepoint));
1049 else {
1050 // Surrogate range in input → replace
1051 out.push_back(0xfffd);
1052 }
1053 }
1054 }
1055 }
1056
1057 // If string ends prematurely, insert replacement character
1058 if (expected_bytes != 0) out.push_back(0xfffd);
1059 return out;
1060}
1061
1065template<>
1066inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1067 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
1068 auto codepoint = 0u; // Current Unicode code point
1069 auto expected_bytes = 0; // Continuation bytes expected
1070 auto str_ptr = str.data(); // Pointer to traverse input
1071
1072 while (*str_ptr != 0) {
1073 auto ch = static_cast<unsigned char>(*str_ptr++);
1074
1075 if (expected_bytes == 0) {
1076 // Determine sequence length based on first byte
1077 if (ch <= 0x7f) {
1078 codepoint = ch;
1079 expected_bytes = 0;
1080 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1081 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1082 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1083 else {
1084 out.push_back(0xfffd); // Invalid first byte → replace
1085 continue;
1086 }
1087 } else {
1088 // Continuation byte
1089 if ((ch & 0xc0) != 0x80) {
1090 // Unexpected byte → invalid sequence
1091 out.push_back(0xfffd);
1092 expected_bytes = 0;
1093 --str_ptr; // Re-evaluate this byte as first byte
1094 continue;
1095 }
1096 codepoint = (codepoint << 6) | (ch & 0x3f);
1097 --expected_bytes;
1098 }
1099
1100 // Sequence complete
1101 if (expected_bytes == 0) {
1102 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1103
1104 if (sizeof(xtd::wchar) > 2) {
1105 // UTF-32 capable
1106 out.push_back(static_cast<xtd::wchar>(codepoint));
1107 } else {
1108 // UTF-16, may need surrogate pairs
1109 if (codepoint > 0xffff) {
1110 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
1111 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
1112 out.push_back(static_cast<xtd::wchar>(high));
1113 out.push_back(static_cast<xtd::wchar>(low));
1114 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
1115 out.push_back(static_cast<xtd::wchar>(codepoint));
1116 else {
1117 // Surrogate range in input → replace
1118 out.push_back(0xfffd);
1119 }
1120 }
1121 }
1122 }
1123
1124 // If string ends prematurely, insert replacement character
1125 if (expected_bytes != 0) out.push_back(0xfffd);
1126 return out;
1127}
1128
1132template<>
1133inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, char>(const std::basic_string<char>& str) noexcept {
1134 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
1135 auto codepoint = 0u; // Current Unicode code point
1136 auto expected_bytes = 0; // Number of continuation bytes expected
1137 auto str_ptr = str.data(); // Pointer to traverse input string
1138
1139 while (*str_ptr != 0) {
1140 auto ch = static_cast<unsigned char>(*str_ptr++);
1141
1142 if (expected_bytes == 0) {
1143 // Determine sequence length based on first byte
1144 if (ch <= 0x7f) {
1145 codepoint = ch;
1146 out.push_back(static_cast<xtd::char32>(codepoint));
1147 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1148 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1149 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1150 else out.push_back(0xfffd); // Invalid first byte → replace
1151 } else {
1152 // Continuation byte
1153 if ((ch & 0xc0) != 0x80) {
1154 // Unexpected byte → invalid sequence
1155 out.push_back(0xfffd);
1156 expected_bytes = 0;
1157 --str_ptr; // Re-evaluate this byte as first byte
1158 continue;
1159 }
1160 codepoint = (codepoint << 6) | (ch & 0x3f);
1161 --expected_bytes;
1162
1163 if (expected_bytes == 0) {
1164 // Sequence complete, check valid Unicode range
1165 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1166 out.push_back(static_cast<xtd::char32>(codepoint));
1167 }
1168 }
1169 }
1170
1171 // If string ends prematurely, insert replacement character
1172 if (expected_bytes != 0) out.push_back(0xfffd);
1173 return out;
1174}
1175
1179template<>
1180inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1181 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
1182 auto codepoint = 0u; // Current Unicode code point
1183 auto expected_bytes = 0; // Number of continuation bytes expected
1184 auto str_ptr = str.data(); // Pointer to traverse input string
1185
1186 while (*str_ptr != 0) {
1187 auto ch = static_cast<unsigned char>(*str_ptr++);
1188
1189 if (expected_bytes == 0) {
1190 // Determine sequence length based on first byte
1191 if (ch <= 0x7f) {
1192 codepoint = ch;
1193 out.push_back(static_cast<xtd::char32>(codepoint));
1194 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1195 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1196 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1197 else out.push_back(0xfffd); // Invalid first byte → replace
1198 } else {
1199 // Continuation byte
1200 if ((ch & 0xc0) != 0x80) {
1201 // Unexpected byte → invalid sequence
1202 out.push_back(0xfffd);
1203 expected_bytes = 0;
1204 --str_ptr; // Re-evaluate this byte as first byte
1205 continue;
1206 }
1207 codepoint = (codepoint << 6) | (ch & 0x3f);
1208 --expected_bytes;
1209
1210 if (expected_bytes == 0) {
1211 // Sequence complete, check valid Unicode range
1212 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1213 out.push_back(static_cast<xtd::char32>(codepoint));
1214 }
1215 }
1216 }
1217
1218 // If string ends prematurely, insert replacement character
1219 if (expected_bytes != 0) out.push_back(0xfffd);
1220 return out;
1221}
1222
1223template<>
1224inline std::basic_string<char> __xtd_convert_to_string<char, char>(const std::basic_string<char>& str) noexcept {
1225 return str;
1226}
1227
1228template<>
1229inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1230 return str;
1231}
1232
1233template<>
1234inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1235 return str;
1236}
1237
1238template<>
1239inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1240 return str;
1241}
1242
1243template<>
1244inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1245 return str;
1246}
1247
1248template<>
1249inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, char>(const std::basic_string<char>& str) noexcept {
1250 return reinterpret_cast<const xtd::char8*>(str.c_str());
1251}
1252
1253template<>
1254inline std::basic_string<char> __xtd_convert_to_string<char, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1255 return reinterpret_cast<const char*>(str.c_str());
1256}
1257
1258template<>
1259inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1260 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(str));
1261}
1262
1263template<>
1264inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1265 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(str));
1266}
1267
1268template<>
1269inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1270 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(str));
1271}
1272
1273template<>
1274inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1275 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(str));
1276}
1277
1278template<>
1279inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1280 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(str));
1281}
1282
1283template<>
1284inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1285 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(str));
1286}
Contains xtd::array class.
Provides methods for creating, manipulating, searching, and sorting arrays, thereby serving as the ba...
Definition array.hpp:64
virtual const base_type & items() const noexcept
Returns the underlying base type items.
Definition basic_array.hpp:113
Represents text as a sequence of character units.
Definition basic_string.hpp:66
static const basic_string empty_string
Represents the empty basic_string.
Definition basic_string.hpp:111
const base_type & chars() const noexcept
Returns a reference to the underlying base type.
Definition basic_string.hpp:354
virtual size_type length() const noexcept
Gets the number of characters in the current xtd::basic_string object.
Definition basic_string.hpp:380
virtual bool empty() const noexcept
Checks whether the container is empty.
Definition basic_string.hpp:375
auto concat(const ienumerable< char_t > &second) const noexcept
Definition enumerable.hpp:185
static auto throws(xtd::helpers::exception_case exception_case, const source_location &location=source_location::current()) -> void
Throws an exption with specified exception case.
xtd::string format(const xtd::string &fmt, args_t &&... args)
Writes the text representation of the specified arguments list, to string using the specified format ...
Definition format.hpp:21
@ format
The format is not valid.
Definition exception_case.hpp:51
@ index_out_of_range
The index is out of range.
Definition exception_case.hpp:61
@ format_opened_bracket_without_end_bracket
The format contains open backet_without_end_bracket.
Definition exception_case.hpp:55
@ format_closing_bracket_without_open_bracket
The format contains close backet_without_open_bracket.
Definition exception_case.hpp:53
#define self_
The self_ expression is a reference value expression whose value is the reference of the implicit obj...
Definition self.hpp:20
constexpr xtd::size npos
Represents a value that is not a valid position in a collection.
Definition npos.hpp:26
@ character
Specifies that the text is trimmed to the nearest character.
Definition string_trimming.hpp:21
@ word
Specifies that text is trimmed to the nearest word.
Definition string_trimming.hpp:23
size_t size
Represents a size of any object in bytes.
Definition size.hpp:23
char8_t char8
Represents a 8-bit unicode character.
Definition char8.hpp:26
wchar_t wchar
Represents a wide character.
Definition wchar.hpp:24
char16_t char16
Represents a 16-bit unicode character.
Definition char16.hpp:26
std::int32_t int32
Represents a 32-bit signed integer.
Definition int32.hpp:23
char32_t char32
Represents a 32-bit unicode character.
Definition char32.hpp:23
string_split_options
Specifies whether applicable xtd::string::split method overloads include or omit empty substrings fro...
Definition string_split_options.hpp:14
@ none
The return value includes array elements that contain an empty string.
Definition string_split_options.hpp:16
@ remove_empty_entries
The return value does not include array elements that contain an empty string.
Definition string_split_options.hpp:18
@ high
Specifies that the process performs time-critical tasks that must be executed immediately,...
Definition process_priority_class.hpp:32
@ u
The U key.
Definition console_key.hpp:128
@ separator
The Separator key.
Definition console_key.hpp:172
@ low
Specifies low quality interpolation.
Definition interpolation_mode.hpp:26
const_iterator begin() const
Returns an iterator to the beginning.
Definition read_only_span.hpp:183
string to_string() const noexcept override
Returns the string representation of this xtd::read_only_span <type_t> object.
Definition read_only_span.hpp:375
const_reverse_iterator crbegin() const
Returns a reverse iterator to the beginning.
Definition read_only_span.hpp:194
constexpr size_type length() const noexcept
Returns the length of the current read_only_span.
Definition read_only_span.hpp:229
xtd::array< std::remove_cv_t< type_t > > to_array() const noexcept
Copies the contents of this read_only_span into a new array.
Definition read_only_span.hpp:368
Contains xtd::to_string methods.