YSTest: string.hpp 源文件

YSTest PreAlpha_b700_20160611 The YSLib Test Project

- 首页
- 相关页面
- 模块
- 命名空间
- 类
- 文件

- 文件列表
- 文件成员

string.hpp
浏览该文件的文档.
1 /*
2 © 2012-2016 FrankHB.
3
4 This file is part of the YSLib project, and may only be used,
5 modified, and distributed under the terms of the YSLib project
6 license, LICENSE.TXT. By continuing to use, modify, or distribute
7 this file you indicate that you have read the license and
8 understand and accept it fully.
9 */
10
28 #ifndef YB_INC_ystdex_string_hpp_
29 #define YB_INC_ystdex_string_hpp_ 1
30
31 #include "memory.hpp" // for decay_t, remove_rcv_t, std::declval,
32 // nested_allocator, is_enum, is_class;
33 #include <libdefect/string.h> // for std::char_traits, std::initializer_list,
34 // std::to_string;
35 #include "container.hpp" // for "container.hpp", make_index_sequence,
36 // index_sequence, begin, end, sort_unique, size, underlying;
37 #include "cstdio.h" // for yconstraint, vfmtlen;
38 #include "cstring.h" // for ntctslen;
39 #include "array.hpp" // for std::bidirectional_iterator_tag, to_array;
40 #include <istream> // for std::basic_istream;
41 #include "ios.hpp" // for rethrow_badstate;
42 #include <ostream> // for std::basic_ostream;
43 #include <sstream> // for std::ostringstream, std::wostring_stream;
44 #include <cstdarg> // for std::va_list;
45
46 namespace ystdex
47 {
48
54 template<typename _tString>
55 struct string_traits
56 {
57 using string_type = remove_rcv_t<_tString>;
58 using value_type = remove_rcv_t<decltype(std::declval<string_type>()[0])>;
59 using traits_type = typename std::char_traits<value_type>;
61
62 using allocator_type = _t<nested_allocator<string_type>>;
63 using size_type = typename std::allocator_traits<allocator_type>::size_type;
64 using difference_type
65 = typename std::allocator_traits<allocator_type>::difference_type;
66 using reference = value_type&;
67 using const_reference = const value_type&;
69 using pointer = value_type*;
70 using const_pointer = const value_type*;
71 using initializer = std::initializer_list<value_type>;
72 };
73
74
76 namespace details
77 {
78
80
81 template<typename _type, typename = void>
82 struct is_string_like : false_type
83 {};
84
85 template<typename _type>
86 struct is_string_like<_type, enable_if_t<
87 is_object<decay_t<decltype(std::declval<_type>()[0])>>::value>> : true_type
88 {};
90
91
93 template<typename _tFwd1, typename _tFwd2, typename _fPred>
94 bool
95 ends_with_iter_dispatch(_tFwd1 b, _tFwd1 e, _tFwd2 bt, _tFwd2 et,
96 _fPred comp, std::bidirectional_iterator_tag)
97 {
98 auto i(e);
99 auto it(et);
100
101 while(i != b && it != bt)
102 if(!comp(*--i, *--it))
103 return {};
104 return it == bt;
105 }
106
107
109
110 template<size_t>
111 struct str_algos;
112
113 template<>
114 struct str_algos<0>
115 {
117 template<class _tString,
118 typename _tSize = typename string_traits<_tString>::size_type>
119 static yconstfn auto
120 erase_left(_tString& s, _tSize n) ynothrowv
121 -> yimpl(decltype(s.remove_prefix(n), s))
122 {
123 return yconstraint(n < s.size() || n == _tSize(-1)),
124 s.remove_prefix(n != _tSize(-1) ? n : _tSize(s.size())), s;
125 }
126
128 template<class _tString,
129 typename _tSize = typename string_traits<_tString>::size_type>
130 static yconstfn auto
131 erase_right(_tString& s, _tSize n) ynothrowv
132 -> yimpl(decltype(s.remove_suffix(n), s))
133 {
134 return yconstraint(n < s.size() || n == _tSize(-1)),
135 s.remove_suffix(s.size() - n - 1), s;
136 }
137 };
138
139 template<>
140 struct str_algos<1>
141 {
143 template<class _tString,
144 typename _tSize = typename string_traits<_tString>::size_type>
145 static yconstfn auto
146 erase_left(_tString& s, _tSize n) ynothrowv
147 -> yimpl(decltype(s.erase(0, n)))
148 {
149 return yconstraint(n < s.size() || n == _tSize(-1)), s.erase(0, n);
150 }
151
153 template<class _tString,
154 typename _tSize = typename string_traits<_tString>::size_type>
155 static yconstfn auto
156 erase_right(_tString& s, _tSize n) ynothrowv
157 -> yimpl(decltype(s.erase(n + 1)))
158 {
159 return yconstraint(n < s.size() || n == _tSize(-1)), s.erase(n + 1);
160 }
161 };
162
163
164 template<yimpl(typename = make_index_sequence<2>)>
165 struct str_algo;
166
167 template<>
168 struct str_algo<index_sequence<>>
169 {
170 void
171 erase_left() = delete;
172
173 void
174 erase_right() = delete;
175 };
176
177 template<size_t _vIdx, size_t... _vSeq>
178 struct str_algo<index_sequence<_vIdx, _vSeq...>>
179 : str_algos<_vIdx>, str_algo<index_sequence<_vSeq...>>
180 {
181 using str_algos<_vIdx>::erase_left;
182 using str_algo<index_sequence<_vSeq...>>::erase_left;
183 using str_algos<_vIdx>::erase_right;
184 using str_algo<index_sequence<_vSeq...>>::erase_right;
185 };
187
188 } // unnamed namespace;
189
190
192
193
197 template<typename _type>
198 struct is_string_like : details::is_string_like<_type>
199 {};
200
205 template<typename _type>
206 struct is_string_class : and_<is_class<_type>, is_string_like<_type>>
207 {};
209
210
217 template<typename _tParam, typename _type = void>
218 using enable_for_string_class_t
219 = enable_if_t<is_string_class<decay_t<_tParam>>::value, _type>;
220
221
231 template<class _tRange>
232 yconstfn auto
233 string_begin(_tRange& c) -> decltype(c.begin())
234 {
235 return begin(c);
236 }
237 template<class _tRange>
238 yconstfn auto
239 string_begin(const _tRange& c) -> decltype(c.begin())
240 {
241 return begin(c);
242 }
244
245 template<typename _tChar>
246 yconstfn _tChar*
247 string_begin(_tChar* str) ynothrow
248 {
249 return yconstraint(str), str;
250 }
251 #if __cplusplus <= 201402L
252 template<typename _tElem>
254 yconstfn auto
255 string_begin(std::initializer_list<_tElem> il) -> decltype(il.begin())
256 {
257 return il.begin();
258 }
259 #endif
260
261
262 template<class _tRange>
263 yconstfn auto
264 string_end(_tRange& c) -> decltype(c.end())
265 {
266 return end(c);
267 }
268 template<class _tRange>
269 yconstfn auto
270 string_end(const _tRange& c) -> decltype(c.end())
271 {
272 return end(c);
273 }
275
276 template<typename _tChar>
277 yconstfn _tChar*
278 string_end(_tChar* str) ynothrow
279 {
280 return str + ystdex::ntctslen(str);
281 }
282 #if __cplusplus <= 201402L
283 template<typename _tElem>
285 yconstfn auto
286 string_end(std::initializer_list<_tElem> il) -> decltype(il.end())
287 {
288 return il.end();
289 }
290 #endif
291
292
293
294
307 template<typename _type>
308 inline size_t
309 string_length(const _type* str) ynothrow
310 {
311 return std::char_traits<_type>::length(str);
312 }
313 template<typename _type>
314 yconstfn auto
315 string_length(const _type& str) -> decltype(size(str))
316 {
317 return size(str);
318 }
319 #if __cplusplus <= 201402L
320 template<typename _tElem>
322 yconstfn size_t
323 string_length(std::initializer_list<_tElem> il)
324 {
325 return il.size();
326 }
327 #endif
328
329
330
338
340 template<typename _tRange1, typename _tRange2, typename _fPred>
342 bool
343 begins_with(const _tRange1& input, const _tRange2& test, _fPred comp)
344 {
345 return ystdex::string_length(test) <= ystdex::string_length(input)
346 && std::equal(string_begin(test), string_end(test),
347 string_begin(input), comp);
348 }
350 template<typename _tRange1, typename _tRange2>
351 inline bool
352 begins_with(const _tRange1& input, const _tRange2& test)
353 {
354 return ystdex::begins_with(input, test, is_equal());
355 }
357
359
360 template<typename _tRange1, typename _tRange2, typename _fPred>
361 inline bool
362 ends_with(const _tRange1& input, const _tRange2& test, _fPred comp)
363 {
364 // NOTE: See $2014-07 @ %Documentation::Workflow::Annual2014.
365 return details::ends_with_iter_dispatch(string_begin(input),
366 string_end(input), string_begin(test), string_end(test), comp, typename
367 std::iterator_traits<remove_reference_t<decltype(string_begin(input))>>
368 ::iterator_category());
369 }
370 template<typename _tRange1, typename _tRange2>
371 inline bool
372 ends_with(const _tRange1& input, const _tRange2& test)
373 {
374 return ystdex::ends_with(input, test, is_equal());
375 }
377
378
379
386 template<class _tString, typename _type>
387 inline bool
388 exists_substr(const _tString& str, const _type& sub)
389 {
390 return str.find(sub) != _tString::npos;
391 }
392 template<class _tString, typename _type>
393 inline bool
394 exists_substr(const _tString& str, const typename _tString::value_type* p_sub)
395 {
396 yconstraint(p_sub);
397
398 return str.find(p_sub) != _tString::npos;
399 }
401
402
404
405
410 template<class _tString>
411 auto
412 normalize(_tString& str) -> decltype(str.resize(ystdex::ntctslen(str.c_str())))
413 {
414 return str.resize(ystdex::ntctslen(str.c_str()));
415 }
416
424 template<class _tString,
426 yimpl(typename = ystdex::enable_for_string_class_t<_tString>)>
427 inline _tString&&
428 ntctsncpy(_tString&& str, const typename string_traits<_tString>::const_pointer
429 s, const typename string_traits<_tString>::size_type n)
430 {
431 yconstraint(s);
432 return static_cast<_tString&&>(str = decay_t<_tString>(s, n));
433 }
434 template<class _tString,
435 yimpl(typename = ystdex::enable_for_string_class_t<_tString>)>
436 inline _tString&&
437 ntctsncpy(_tString&& str, _tString&& s,
438 const typename string_traits<_tString>::size_type n)
439 {
440 auto sub(yforward(s));
441
442 sub.resize(n);
443 return static_cast<_tString&&>(str = std::move(sub));
444 }
446
447
448
453 template<class _tString>
454 inline _tString&&
455 restrict_length(_tString&& str,
456 const typename string_traits<_tString>::size_type n)
457 {
458 if(n < str.length())
459 str.resize(n);
460 return static_cast<_tString&&>(str);
461 }
462
463
468 template<class _tString>
469 _tString
470 alph(_tString& str)
471 {
472 _tString res(str);
473
474 ystdex::sort_unique(res);
475 return res;
476 }
477
486 template<class _tString>
487 void
488 concat(_tString& str, size_t n)
489 {
490 yconstraint(n != 0);
491 if(1 < n)
492 {
493 const auto len(str.length());
494
495 ystdex::concat(str, n / 2);
496 str.append(str.data(), str.length());
497 if(n % 2 != 0)
498 str.append(str.data(), len);
499 }
500 }
501
503
504
506
508 template<class _tString>
509 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
510 erase_left(typename string_traits<_tString>::size_type pos, _tString&& str)
511 {
512 return static_cast<_tString&&>(pos != decay_t<_tString>::npos
513 ? details::str_algo<>::erase_left(str, pos) : str);
514 }
515 template<class _tString>
516 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
517 erase_left(_tString&& str, typename string_traits<_tString>::value_type c)
518 {
519 return static_cast<_tString&&>(ystdex::erase_left(str.find_last_of(c), str));
520 }
521 template<class _tString>
522 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
523 erase_left(_tString&& str, const remove_reference_t<_tString>& t)
524 {
525 return static_cast<_tString&&>(ystdex::erase_left(str.find_last_of(t), str));
526 }
531 template<class _tString>
532 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
533 erase_left(_tString&& str, typename string_traits<_tString>::const_pointer t
534 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
535 {
536 yconstraint(t);
537 return static_cast<_tString&&>(ystdex::erase_left(str.find_last_of(t), str));
538 }
540
542
543 template<class _tString>
544 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
545 erase_right(typename string_traits<_tString>::size_type pos, _tString&& str)
546 {
547 return static_cast<_tString&&>(pos != decay_t<_tString>::npos
548 ? details::str_algo<>::erase_right(str, pos) : str);
549 }
550 template<class _tString>
551 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
552 erase_right(_tString&& str, typename string_traits<_tString>::value_type c)
553 {
554 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(c),
555 str));
556 }
558 template<class _tString>
559 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
560 erase_right(_tString&& str, const remove_reference_t<_tString>& t)
561 {
562 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(t),
563 str));
564 }
569 template<class _tString>
570 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
571 erase_right(_tString&& str, typename string_traits<_tString>::const_pointer t
572 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
573 {
574 yconstraint(t);
575 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(t),
576 str));
577 }
579
580
582
583
585 template<class _tString>
586 yconstfn _tString&&
587 ltrim(_tString&& str, typename string_traits<_tString>::value_type c)
588 {
589 return static_cast<_tString&&>(
590 details::str_algo<>::erase_left(str, str.find_first_not_of(c)));
591 }
593 template<class _tString>
594 inline _tString&&
595 ltrim(_tString&& str, const _tString& t)
596 {
597 return static_cast<_tString&&>(
598 details::str_algo<>::erase_left(str, str.find_first_not_of(t)));
599 }
604 template<class _tString>
605 yconstfn _tString&&
606 ltrim(_tString&& str, typename string_traits<_tString>::const_pointer t
607 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
608 {
609 return yconstraint(t), static_cast<_tString&&>(
610 details::str_algo<>::erase_left(str, str.find_first_not_of(t)));
611 }
613
615
616 template<class _tString>
617 yconstfn _tString&&
618 rtrim(_tString&& str, typename string_traits<_tString>::value_type c)
619 {
620 return static_cast<_tString&&>(
621 details::str_algo<>::erase_right(str, str.find_last_not_of(c)));
622 }
624 template<class _tString>
625 yconstfn _tString&&
626 rtrim(_tString&& str, const remove_reference_t<_tString>& t) ynothrowv
627 {
628 return static_cast<_tString&&>(
629 details::str_algo<>::erase_right(str, str.find_last_not_of(t)));
630 }
635 template<class _tString>
636 yconstfn _tString&&
637 rtrim(_tString&& str, typename string_traits<_tString>::const_pointer t
638 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
639 {
640 return yconstraint(t), static_cast<_tString&&>(
641 details::str_algo<>::erase_right(str, str.find_last_not_of(t)));
642 }
644
646
647 template<class _tString>
648 yconstfn _tString&&
649 trim(_tString&& str, typename string_traits<_tString>::value_type c)
650 {
651 return yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), c)), c));
652 }
654 template<class _tString>
655 yconstfn _tString&&
656 trim(_tString&& str, const _tString& t) ynothrowv
657 {
658 return yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), t)), t));
659 }
664 template<class _tString>
665 yconstfn _tString&&
666 trim(_tString&& str, typename string_traits<_tString>::const_pointer t
667 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
668 {
669 return yconstraint(t),
670 yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), t)), t));
671 }
673
674
675
676
678
679
681 template<typename _tString, typename... _tParams>
682 inline _tString
683 find_prefix(const _tString& str, _tParams&&... args)
684 {
685 if(!str.empty())
686 {
687 const auto pos(str.find(yforward(args)...));
688
689 if(pos != _tString::npos)
690 return str.substr(0, pos);
691 }
692 return {};
693 }
695
697
698 template<typename _tString, typename... _tParams>
699 inline _tString
700 find_suffix(const _tString& str, _tParams&&... args)
701 {
702 if(!str.empty())
703 {
704 const auto pos(str.rfind(yforward(args)...));
705
706 if(pos != _tString::npos)
707 return str.substr(pos + 1);
708 }
709 return {};
710 }
712
713
724 template<typename _tString>
725 yconstfn typename string_traits<_tString>::value_type
726 get_quote_mark_nonstrict(const _tString& str)
727 {
728 return str.front() == str.back() ? str.front()
729 : typename string_traits<_tString>::value_type();
730 }
732
739 template<typename _tString>
740 inline _tString
741 quote(const _tString& str, typename string_traits<_tString>::value_type c
742 = typename string_traits<_tString>::value_type('"'))
743 {
744 return c + str + c;
745 }
746 template<typename _tString, typename _tString2>
747 inline yimpl(enable_if_t)<!is_convertible<_tString2,
748 typename string_traits<_tString>::value_type>::value ,_tString>
749 quote(const _tString& str, const _tString2& s)
750 {
751 return s + str + s;
752 }
753 template<typename _tString, typename _tPrefix, typename _tSuffix>
754 inline _tString
755 quote(const _tString& str, const _tPrefix& pfx, const _tSuffix& sfx)
756 {
757 return pfx + str + sfx;
758 }
760
767 template<typename _tString>
768 inline _tString
769 get_mid(const _tString& str, typename _tString::size_type l = 1)
770 {
771 yassume(!(str.size() < l * 2));
772 return str.substr(l, str.size() - l * 2);
773 }
774 template<typename _tString>
775 inline _tString
776 get_mid(const _tString& str, typename _tString::size_type l,
777 typename _tString::size_type r)
778 {
779 yassume(!(str.size() < l + r));
780 return str.substr(l, str.size() - l - r);
781 }
783
784
785
786
792 template<typename _tChar, class _tTraits, class _tAlloc, typename _func>
794 std::basic_istream<_tChar, _tTraits>&
795 extract(std::basic_istream<_tChar, _tTraits>& is,
796 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _func f)
797 {
798 std::string::size_type n(0);
799 auto st(std::ios_base::goodbit);
800
801 if(const auto k
802 = typename std::basic_istream<_tChar, _tTraits>::sentry(is, true))
803 {
804 const auto msize(str.max_size());
805 const auto p_buf(is.rdbuf());
806
807 yassume(p_buf);
808 str.erase();
809 try
810 {
811 const auto eof(_tTraits::eof());
812
813 for(auto c(p_buf->sgetc()); ; c = p_buf->snextc())
814 {
815 if(_tTraits::eq_int_type(c, eof))
816 {
817 st |= std::ios_base::eofbit;
818 break;
819 }
820 if(f(c, *p_buf))
821 {
822 ++n;
823 break;
824 }
825 if(!(str.length() < msize))
826 {
827 st |= std::ios_base::failbit;
828 break;
829 }
830 str.append(1, _tTraits::to_char_type(c));
831 ++n;
832 }
833 }
834 catch(...)
835 {
836 // NOTE: See http://wg21.cmeerw.net/lwg/issue91.
837 rethrow_badstate(is, std::ios_base::badbit);
838 }
839 }
840 if(n == 0)
841 st |= std::ios_base::failbit;
842 if(st)
843 is.setstate(st);
844 return is;
845 }
846
848
849 template<typename _tChar, class _tTraits, class _tAlloc>
850 std::basic_istream<_tChar, _tTraits>&
851 extract_line(std::basic_istream<_tChar, _tTraits>& is,
852 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _tChar delim)
853 {
854 const auto d(_tTraits::to_int_type(delim));
855
856 return ystdex::extract(is, str,
857 [d, &str](typename std::basic_istream<_tChar, _tTraits>::int_type c,
858 std::basic_streambuf<_tChar, _tTraits>& sb) -> bool{
859 if(_tTraits::eq_int_type(c, d))
860 {
861 sb.sbumpc();
862 // NOTE: If not appended here, this function template shall be
863 // equivalent with %std::getline.
864 str.append(1, d);
865 return true;
866 }
867 return {};
868 });
869 }
870 template<typename _tChar, class _tTraits, class _tAlloc>
871 inline std::basic_istream<_tChar, _tTraits>&
872 extract_line(std::basic_istream<_tChar, _tTraits>& is,
873 std::basic_string<_tChar, _tTraits, _tAlloc>& str)
874 {
875 return ystdex::extract_line(is, str, is.widen('\n'));
876 }
877
883 template<typename _tChar, class _tTraits, class _tAlloc>
884 std::basic_istream<_tChar, _tTraits>&
885 extract_line_cr(std::basic_istream<_tChar, _tTraits>& is,
886 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _tChar delim_cr = '\r',
887 _tChar delim = '\n')
888 {
889 const auto cr(_tTraits::to_int_type(delim_cr));
890 const auto d(_tTraits::to_int_type(delim));
891
892 return ystdex::extract(is, str,
893 [cr, d, &str](typename std::basic_istream<_tChar, _tTraits>::int_type c,
894 std::basic_streambuf<_tChar, _tTraits>& sb) -> bool{
895 if(_tTraits::eq_int_type(c, d))
896 str.append(1, d);
897 else if(_tTraits::eq_int_type(c, cr)
898 && _tTraits::eq_int_type(sb.sgetc(), d))
899 {
900 sb.sbumpc();
901 str.append(1, cr);
902 str.append(1, d);
903 }
904 else
905 return {};
906 sb.sbumpc();
907 return true;
908 });
909 }
911
912
913
919 template<typename _tChar, class _tString>
920 std::basic_ostream<_tChar, typename _tString::traits_type>&
921 write(std::basic_ostream<_tChar, typename _tString::traits_type>& os,
922 const _tString& str, typename _tString::size_type pos = 0,
923 typename _tString::size_type n = _tString::npos)
924 {
925 const auto len(str.length());
926
927 if(pos < len)
928 os.write(&str[pos], std::streamsize(std::min(n, len - pos)));
929 return os;
930 }
932 template<typename _tChar, class _tTraits, size_t _vN>
933 std::basic_ostream<_tChar, _tTraits>&
934 write(std::basic_ostream<_tChar, _tTraits>& os, const _tChar(&s)[_vN])
935 {
936 return os.write(std::addressof(s[0]), std::streamsize(size(s)));
937 }
938
943 template<typename _tChar, class _tTraits, size_t _vN>
944 std::basic_ostream<_tChar, _tTraits>&
945 write_literal(std::basic_ostream<_tChar, _tTraits>& os, const _tChar(&s)[_vN])
946 {
947 static_assert(0 < _vN, "Empty string literal found.");
948
949 return
950 os.write(std::addressof(s[0]), std::streamsize(size(s) - 1));
951 }
953
954
960
962 inline std::string
963 to_string(unsigned char val)
964 {
965 return std::to_string(unsigned(val));
966 }
967 inline std::string
968 to_string(unsigned short val)
969 {
970 return std::to_string(unsigned(val));
971 }
973 template<typename _type>
974 inline yimpl(enable_if_t)<is_enum<_type>::value, std::string>
975 to_string(_type val)
976 {
977 using std::to_string;
978 using ystdex::to_string;
979
980 return to_string(ystdex::underlying(val));
981 }
983 template<typename _type, class _tStream = std::ostringstream>
984 yimpl(enable_if_t)<is_class<_type>::value,
985 decltype(std::declval<_tStream&>().str())>
986 to_string(const _type& x)
987 {
988 _tStream oss;
989
990 oss << x;
991 return oss.str();
992 }
994
996
997 inline std::wstring
998 to_wstring(unsigned char val)
999 {
1000 return std::to_wstring(unsigned(val));
1001 }
1002 inline std::wstring
1003 to_wstring(unsigned short val)
1004 {
1005 return std::to_wstring(unsigned(val));
1006 }
1008 template<typename _type>
1009 inline yimpl(enable_if_t)<is_enum<_type>::value, std::wstring>
1010 to_wstring(_type val)
1011 {
1012 using std::to_wstring;
1013 using ystdex::to_wstring;
1014
1015 return to_wstring(ystdex::underlying(val));
1016 }
1017 template<typename _type, class _tStream = std::wostringstream>
1018 yimpl(enable_if_t)<is_class<_type>::value,
1019 decltype(std::declval<_tStream&>().str())>
1020 to_wstring(const _type& x)
1021 {
1022 _tStream oss;
1023
1024 oss << x;
1025 return oss.str();
1026 }
1028
1029
1030
1032 namespace details
1033 {
1034
1035 template<typename _tString, typename _type>
1036 struct ston_dispatcher;
1037
1038 #define YB_Impl_String_ston_begin(_tString, _type, _n, ...) \
1039 template<> \
1040 struct ston_dispatcher<_tString, _type> \
1041 { \
1042 static _type \
1043 cast(const _tString& str, __VA_ARGS__) \
1044 { \
1045 return _n(str
1046 #define YB_Impl_String_ston_end \
1047 ); \
1048 } \
1049 };
1050
1051 #define YB_Impl_String_ston_i(_tString, _type, _n) \
1052 YB_Impl_String_ston_begin(_tString, _type, _n, size_t* idx = {}, \
1053 int base = 10), idx, base \
1054 YB_Impl_String_ston_end
1055 #define YB_Impl_String_ston_i_std(_type, _n) \
1056 YB_Impl_String_ston_i(std::string, _type, std::_n)
1057 YB_Impl_String_ston_i_std(int, stoi)
1058 YB_Impl_String_ston_i_std(long, stol)
1059 YB_Impl_String_ston_i_std(unsigned long, stoul)
1060 YB_Impl_String_ston_i_std(long long, stoll)
1061 YB_Impl_String_ston_i_std(unsigned long long, stoull)
1062 #undef YB_Impl_String_ston_i_std
1063 #undef YB_Impl_String_ston_i
1064
1065 #define YB_Impl_String_ston_f(_tString, _type, _n) \
1066 YB_Impl_String_ston_begin(_tString, _type, _n, size_t* idx = {}), idx \
1067 YB_Impl_String_ston_end
1068 #define YB_Impl_String_ston_f_std(_type, _n) \
1069 YB_Impl_String_ston_f(std::string, _type, std::_n)
1070 # ifndef __BIONIC__
1071 YB_Impl_String_ston_f_std(float, stof)
1072 YB_Impl_String_ston_f_std(double, stod)
1073 YB_Impl_String_ston_f_std(long double, stold)
1074 # endif
1075 #undef YB_Impl_String_ston_f_std
1076 #undef YB_Impl_String_ston_f
1077
1078 #undef YB_Impl_String_ston_end
1079 #undef YB_Impl_String_ston_begin
1080
1081 } // namespace details;
1082
1089 template<typename _type, typename _tString, typename... _tParams>
1090 inline _type
1091 ston(const _tString& str, _tParams&&... args)
1092 {
1093 return details::ston_dispatcher<decay_t<_tString>, _type>::cast(str,
1094 yforward(args)...);
1095 }
1096
1097
1109 template<typename _tChar, class _tString = std::basic_string<_tChar>>
1110 YB_NONNULL(1) _tString
1111 vsfmt(const _tChar* fmt, std::va_list args)
1112 {
1113 std::va_list ap;
1114
1115 va_copy(ap, args);
1116
1117 const auto l(ystdex::vfmtlen(fmt, ap));
1118
1119 va_end(ap);
1120 if(l == size_t(-1))
1121 throw std::runtime_error("Failed to write formatted string.");
1122
1123 _tString str(l, _tChar());
1124
1125 if(l != 0)
1126 {
1127 yassume(str.length() > 0 && str[0] == _tChar());
1128 std::vsprintf(&str[0], fmt, args);
1129 }
1130 return str;
1131 }
1132
1138 template<typename _tChar>
1139 YB_NONNULL(1) auto
1140 sfmt(const _tChar* fmt, ...)
1141 -> decltype(vsfmt(fmt, std::declval<std::va_list>()))
1142 {
1143 std::va_list args;
1144
1145 va_start(args, fmt);
1146 try
1147 {
1148 auto str(vsfmt(fmt, args));
1149
1150 va_end(args);
1151 return str;
1152 }
1153 catch(...)
1154 {
1155 va_end(args);
1156 throw;
1157 }
1158 }
1160
1166 template YB_ATTR_gnu_printf(1, 2) YB_NONNULL(1) std::string
1167 sfmt<char>(const char*, ...);
1168
1169
1175 template<typename _type, typename _tString, typename _func>
1176 bool
1177 filter_prefix(const _tString& str, const _type& prefix, _func f)
1178 {
1179 if(ystdex::begins_with(str, prefix))
1180 {
1181 auto&& sub(str.substr(string_length(prefix)));
1182
1183 if(!sub.empty())
1184 f(std::move(sub));
1185 return true;
1186 }
1187 return {};
1188 }
1189
1195 template<typename _type, typename _tString>
1196 _tString
1197 cond_prefix(const _tString& str, const _type& prefix, _tString&& val = {})
1198 {
1199 ystdex::filter_prefix(str, prefix, [&](_tString&& s)
1200 ynoexcept(is_nothrow_move_assignable<decay_t<_tString>>::value){
1201 val = std::move(s);
1202 });
1203 return std::move(val);
1204 }
1205
1206 } // namespace ystdex;
1207
1208 #endif
1209
ystdex::string_traits::size_type
typename std::allocator_traits< allocator_type >::size_type size_type
Definition: string.hpp:63
yassume
#define yassume(_expr)
假定：环境语义。
Definition: cassert.h:99
YSLib::Drawing::x
The boundary is out of the const Rect SDst SPos x
Definition: YDraw.h:127
cstring.h
ISO C 标准字符串扩展。
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1140
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:740
platform::containers::string
basic_string< char > string
Definition: Container.h:101
ystdex::extract_line_cr
std::basic_istream< _tChar, _tTraits > & extract_line_cr(std::basic_istream< _tChar, _tTraits > &is, std::basic_string< _tChar, _tTraits, _tAlloc > &str, _tChar delim_cr= '\r', _tChar delim= '\n')
同 ystdex::extract_line ，但允许分隔符包含附加的前缀字符。
Definition: string.hpp:885
yconstraint
#define yconstraint(_expr)
约束：接口语义。
Definition: cassert.h:82
cstdio.h
ystdex::cpp2014::enable_if_t
typename enable_if< _bCond, _type >::type enable_if_t
Definition: type_traits.hpp:350
ystdex::details::str_algos< 1 >::erase_right
static auto erase_right(_tString &s, _tSize n) -> decltype(s.erase(n+1))
Definition: string.hpp:156
ystdex::rethrow_badstate
void rethrow_badstate(std::basic_ios< _tChar, _tTraits > &ios, std::ios_base::iostate state=std::ios_base::badbit)
设置流状态并重新抛出当前异常。
Definition: ios.hpp:64
ystdex::trim
_tString && trim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀与后缀字符。
Definition: string.hpp:649
ystdex::underlying
underlying_type_t< _type > underlying(_type val)
取枚举值的底层整数。
Definition: utility.hpp:120
ystdex::erase_left
enable_if_t< is_class< decay_t< _tString > >::value, _tString && > erase_left(_tString &&str, typename string_traits< _tString >::const_pointer t=&to_array< typename string_traits< _tString >::value_type >(" \f\n\r\t\v")[0])
Definition: string.hpp:533
ystdex::begins_with
bool begins_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一个参数指定的串是否以第二个参数起始。
Definition: string.hpp:343
ystdex::erase_right
enable_if_t< is_class< decay_t< _tString > >::value, _tString && > erase_right(typename string_traits< _tString >::size_type pos, _tString &&str)
删除字符串中指定的连续字符右侧的字符串。
Definition: string.hpp:545
ystdex::string_traits::value_type
remove_rcv_t< decltype(std::declval< string_type >()[0])> value_type
Definition: string.hpp:58
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
ystdex::string_traits::difference_type
typename std::allocator_traits< allocator_type >::difference_type difference_type
Definition: string.hpp:65
ystdex::get_quote_mark_nonstrict
string_traits< _tString >::value_type get_quote_mark_nonstrict(const _tString &str)
取相同的前缀和后缀元素。
Definition: string.hpp:726
ystdex::details::ston_dispatcher
Definition: string.hpp:1036
ystdex::write
std::basic_ostream< _tChar, typename _tString::traits_type > & write(std::basic_ostream< _tChar, typename _tString::traits_type > &os, const _tString &str, typename _tString::size_type pos=0, typename _tString::size_type n=_tString::npos)
非格式输出。
Definition: string.hpp:921
ystdex::is_equal
相等关系仿函数。
Definition: functor.hpp:185
ystdex::string_end
auto string_end(_tRange &c) -> decltype(c.end())
Definition: string.hpp:264
ystdex::cpp2014::remove_reference_t
typename remove_reference< _type >::type remove_reference_t
Definition: type_traits.hpp:304
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:760
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:139
ystdex::normalize
auto normalize(_tString &str) -> decltype(str.resize(ystdex::ntctslen(str.c_str())))
NTCTS 正规化：保留空字符之前的字符。
Definition: string.hpp:412
CHRLib::c
c
Definition: CharacterProcessing.h:81
ystdex::to_string
enable_if_t< is_class< _type >::value, decltype(std::declval< _tStream & >).str())> to_string(const _type &x)
Definition: string.hpp:986
ystdex::string_traits::initializer
std::initializer_list< value_type > initializer
Definition: string.hpp:71
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:256
ystdex::cpp2014::index_sequence
integer_sequence< size_t, _vSeq... > index_sequence
Definition: integer_sequence.hpp:63
ystdex::string_traits::pointer
value_type * pointer
Definition: string.hpp:69
ystdex::filter_prefix
bool filter_prefix(const _tString &str, const _type &prefix, _func f)
过滤前缀：存在前缀时处理移除前缀后的子串。
Definition: string.hpp:1177
ystdex::enable_for_string_class_t
enable_if_t< is_string_class< decay_t< _tParam >>::value, _type > enable_for_string_class_t
选择字符串类类型的特定重载避免和其它非字符串类型冲突。
Definition: string.hpp:219
container.hpp
通用容器操作。
ystdex::alph
_tString alph(_tString &str)
取字母表：有序的字符串的不重复序列。
Definition: string.hpp:470
ystdex::restrict_length
_tString && restrict_length(_tString &&str, const typename string_traits< _tString >::size_type n)
限制长度不超过指定参数。
Definition: string.hpp:455
ystdex::rtrim
_tString && rtrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续后缀字符。
Definition: string.hpp:618
std
Definition: memory.hpp:1100
ystdex::_t
typename _type::type _t
嵌套类型别名。
Definition: type_traits.hpp:96
ystdex::ntctsncpy
enable_if_irreplaceable_char_t< _tChar, _tChar * > ntctsncpy(_tChar *s1, const _tChar *s2, size_t n)
复制不超过指定长度的 NTCTS 。
Definition: cstring.h:315
ios.hpp
ISO C++ 标准库输入/输出流基类扩展。
ystdex::details::ends_with_iter_dispatch
bool ends_with_iter_dispatch(_tFwd1 b, _tFwd1 e, _tFwd2 bt, _tFwd2 et, _fPred comp, std::bidirectional_iterator_tag)
Definition: string.hpp:95
ystdex::size
auto size(const _tRange &c) -> decltype(c.size())
类容器访问。
Definition: range.hpp:233
ystdex::details::str_algos< 1 >::erase_left
static auto erase_left(_tString &s, _tSize n) -> decltype(s.erase(0, n))
Definition: string.hpp:146
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
ystdex
特性测试宏。
Definition: ydef.h:796
ystdex::cpp2014::decay_t
typename decay< _type >::type decay_t
Definition: type_traits.hpp:347
YSLib::Text::str
const char const char * str
Definition: TextFile.h:77
ystdex::sort_unique
_tRandom sort_unique(_tRandom first, _tRandom last)
排序指定序列范围，保留不重复元素的区间。
Definition: algorithm.hpp:506
ystdex::ltrim
_tString && ltrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀字符。
Definition: string.hpp:587
memory.hpp
存储和智能指针特性。
ystdex::details::str_algos< 0 >::erase_left
static auto erase_left(_tString &s, _tSize n) -> decltype(s.remove_prefix(n), s)
Definition: string.hpp:120
ystdex::string_begin
auto string_begin(_tRange &c) -> decltype(c.begin())
Definition: string.hpp:233
string.h
标准库实现 修正。
YSLib::Drawing::r
The boundary is out of the const Graphics const Rect const Point const Point Color c const Rect const Rect & r
Definition: YDraw.h:174
YB_Impl_String_ston_f_std
#define YB_Impl_String_ston_f_std(_type, _n)
Definition: string.hpp:1068
ystdex::cond_prefix
_tString cond_prefix(const _tString &str, const _type &prefix, _tString &&val={})
选择性过滤前缀。
Definition: string.hpp:1197
ystdex::get_mid
_tString get_mid(const _tString &str, typename _tString::size_type l=1)
取删除前缀和后缀的子字符串。
Definition: string.hpp:769
ystdex::string_traits::const_pointer
const value_type * const_pointer
Definition: string.hpp:70
ystdex::vsfmt
_tString vsfmt(const _tChar *fmt, std::va_list args)
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1111
YSLib::i
return i
Definition: YCoreUtilities.h:176
ystdex::remove_rcv_t
_t< remove_rcv< _type >> remove_rcv_t
Definition: type_op.hpp:241
ystdex::is_string_like
判断指定类型是否为类字符串类型。
Definition: string.hpp:198
ystdex::string_traits
字符串特征。
Definition: string.hpp:55
ystdex::exists_substr
bool exists_substr(const _tString &str, const _type &sub)
判断是否存在子串。
Definition: string.hpp:388
ystdex::write_literal
std::basic_ostream< _tChar, _tTraits > & write_literal(std::basic_ostream< _tChar, _tTraits > &os, const _tChar(&s)[_vN])
Definition: string.hpp:945
ystdex::string_traits::string_type
remove_rcv_t< _tString > string_type
Definition: string.hpp:57
ynoexcept
#define ynoexcept(...)
YSLib 无异常抛出保证：指定特定的异常规范。
Definition: ydef.h:720
ystdex::find_prefix
_tString find_prefix(const _tString &str, _tParams &&...args)
取前缀子字符串。
Definition: string.hpp:683
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:654
ystdex::string_traits::traits_type
typename std::char_traits< value_type > traits_type
Definition: string.hpp:59
ystdex::details::str_algos< 0 >::erase_right
static auto erase_right(_tString &s, _tSize n) -> decltype(s.remove_suffix(n), s)
Definition: string.hpp:131
ystdex::string_traits::reference
value_type & reference
Definition: string.hpp:66
ystdex::is_string_class
判断指定类型是否为字符串类类型。
Definition: string.hpp:206
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:969
array.hpp
数组操作。
YB_Impl_String_ston_i_std
#define YB_Impl_String_ston_i_std(_type, _n)
Definition: string.hpp:1055
ystdex::min
const _type & min(const _type &a, const _type &b, _fComp comp=less< _type >())
取较小的元素。
Definition: algorithm.hpp:521
ystdex::to_wstring
std::wstring to_wstring(unsigned char val)
Definition: string.hpp:998
ystdex::ends_with
bool ends_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一个参数指定的串是否以第二个参数结束。
Definition: string.hpp:362
ystdex::extract_line
std::basic_istream< _tChar, _tTraits > & extract_line(std::basic_istream< _tChar, _tTraits > &is, std::basic_string< _tChar, _tTraits, _tAlloc > &str, _tChar delim)
Definition: string.hpp:851
ystdex::concat
void concat(_tCon &con, _tIn first, _tIn last)
插入元素到容器末尾。
Definition: container.hpp:435
ystdex::cpp2011::begin
_type * begin(_type(&&array)[_vN])
Definition: range.hpp:46
YSLib::IO::f
const string &path const String &path _func f
Definition: YSLib/Service/FileSystem.h:430
ystdex::details::str_algo
Definition: string.hpp:165
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
ystdex::erase_left
enable_if_t< is_class< decay_t< _tString > >::value, _tString && > erase_left(typename string_traits< _tString >::size_type pos, _tString &&str)
删除字符串中指定的连续字符左侧的字符串。
Definition: string.hpp:510
ystdex::vfmtlen
size_t vfmtlen(const char *, std::va_list)
计算指定格式字符串输出的占用的字节数。
Definition: cstdio.cpp:39
ystdex::details::str_algos
Definition: string.hpp:111
ystdex::and_
逻辑操作元函数。
Definition: type_traits.hpp:394
ystdex::quote
_tString quote(const _tString &str, typename string_traits< _tString >::value_type c=typename string_traits< _tString >::value_type('"'))
取添加前缀和后缀的字符串。
Definition: string.hpp:741
ystdex::erase_right
enable_if_t< is_class< decay_t< _tString > >::value, _tString && > erase_right(_tString &&str, typename string_traits< _tString >::const_pointer t=&to_array< typename string_traits< _tString >::value_type >(" \f\n\r\t\v")[0])
Definition: string.hpp:571
ystdex::string_length
size_t string_length(const _type *str)
计算字符串长度。
Definition: string.hpp:309
ystdex::extract
std::basic_istream< _tChar, _tTraits > & extract(std::basic_istream< _tChar, _tTraits > &is, std::basic_string< _tChar, _tTraits, _tAlloc > &str, _func f)
从输入流中取字符串。
Definition: string.hpp:795
ystdex::string_traits::const_reference
const value_type & const_reference
Definition: string.hpp:67
ystdex::ston
_type ston(const _tString &str, _tParams &&...args)
转换表示数的字符串。
Definition: string.hpp:1091
ystdex::to_array
std::array< _type, _vN > to_array(const _tSrc &src)
转换指定参数为 std::array 对象。
Definition: array.hpp:87
ystdex::details::is_string_like
Definition: string.hpp:82
ystdex::find_suffix
_tString find_suffix(const _tString &str, _tParams &&...args)
取后缀子字符串。
Definition: string.hpp:700
ystdex::ntctslen
size_t ntctslen(const _tChar *s)
计算简单 NTCTS 长度。
Definition: cstring.h:456
ystdex::cpp2011::end
_type * end(_type(&&array)[_vN])
Definition: range.hpp:54
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
YB_ATTR_gnu_printf
#define YB_ATTR_gnu_printf(...)
GNU 风格 printf 属性。
Definition: ydef.h:375
ystdex::to_wstring
enable_if_t< is_class< _type >::value, decltype(std::declval< _tStream & >).str())> to_wstring(const _type &x)
Definition: string.hpp:1020
ystdex::cpp2014::equal
bool equal(_tIn1 first1, _tIn1 last1, _tIn2 first2, _tIn2 last2, _fBiPred binary_pred)
Definition: algorithm.hpp:175
platform::n
size_t n
Definition: YCLib/FileSystem.cpp:321
ystdex::string_traits::allocator_type
_t< nested_allocator< string_type >> allocator_type
Definition: string.hpp:62