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