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