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
130#if defined(__GNUC__)
131# pragma GCC diagnostic push
132# pragma GCC diagnostic ignored "-Warray-bounds"
133#endif
134
135template<class char_t, class traits_t, class allocator_t>
137 if (count == 0) return {};
138 if (count == 1) return {self_};
139
140 auto result = std::vector<basic_string> {};
141 auto sub_string = basic_string {};
142 auto split_char_separators = separators.length() == 0 ? default_split_separators : separators;
143 for (auto it = chars().begin(); it != chars().end(); ++it) {
144 auto is_separator = std::find(split_char_separators.items().begin(), split_char_separators.items().end(), *it) != split_char_separators.items().end();
145 if (!is_separator) sub_string.chars_.append(basic_string(*it, 1));
146 auto is_last = (it + 1 == chars().end());
147 auto should_add = is_last || is_separator;
148 auto keep_empty = sub_string.length() > 0 || (options != xtd::string_split_options::remove_empty_entries);
149
150 if (should_add && keep_empty) {
151 if (result.size() == count - 1) {
152 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)));
153 return result;
154 }
155 result.push_back(sub_string);
156 sub_string.chars_.clear();
157 }
158 }
159
160 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 {});
161
162 return result;
163}
164
166#if defined(__GNUC__)
167# pragma GCC diagnostic pop
168#endif
169
170template<class char_t, class traits_t, class allocator_t>
172 return to_array(0, length());
173}
174
175template<class char_t, class traits_t, class allocator_t>
177 return to_array(start_index, length() - start_index);
178}
179
180template<class char_t, class traits_t, class allocator_t>
182 if (start_index >= self_.length()) return {};
183 if (start_index + length >= self_.length()) return {chars().begin() + start_index, chars().end()};
184 return {chars().begin() + start_index, chars().begin() + start_index + length};
185}
186
187template<class char_t, class traits_t, class allocator_t>
189 return to_array(0, length());
190}
191
192template<class char_t, class traits_t, class allocator_t>
194 return to_array(start_index, length);
195}
196
197template<class char_t, class traits_t, class allocator_t>
199 auto words = split({' '});
200 for (auto& word : words)
201 if (word.length() && word != word.to_upper()) word = static_cast<value_type>(toupper(word[0])) + word.substring(1).to_lower();
202 return basic_string::join(" ", words);
203}
204
205template<class char_t, class traits_t, class allocator_t>
207 return trim(xtd::array<value_type> {trim_char});
208}
209
210template<class char_t, class traits_t, class allocator_t>
212 return trim_start(trim_chars).trim_end(trim_chars);
213}
214
215template<class char_t, class traits_t, class allocator_t>
217 return trim_end(xtd::array<value_type> {trim_char});
218}
219
220template<class char_t, class traits_t, class allocator_t>
222 if (!length()) return self_;
223 auto result = chars_;
224 while (std::find(trim_chars.items().begin(), trim_chars.items().end(), result[result.size() - 1]) != trim_chars.items().end())
225 result.erase(result.size() - 1, 1);
226 return result;
227}
228
229template<class char_t, class traits_t, class allocator_t>
231
232template<class char_t, class traits_t, class allocator_t>
234 if (!length()) return self_;
235 auto result = chars_;
236 while (std::find(trim_chars.items().begin(), trim_chars.items().end(), result[0]) != trim_chars.items().end())
237 result.erase(0, 1);
238 return result;
239}
240
241template<class char_t, class traits_t, class allocator_t>
243 auto result = basic_string::empty_string;
244 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
245 return result;
246}
247
248template<class char_t, class traits_t, class allocator_t>
250 auto result = basic_string::empty_string;
251 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
252 return result;
253}
254
255template<class char_t, class traits_t, class allocator_t>
256template<class other_char_t>
258 auto result = basic_string::empty_string;
259 std::for_each(values.begin(), values.end(), [&](const auto & item) {result += item;});
260 return result;
261}
262
263
264template<class char_t, class traits_t, class allocator_t>
265template<class object_t>
267 basic_string result;
268 for (const auto& arg : args)
269 result += format("{}", arg);
270 return result;
271}
272
273template<class char_t, class traits_t, class allocator_t>
274template<class ...args_t>
276 return format(std::locale {}, fmt, std::forward<args_t>(args)...);
277}
278
279template<class char_t, class traits_t, class allocator_t>
280template<class ...args_t>
281inline 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) {
282 auto result = basic_string<char> {};
283 auto index = xtd::size {0};
284 auto formats = std::vector<__format_information<char>> {};
285 auto begin_format_iterator = fmt.end();
286 auto end_format_iterator = fmt.end();
287 for (auto iterator = fmt.begin(); iterator != fmt.end(); ++iterator) {
288 if (*iterator == '{') {
289 if (++iterator == fmt.end())
291 if (*iterator == '{')
292 result += *iterator;
293 else {
294 begin_format_iterator = iterator;
295 while (iterator != fmt.end() && *iterator != '}') ++iterator;
296 if (iterator == fmt.end())
298 end_format_iterator = iterator;
299 __format_information<char> fi;
300 fi.location = result.length();
301 auto format_str = std::basic_string<char> {begin_format_iterator, end_format_iterator};
302 if (format_str.length() == 0)
303 fi.index = index++;
304 else {
305 xtd::size index_alignment_separator = basic_string(format_str).index_of(',');
306 xtd::size index_format_separator = basic_string(format_str).index_of(u':');
307
308 if (index_alignment_separator != std::basic_string<char>::npos && index_format_separator != std::basic_string<char>::npos && index_alignment_separator > index_format_separator)
309 index_alignment_separator = std::basic_string<char>::npos;
310
311 if (index_alignment_separator != basic_string<char_t>::npos)
312 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);
313
314 if (index_format_separator != basic_string<char>::npos)
315 fi.format = format_str.substr(index_format_separator + 1);
316
317 if (index_alignment_separator == 0 || index_format_separator == 0)
318 fi.index = index++;
319 else {
320 auto index_str = std::basic_string<char> {};
321 if (index_alignment_separator != basic_string<char>::npos)
322 index_str = format_str.substr(0, index_alignment_separator);
323 else if (index_format_separator != basic_string<char>::npos)
324 index_str = format_str.substr(0, index_format_separator);
325 else
326 index_str = std::move(format_str);
327 try {
328 for (auto c : index_str)
330 fi.index = std::stoi(index_str);
331 } catch (...) {
333 }
334 }
335 }
336 formats.push_back(fi);
337 }
338 } else if (*iterator == '}') {
339 if (++iterator == fmt.end())
341 if (*iterator != '}')
343 result += *iterator;
344 } else
345 result += *iterator;
346 }
347
348 __basic_string_extract_format_arg(loc, result, formats, std::forward<args_t>(args)...);
349 return result.chars().c_str();
350}
351
352template<class char_t, class traits_t, class allocator_t>
353template<class value_t>
354inline 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 {
355 return join(separator, xtd::array<value_t>(values));
356}
357
358template<class char_t, class traits_t, class allocator_t>
359template<class value_t>
360inline 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) {
361 return join(separator, xtd::array<value_t>(values), index);
362}
363
364template<class char_t, class traits_t, class allocator_t>
365template<class value_t>
366inline 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) {
367 return join(separator, xtd::array<value_t>(values), index, count);
368}
369
370template<class char_t, class traits_t, class allocator_t>
372
373template<class char_t, class traits_t, class allocator_t>
374inline 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};
375
376template<class char_t, class traits_t, class allocator_t>
377inline 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};
378
379template<class arg_t>
380void __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) {
381 //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) {
382 auto offset = xtd::size {0};
383 for (auto& format : formats) {
384 format.location += offset;
385 if (format.index == index) {
386 //xtd::basic_string<char> arg_str = xtd::formatter<arg_t> {}(arg, format.format, std::locale());
388
389 if (!format.alignment.empty()) {
390 xtd::int32 alignment = 0;
391 try {
392 alignment = std::stoi(format.alignment);
393 } catch (...) {
395 }
396 if (alignment > 0) arg_str = arg_str.to_u32string().pad_left(alignment);
397 else if (alignment < 0) arg_str = arg_str.to_u32string().pad_right(-alignment);
398 }
399 fmt.insert(format.location, arg_str);
400 offset += arg_str.length();
401 }
402 }
403 ++index;
404}
405
406template<class ...args_t>
407void __basic_string_extract_format_arg(const std::locale& loc, xtd::basic_string<char>& fmt, std::vector<__format_information<char >>& formats, args_t&&... args) {
408 [[maybe_unused]] auto index = xtd::size {0};
409 (__basic_string_extract_format_arg(loc, const_cast<std::basic_string<char>& > (fmt.chars()), index, formats, args), ...);
410 //(__basic_string_extract_format_arg(loc, fmt, index, formats, args), ...);
411}
412
413template<class target_t, class source_t>
414inline std::basic_string<target_t> __xtd_convert_to_string(std::basic_string<source_t>&& str) noexcept {
415 auto out = std::basic_string<target_t> {};
416 auto codepoint = 0u;
417 for (const auto& character : str) {
418 if (character >= 0xd800 && character <= 0xdbff)
419 codepoint = ((character - 0xd800) << 10) + 0x10000;
420 else {
421 if (character >= 0xdc00 && character <= 0xdfff) codepoint |= character - 0xdc00;
422 else codepoint = character;
423
424 if (codepoint <= 0x7f)
425 out.append(1, static_cast<target_t>(codepoint));
426 else if (codepoint <= 0x7ff) {
427 out.append(1, static_cast<target_t>(0xc0 | ((codepoint >> 6) & 0x1f)));
428 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
429 } else if (codepoint <= 0xffff) {
430 out.append(1, static_cast<target_t>(0xe0 | ((codepoint >> 12) & 0x0f)));
431 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
432 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
433 } else {
434 out.append(1, static_cast<target_t>(0xf0 | ((codepoint >> 18) & 0x07)));
435 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 12) & 0x3f)));
436 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
437 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
438 }
439 codepoint = 0;
440 }
441 }
442 return out;
443}
444
448template<>
449inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, char>(std::basic_string<char>&& str) noexcept {
450 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
451 auto codepoint = 0u; // Current Unicode code point
452 auto expected_bytes = 0; // Number of continuation bytes expected
453 auto str_ptr = str.data(); // Pointer to traverse input string
454
455 while (*str_ptr != 0) {
456 auto ch = static_cast<unsigned char>(*str_ptr++);
457
458 if (expected_bytes == 0) {
459 // Determine the sequence length based on the first byte
460 if (ch <= 0x7f) {
461 codepoint = ch;
462 expected_bytes = 0;
463 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
464 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
465 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
466 else {
467 // Invalid first byte → replacement character
468 out.push_back(0xfffd);
469 continue;
470 }
471 } else {
472 // Continuation byte
473 if ((ch & 0xc0) != 0x80) {
474 // Unexpected byte → invalid sequence
475 out.push_back(0xfffd);
476 expected_bytes = 0;
477 --str_ptr; // Re-evaluate this byte as first byte
478 continue;
479 }
480 codepoint = (codepoint << 6) | (ch & 0x3f);
481 --expected_bytes;
482 }
483
484 // Sequence complete
485 if (expected_bytes == 0) {
486 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
487
488 if (codepoint > 0xffff) {
489 // Code point requires surrogate pair
490 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
491 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
492 out.push_back(static_cast<xtd::char16>(high));
493 out.push_back(static_cast<xtd::char16>(low));
494 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
495 else out.push_back(0xfffd); // Surrogate range in input → replace
496 }
497 }
498
499 // If string ends prematurely, insert replacement character
500 if (expected_bytes != 0) out.push_back(0xfffd);
501 return out;
502}
503
507template<>
508inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
509 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
510 auto codepoint = 0u; // Current Unicode code point
511 auto expected_bytes = 0; // Number of continuation bytes expected
512 auto str_ptr = str.data(); // Pointer to traverse input string
513
514 while (*str_ptr != 0) {
515 auto ch = static_cast<unsigned char>(*str_ptr++);
516
517 if (expected_bytes == 0) {
518 // Determine the sequence length based on the first byte
519 if (ch <= 0x7f) {
520 codepoint = ch;
521 expected_bytes = 0;
522 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
523 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
524 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
525 else {
526 // Invalid first byte → replacement character
527 out.push_back(0xfffd);
528 continue;
529 }
530 } else {
531 // Continuation byte
532 if ((ch & 0xc0) != 0x80) {
533 // Unexpected byte → invalid sequence
534 out.push_back(0xfffd);
535 expected_bytes = 0;
536 --str_ptr; // Re-evaluate this byte as first byte
537 continue;
538 }
539 codepoint = (codepoint << 6) | (ch & 0x3f);
540 --expected_bytes;
541 }
542
543 // Sequence complete
544 if (expected_bytes == 0) {
545 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
546
547 if (codepoint > 0xffff) {
548 // Code point requires surrogate pair
549 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
550 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
551 out.push_back(static_cast<xtd::char16>(high));
552 out.push_back(static_cast<xtd::char16>(low));
553 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
554 else out.push_back(0xfffd); // Surrogate range in input → replace
555 }
556 }
557
558 // If string ends prematurely, insert replacement character
559 if (expected_bytes != 0) out.push_back(0xfffd);
560 return out;
561}
562
566template<>
567inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, char>(std::basic_string<char>&& str) noexcept {
568 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
569 auto codepoint = 0u; // Current Unicode code point
570 auto expected_bytes = 0; // Continuation bytes expected
571 auto str_ptr = str.data(); // Pointer to traverse input
572
573 while (*str_ptr != 0) {
574 auto ch = static_cast<unsigned char>(*str_ptr++);
575
576 if (expected_bytes == 0) {
577 // Determine sequence length based on first byte
578 if (ch <= 0x7f) {
579 codepoint = ch;
580 expected_bytes = 0;
581 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
582 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
583 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
584 else {
585 out.push_back(0xfffd); // Invalid first byte → replace
586 continue;
587 }
588 } else {
589 // Continuation byte
590 if ((ch & 0xc0) != 0x80) {
591 // Unexpected byte → invalid sequence
592 out.push_back(0xfffd);
593 expected_bytes = 0;
594 --str_ptr; // Re-evaluate this byte as first byte
595 continue;
596 }
597 codepoint = (codepoint << 6) | (ch & 0x3f);
598 --expected_bytes;
599 }
600
601 // Sequence complete
602 if (expected_bytes == 0) {
603 if (codepoint > 0x10ffff) codepoint = 0xfffd;
604
605 if (sizeof(xtd::wchar) > 2) {
606 // UTF-32 capable
607 out.push_back(static_cast<xtd::wchar>(codepoint));
608 } else {
609 // UTF-16, may need surrogate pairs
610 if (codepoint > 0xffff) {
611 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
612 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
613 out.push_back(static_cast<xtd::wchar>(high));
614 out.push_back(static_cast<xtd::wchar>(low));
615 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
616 out.push_back(static_cast<xtd::wchar>(codepoint));
617 else {
618 // Surrogate range in input → replace
619 out.push_back(0xfffd);
620 }
621 }
622 }
623 }
624
625 // If string ends prematurely, insert replacement character
626 if (expected_bytes != 0) out.push_back(0xfffd);
627 return out;
628}
629
633template<>
634inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
635 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
636 auto codepoint = 0u; // Current Unicode code point
637 auto expected_bytes = 0; // Continuation bytes expected
638 auto str_ptr = str.data(); // Pointer to traverse input
639
640 while (*str_ptr != 0) {
641 auto ch = static_cast<unsigned char>(*str_ptr++);
642
643 if (expected_bytes == 0) {
644 // Determine sequence length based on first byte
645 if (ch <= 0x7f) {
646 codepoint = ch;
647 expected_bytes = 0;
648 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
649 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
650 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
651 else {
652 out.push_back(0xfffd); // Invalid first byte → replace
653 continue;
654 }
655 } else {
656 // Continuation byte
657 if ((ch & 0xc0) != 0x80) {
658 // Unexpected byte → invalid sequence
659 out.push_back(0xfffd);
660 expected_bytes = 0;
661 --str_ptr; // Re-evaluate this byte as first byte
662 continue;
663 }
664 codepoint = (codepoint << 6) | (ch & 0x3f);
665 --expected_bytes;
666 }
667
668 // Sequence complete
669 if (expected_bytes == 0) {
670 if (codepoint > 0x10ffff) codepoint = 0xfffd;
671
672 if (sizeof(xtd::wchar) > 2) {
673 // UTF-32 capable
674 out.push_back(static_cast<xtd::wchar>(codepoint));
675 } else {
676 // UTF-16, may need surrogate pairs
677 if (codepoint > 0xffff) {
678 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
679 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
680 out.push_back(static_cast<xtd::wchar>(high));
681 out.push_back(static_cast<xtd::wchar>(low));
682 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
683 out.push_back(static_cast<xtd::wchar>(codepoint));
684 else {
685 // Surrogate range in input → replace
686 out.push_back(0xfffd);
687 }
688 }
689 }
690 }
691
692 // If string ends prematurely, insert replacement character
693 if (expected_bytes != 0) out.push_back(0xfffd);
694 return out;
695}
696
700template<>
701inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, char>(std::basic_string<char>&& str) noexcept {
702 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
703 auto codepoint = 0u; // Current Unicode code point
704 auto expected_bytes = 0; // Number of continuation bytes expected
705 auto str_ptr = str.data(); // Pointer to traverse input string
706
707 while (*str_ptr != 0) {
708 auto ch = static_cast<unsigned char>(*str_ptr++);
709
710 if (expected_bytes == 0) {
711 // Determine sequence length based on first byte
712 if (ch <= 0x7f) {
713 codepoint = ch;
714 out.push_back(static_cast<xtd::char32>(codepoint));
715 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
716 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
717 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
718 else out.push_back(0xfffd); // Invalid first byte → replace
719 } else {
720 // Continuation byte
721 if ((ch & 0xc0) != 0x80) {
722 // Unexpected byte → invalid sequence
723 out.push_back(0xfffd);
724 expected_bytes = 0;
725 --str_ptr; // Re-evaluate this byte as first byte
726 continue;
727 }
728 codepoint = (codepoint << 6) | (ch & 0x3f);
729 --expected_bytes;
730
731 if (expected_bytes == 0) {
732 // Sequence complete, check valid Unicode range
733 if (codepoint > 0x10ffff) codepoint = 0xfffd;
734 out.push_back(static_cast<xtd::char32>(codepoint));
735 }
736 }
737 }
738
739 // If string ends prematurely, insert replacement character
740 if (expected_bytes != 0) out.push_back(0xfffd);
741 return out;
742}
743
747template<>
748inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
749 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
750 auto codepoint = 0u; // Current Unicode code point
751 auto expected_bytes = 0; // Number of continuation bytes expected
752 auto str_ptr = str.data(); // Pointer to traverse input string
753
754 while (*str_ptr != 0) {
755 auto ch = static_cast<unsigned char>(*str_ptr++);
756
757 if (expected_bytes == 0) {
758 // Determine sequence length based on first byte
759 if (ch <= 0x7f) {
760 codepoint = ch;
761 out.push_back(static_cast<xtd::char32>(codepoint));
762 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
763 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
764 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
765 else out.push_back(0xfffd); // Invalid first byte → replace
766 } else {
767 // Continuation byte
768 if ((ch & 0xc0) != 0x80) {
769 // Unexpected byte → invalid sequence
770 out.push_back(0xfffd);
771 expected_bytes = 0;
772 --str_ptr; // Re-evaluate this byte as first byte
773 continue;
774 }
775 codepoint = (codepoint << 6) | (ch & 0x3f);
776 --expected_bytes;
777
778 if (expected_bytes == 0) {
779 // Sequence complete, check valid Unicode range
780 if (codepoint > 0x10ffff) codepoint = 0xfffd;
781 out.push_back(static_cast<xtd::char32>(codepoint));
782 }
783 }
784 }
785
786 // If string ends prematurely, insert replacement character
787 if (expected_bytes != 0) out.push_back(0xfffd);
788 return out;
789}
790
791template<>
792inline std::basic_string<char> __xtd_convert_to_string<char, char>(std::basic_string<char>&& str) noexcept {
793 return std::move(str);
794}
795
796template<>
797inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
798 return std::move(str);
799}
800
801template<>
802inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
803 return std::move(str);
804}
805
806template<>
807inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
808 return std::move(str);
809}
810
811template<>
812inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
813 return std::move(str);
814}
815
816template<>
817inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, char>(std::basic_string<char>&& str) noexcept {
818 return std::basic_string<xtd::char8> {reinterpret_cast<const xtd::char8*>(str.c_str())};
819}
820
821template<>
822inline std::basic_string<char> __xtd_convert_to_string<char, xtd::char8>(std::basic_string<xtd::char8>&& str) noexcept {
823 return std::basic_string<char> {reinterpret_cast<const char*>(str.c_str())};
824}
825
826template<>
827inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
828 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(std::move(str)));
829}
830
831template<>
832inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
833 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(std::move(str)));
834}
835
836template<>
837inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
838 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(std::move(str)));
839}
840
841template<>
842inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::wchar>(std::basic_string<xtd::wchar>&& str) noexcept {
843 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(std::move(str)));
844}
845
846template<>
847inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char16>(std::basic_string<xtd::char16>&& str) noexcept {
848 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(std::move(str)));
849}
850
851template<>
852inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char32>(std::basic_string<xtd::char32>&& str) noexcept {
853 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(std::move(str)));
854}
855
856template<class target_t, class source_t>
857inline std::basic_string<target_t> __xtd_convert_to_string(const std::basic_string<source_t>& str) noexcept {
858 auto out = std::basic_string<target_t> {};
859 auto codepoint = 0u;
860 for (const auto& character : str) {
861 if (character >= 0xd800 && character <= 0xdbff)
862 codepoint = ((character - 0xd800) << 10) + 0x10000;
863 else {
864 if (character >= 0xdc00 && character <= 0xdfff) codepoint |= character - 0xdc00;
865 else codepoint = character;
866
867 if (codepoint <= 0x7f)
868 out.append(1, static_cast<target_t>(codepoint));
869 else if (codepoint <= 0x7ff) {
870 out.append(1, static_cast<target_t>(0xc0 | ((codepoint >> 6) & 0x1f)));
871 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
872 } else if (codepoint <= 0xffff) {
873 out.append(1, static_cast<target_t>(0xe0 | ((codepoint >> 12) & 0x0f)));
874 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
875 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
876 } else {
877 out.append(1, static_cast<target_t>(0xf0 | ((codepoint >> 18) & 0x07)));
878 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 12) & 0x3f)));
879 out.append(1, static_cast<target_t>(0x80 | ((codepoint >> 6) & 0x3f)));
880 out.append(1, static_cast<target_t>(0x80 | (codepoint & 0x3f)));
881 }
882 codepoint = 0;
883 }
884 }
885 return out;
886}
887
891template<>
892inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, char>(const std::basic_string<char>& str) noexcept {
893 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
894 auto codepoint = 0u; // Current Unicode code point
895 auto expected_bytes = 0; // Number of continuation bytes expected
896 auto str_ptr = str.data(); // Pointer to traverse input string
897
898 while (*str_ptr != 0) {
899 auto ch = static_cast<unsigned char>(*str_ptr++);
900
901 if (expected_bytes == 0) {
902 // Determine the sequence length based on the first byte
903 if (ch <= 0x7f) {
904 codepoint = ch;
905 expected_bytes = 0;
906 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
907 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
908 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
909 else {
910 // Invalid first byte → replacement character
911 out.push_back(0xfffd);
912 continue;
913 }
914 } else {
915 // Continuation byte
916 if ((ch & 0xc0) != 0x80) {
917 // Unexpected byte → invalid sequence
918 out.push_back(0xfffd);
919 expected_bytes = 0;
920 --str_ptr; // Re-evaluate this byte as first byte
921 continue;
922 }
923 codepoint = (codepoint << 6) | (ch & 0x3f);
924 --expected_bytes;
925 }
926
927 // Sequence complete
928 if (expected_bytes == 0) {
929 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
930
931 if (codepoint > 0xffff) {
932 // Code point requires surrogate pair
933 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
934 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
935 out.push_back(static_cast<xtd::char16>(high));
936 out.push_back(static_cast<xtd::char16>(low));
937 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
938 else out.push_back(0xfffd); // Surrogate range in input → replace
939 }
940 }
941
942 // If string ends prematurely, insert replacement character
943 if (expected_bytes != 0) out.push_back(0xfffd);
944 return out;
945}
946
950template<>
951inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
952 auto out = std::basic_string<xtd::char16> {}; // Output UTF-16 string
953 auto codepoint = 0u; // Current Unicode code point
954 auto expected_bytes = 0; // Number of continuation bytes expected
955 auto str_ptr = str.data(); // Pointer to traverse input string
956
957 while (*str_ptr != 0) {
958 auto ch = static_cast<unsigned char>(*str_ptr++);
959
960 if (expected_bytes == 0) {
961 // Determine the sequence length based on the first byte
962 if (ch <= 0x7f) {
963 codepoint = ch;
964 expected_bytes = 0;
965 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
966 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
967 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
968 else {
969 // Invalid first byte → replacement character
970 out.push_back(0xfffd);
971 continue;
972 }
973 } else {
974 // Continuation byte
975 if ((ch & 0xc0) != 0x80) {
976 // Unexpected byte → invalid sequence
977 out.push_back(0xfffd);
978 expected_bytes = 0;
979 --str_ptr; // Re-evaluate this byte as first byte
980 continue;
981 }
982 codepoint = (codepoint << 6) | (ch & 0x3f);
983 --expected_bytes;
984 }
985
986 // Sequence complete
987 if (expected_bytes == 0) {
988 if (codepoint > 0x10ffff) codepoint = 0xfffd; // Unicode limit
989
990 if (codepoint > 0xffff) {
991 // Code point requires surrogate pair
992 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
993 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
994 out.push_back(static_cast<xtd::char16>(high));
995 out.push_back(static_cast<xtd::char16>(low));
996 } else if (codepoint < 0xd800 || codepoint >= 0xe000) out.push_back(static_cast<xtd::char16>(codepoint)); // Normal BMP character, not a surrogate
997 else out.push_back(0xfffd); // Surrogate range in input → replace
998 }
999 }
1000
1001 // If string ends prematurely, insert replacement character
1002 if (expected_bytes != 0) out.push_back(0xfffd);
1003 return out;
1004}
1005
1009template<>
1010inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, char>(const std::basic_string<char>& str) noexcept {
1011 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
1012 auto codepoint = 0u; // Current Unicode code point
1013 auto expected_bytes = 0; // Continuation bytes expected
1014 auto str_ptr = str.data(); // Pointer to traverse input
1015
1016 while (*str_ptr != 0) {
1017 auto ch = static_cast<unsigned char>(*str_ptr++);
1018
1019 if (expected_bytes == 0) {
1020 // Determine sequence length based on first byte
1021 if (ch <= 0x7f) {
1022 codepoint = ch;
1023 expected_bytes = 0;
1024 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1025 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1026 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1027 else {
1028 out.push_back(0xfffd); // Invalid first byte → replace
1029 continue;
1030 }
1031 } else {
1032 // Continuation byte
1033 if ((ch & 0xc0) != 0x80) {
1034 // Unexpected byte → invalid sequence
1035 out.push_back(0xfffd);
1036 expected_bytes = 0;
1037 --str_ptr; // Re-evaluate this byte as first byte
1038 continue;
1039 }
1040 codepoint = (codepoint << 6) | (ch & 0x3f);
1041 --expected_bytes;
1042 }
1043
1044 // Sequence complete
1045 if (expected_bytes == 0) {
1046 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1047
1048 if (sizeof(xtd::wchar) > 2) {
1049 // UTF-32 capable
1050 out.push_back(static_cast<xtd::wchar>(codepoint));
1051 } else {
1052 // UTF-16, may need surrogate pairs
1053 if (codepoint > 0xffff) {
1054 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
1055 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
1056 out.push_back(static_cast<xtd::wchar>(high));
1057 out.push_back(static_cast<xtd::wchar>(low));
1058 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
1059 out.push_back(static_cast<xtd::wchar>(codepoint));
1060 else {
1061 // Surrogate range in input → replace
1062 out.push_back(0xfffd);
1063 }
1064 }
1065 }
1066 }
1067
1068 // If string ends prematurely, insert replacement character
1069 if (expected_bytes != 0) out.push_back(0xfffd);
1070 return out;
1071}
1072
1076template<>
1077inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1078 auto out = std::basic_string<xtd::wchar> {}; // Output UTF string
1079 auto codepoint = 0u; // Current Unicode code point
1080 auto expected_bytes = 0; // Continuation bytes expected
1081 auto str_ptr = str.data(); // Pointer to traverse input
1082
1083 while (*str_ptr != 0) {
1084 auto ch = static_cast<unsigned char>(*str_ptr++);
1085
1086 if (expected_bytes == 0) {
1087 // Determine sequence length based on first byte
1088 if (ch <= 0x7f) {
1089 codepoint = ch;
1090 expected_bytes = 0;
1091 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1092 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1093 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1094 else {
1095 out.push_back(0xfffd); // Invalid first byte → replace
1096 continue;
1097 }
1098 } else {
1099 // Continuation byte
1100 if ((ch & 0xc0) != 0x80) {
1101 // Unexpected byte → invalid sequence
1102 out.push_back(0xfffd);
1103 expected_bytes = 0;
1104 --str_ptr; // Re-evaluate this byte as first byte
1105 continue;
1106 }
1107 codepoint = (codepoint << 6) | (ch & 0x3f);
1108 --expected_bytes;
1109 }
1110
1111 // Sequence complete
1112 if (expected_bytes == 0) {
1113 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1114
1115 if (sizeof(xtd::wchar) > 2) {
1116 // UTF-32 capable
1117 out.push_back(static_cast<xtd::wchar>(codepoint));
1118 } else {
1119 // UTF-16, may need surrogate pairs
1120 if (codepoint > 0xffff) {
1121 unsigned int high = 0xd800 + ((codepoint - 0x10000) >> 10);
1122 unsigned int low = 0xdc00 + ((codepoint - 0x10000) & 0x3ff);
1123 out.push_back(static_cast<xtd::wchar>(high));
1124 out.push_back(static_cast<xtd::wchar>(low));
1125 } else if (codepoint < 0xd800 || codepoint >= 0xe000)
1126 out.push_back(static_cast<xtd::wchar>(codepoint));
1127 else {
1128 // Surrogate range in input → replace
1129 out.push_back(0xfffd);
1130 }
1131 }
1132 }
1133 }
1134
1135 // If string ends prematurely, insert replacement character
1136 if (expected_bytes != 0) out.push_back(0xfffd);
1137 return out;
1138}
1139
1143template<>
1144inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, char>(const std::basic_string<char>& str) noexcept {
1145 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
1146 auto codepoint = 0u; // Current Unicode code point
1147 auto expected_bytes = 0; // Number of continuation bytes expected
1148 auto str_ptr = str.data(); // Pointer to traverse input string
1149
1150 while (*str_ptr != 0) {
1151 auto ch = static_cast<unsigned char>(*str_ptr++);
1152
1153 if (expected_bytes == 0) {
1154 // Determine sequence length based on first byte
1155 if (ch <= 0x7f) {
1156 codepoint = ch;
1157 out.push_back(static_cast<xtd::char32>(codepoint));
1158 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1159 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1160 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1161 else out.push_back(0xfffd); // Invalid first byte → replace
1162 } else {
1163 // Continuation byte
1164 if ((ch & 0xc0) != 0x80) {
1165 // Unexpected byte → invalid sequence
1166 out.push_back(0xfffd);
1167 expected_bytes = 0;
1168 --str_ptr; // Re-evaluate this byte as first byte
1169 continue;
1170 }
1171 codepoint = (codepoint << 6) | (ch & 0x3f);
1172 --expected_bytes;
1173
1174 if (expected_bytes == 0) {
1175 // Sequence complete, check valid Unicode range
1176 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1177 out.push_back(static_cast<xtd::char32>(codepoint));
1178 }
1179 }
1180 }
1181
1182 // If string ends prematurely, insert replacement character
1183 if (expected_bytes != 0) out.push_back(0xfffd);
1184 return out;
1185}
1186
1190template<>
1191inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1192 auto out = std::basic_string<xtd::char32> {}; // Output UTF-32 string
1193 auto codepoint = 0u; // Current Unicode code point
1194 auto expected_bytes = 0; // Number of continuation bytes expected
1195 auto str_ptr = str.data(); // Pointer to traverse input string
1196
1197 while (*str_ptr != 0) {
1198 auto ch = static_cast<unsigned char>(*str_ptr++);
1199
1200 if (expected_bytes == 0) {
1201 // Determine sequence length based on first byte
1202 if (ch <= 0x7f) {
1203 codepoint = ch;
1204 out.push_back(static_cast<xtd::char32>(codepoint));
1205 } else if (ch <= 0xdf) { codepoint = ch & 0x1f; expected_bytes = 1; }
1206 else if (ch <= 0xef) { codepoint = ch & 0x0f; expected_bytes = 2; }
1207 else if (ch <= 0xf7) { codepoint = ch & 0x07; expected_bytes = 3; }
1208 else out.push_back(0xfffd); // Invalid first byte → replace
1209 } else {
1210 // Continuation byte
1211 if ((ch & 0xc0) != 0x80) {
1212 // Unexpected byte → invalid sequence
1213 out.push_back(0xfffd);
1214 expected_bytes = 0;
1215 --str_ptr; // Re-evaluate this byte as first byte
1216 continue;
1217 }
1218 codepoint = (codepoint << 6) | (ch & 0x3f);
1219 --expected_bytes;
1220
1221 if (expected_bytes == 0) {
1222 // Sequence complete, check valid Unicode range
1223 if (codepoint > 0x10ffff) codepoint = 0xfffd;
1224 out.push_back(static_cast<xtd::char32>(codepoint));
1225 }
1226 }
1227 }
1228
1229 // If string ends prematurely, insert replacement character
1230 if (expected_bytes != 0) out.push_back(0xfffd);
1231 return out;
1232}
1233
1234template<>
1235inline std::basic_string<char> __xtd_convert_to_string<char, char>(const std::basic_string<char>& str) noexcept {
1236 return str;
1237}
1238
1239template<>
1240inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1241 return str;
1242}
1243
1244template<>
1245inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1246 return str;
1247}
1248
1249template<>
1250inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1251 return str;
1252}
1253
1254template<>
1255inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1256 return str;
1257}
1258
1259template<>
1260inline std::basic_string<xtd::char8> __xtd_convert_to_string<xtd::char8, char>(const std::basic_string<char>& str) noexcept {
1261 return reinterpret_cast<const xtd::char8*>(str.c_str());
1262}
1263
1264template<>
1265inline std::basic_string<char> __xtd_convert_to_string<char, xtd::char8>(const std::basic_string<xtd::char8>& str) noexcept {
1266 return reinterpret_cast<const char*>(str.c_str());
1267}
1268
1269template<>
1270inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1271 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(str));
1272}
1273
1274template<>
1275inline std::basic_string<xtd::char16> __xtd_convert_to_string<xtd::char16, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1276 return __xtd_convert_to_string<xtd::char16>(__xtd_convert_to_string<char>(str));
1277}
1278
1279template<>
1280inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1281 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(str));
1282}
1283
1284template<>
1285inline std::basic_string<xtd::char32> __xtd_convert_to_string<xtd::char32, xtd::wchar>(const std::basic_string<xtd::wchar>& str) noexcept {
1286 return __xtd_convert_to_string<xtd::char32>(__xtd_convert_to_string<char>(str));
1287}
1288
1289template<>
1290inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char16>(const std::basic_string<xtd::char16>& str) noexcept {
1291 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(str));
1292}
1293
1294template<>
1295inline std::basic_string<xtd::wchar> __xtd_convert_to_string<xtd::wchar, xtd::char32>(const std::basic_string<xtd::char32>& str) noexcept {
1296 return __xtd_convert_to_string<xtd::wchar>(__xtd_convert_to_string<char>(str));
1297}
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
basic_string pad_left(xtd::size total_width) const noexcept
Right-aligns the characters in this basic_string, padding with spaces on the left for a specified tot...
Definition basic_string.hpp:1022
static const basic_string empty_string
Represents the empty basic_string.
Definition basic_string.hpp:111
basic_string trim() const noexcept
Removes all leading and trailing occurrences of white-space characters from the specified xtd::basic_...
Definition basic_string.hpp:1407
xtd::array< basic_string > split() const noexcept
Splits this basic_string into substrings that are based on the default white-space characters....
static basic_string join(const basic_string &separator, const collection_t &values) noexcept
Concatenates a specified separator basic_string between each element of a specified object array,...
Definition basic_string.hpp:1701
const base_type & chars() const noexcept
Returns a reference to the underlying base type.
Definition basic_string.hpp:354
xtd::size index_of_any(const xtd::array< value_type > &values) const noexcept
Reports the index of the first occurrence in this instance of any character in a specified array of c...
xtd::array< value_type > to_char_array() const noexcept
Copies the characters in this instance to a Unicode character array.
static basic_string concat(const basic_string &str_a, const basic_string &str_b, const basic_string &str_c, const basic_string &str_d) noexcept
Concatenates four specified instances of basic_string.
Definition basic_string.hpp:1535
basic_string trim_end() const noexcept
Removes all trailing occurrences of white-space characters from the specified xtd::basic_string.
Definition basic_string.hpp:1423
xtd::size last_index_of_any(const xtd::array< value_type > &values) const noexcept
Reports the index of the last occurrence in this instance of any character in a specified array of ch...
basic_string to_title_case() const noexcept
Converts the current basic_string to title case (except for words that are entirely in uppercase,...
virtual size_type length() const noexcept
Gets the number of characters in the current xtd::basic_string object.
Definition basic_string.hpp:380
basic_string pad_right(xtd::size total_width) const noexcept
Left-aligns the characters in this basic_string, padding with spaces on the right for a specified tot...
Definition basic_string.hpp:1036
basic_string trim_start() const noexcept
Removes all leading occurrences of white-space characters from the specified xtd::basic_string.
Definition basic_string.hpp:1439
virtual bool empty() const noexcept
Checks whether the container is empty.
Definition basic_string.hpp:375
xtd::array< value_type > to_array() const noexcept
Copies the characters in this instance to a Unicode character array.
basic_string< xtd::char32 > to_u32string() const noexcept
Converts the value of this instance to a xtd::basic_string <xtd::char32>.
Definition basic_string.hpp:1376
static auto throws(xtd::helpers::exception_case exception_case, const source_location &location=source_location::current()) -> void
Throws an exption with specified exception case.
static basic_string format(const basic_string< char > &fmt, args_t &&... args)
Writes the text representation of the specified arguments list, to string using the specified format ...
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
virtual auto count() const noexcept -> xtd::size=0
Gets the number of elements contained in the xtd::collections::generic::icollection <type_t>.
const xtd::collections::generic::helpers::wrap_pointer_iterator< pointer > iterator
Represents the iterator of read_only_span value type.
Definition read_only_span.hpp:74
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.