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