YSTest: string.hpp 源文件

YSTest PreAlpha_b800_20170810 The YSLib Test Project

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

- 文件列表
- 文件成员

string.hpp
浏览该文件的文档.
1 /*
2 © 2012-2017 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 remove_rcv_t, false_, is_object, decay_t,
32 // std::declval, true_, 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, size, sort_unique, 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_
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_
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()), s.remove_prefix(n), s;
124 }
125
127 template<class _tString,
128 typename _tSize = typename string_traits<_tString>::size_type>
129 static yconstfn auto
130 erase_right(_tString& s, _tSize n) ynothrowv
131 -> yimpl(decltype(s.remove_suffix(n), s))
132 {
133 return yconstraint(n < s.size()), trim_right_pos(s, n);
134 }
135
137 template<class _tString,
138 typename _tSize = typename string_traits<_tString>::size_type>
139 static yconstfn auto
140 trim_left_pos(_tString& s, _tSize n) ynothrowv
141 -> yimpl(decltype(s.remove_prefix(n), s))
142 {
143 return yconstraint(n < s.size() || n == _tSize(-1)),
144 erase_left(s, n != _tSize(-1) ? n : _tSize(s.size())), s;
145 }
146
148 template<class _tString,
149 typename _tSize = typename string_traits<_tString>::size_type>
150 static yconstfn auto
151 trim_right_pos(_tString& s, _tSize n) ynothrowv
152 -> yimpl(decltype(s.remove_suffix(n), s))
153 {
154 return yconstraint(n < s.size() || n == _tSize(-1)),
155 s.remove_suffix(s.size() - n - 1), s;
156 }
157 };
158
159 template<>
160 struct str_algos<1>
161 {
163 template<class _tString,
164 typename _tSize = typename string_traits<_tString>::size_type>
165 static yconstfn auto
166 erase_left(_tString& s, _tSize n) ynothrowv
167 -> yimpl(decltype(s.erase(0, n)))
168 {
169 return yconstraint(n <= s.size()), s.erase(0, n);
170 }
171
173 template<class _tString,
174 typename _tSize = typename string_traits<_tString>::size_type>
175 static yconstfn auto
176 erase_right(_tString& s, _tSize n) ynothrowv
177 -> yimpl(decltype(s.erase(n + 1)))
178 {
179 return yconstraint(n < s.size()), s.erase(n + 1);
180 }
181
183 template<class _tString,
184 typename _tSize = typename string_traits<_tString>::size_type>
185 static yconstfn auto
186 trim_left_pos(_tString& s, _tSize n) ynothrowv
187 -> yimpl(decltype(s.erase(0, n)))
188 {
189 return yconstraint(n < s.size() || n == _tSize(-1)), s.erase(0, n);
190 }
191
193 template<class _tString,
194 typename _tSize = typename string_traits<_tString>::size_type>
195 static yconstfn auto
196 trim_right_pos(_tString& s, _tSize n) ynothrowv
197 -> yimpl(decltype(s.erase(n + 1)))
198 {
199 return yconstraint(n < s.size() || n == _tSize(-1)), s.erase(n + 1);
200 }
201 };
202
203
204 template<yimpl(typename = make_index_sequence<2>)>
205 struct str_algo;
206
207 template<>
208 struct str_algo<index_sequence<>>
209 {
210 void
211 erase_left() = delete;
212
213 void
214 erase_right() = delete;
215
217 void
218 trim_left_pos() = delete;
219
221 void
222 trim_right_pos() = delete;
223 };
224
225 template<size_t _vIdx, size_t... _vSeq>
226 struct str_algo<index_sequence<_vIdx, _vSeq...>>
227 : str_algos<_vIdx>, str_algo<index_sequence<_vSeq...>>
228 {
229 using str_algos<_vIdx>::erase_left;
230 using str_algo<index_sequence<_vSeq...>>::erase_left;
231 using str_algos<_vIdx>::erase_right;
232 using str_algo<index_sequence<_vSeq...>>::erase_right;
234
235 using str_algos<_vIdx>::trim_left_pos;
236 using str_algo<index_sequence<_vSeq...>>::trim_left_pos;
237 using str_algos<_vIdx>::trim_right_pos;
238 using str_algo<index_sequence<_vSeq...>>::trim_right_pos;
240 };
242
243 } // unnamed namespace;
244
245
247
248
252 template<typename _type>
253 struct is_string_like : details::is_string_like<_type>
254 {};
255
260 template<typename _type>
261 struct is_string_class : and_<is_class<_type>, is_string_like<_type>>
262 {};
264
265
272 template<typename _tParam, typename _type = void>
273 using enable_for_string_class_t
274 = enable_if_t<is_string_class<decay_t<_tParam>>::value, _type>;
275
276
286 template<class _tRange>
287 yconstfn auto
288 string_begin(_tRange& c) -> decltype(c.begin())
289 {
290 return begin(c);
291 }
292 template<class _tRange>
293 yconstfn auto
294 string_begin(const _tRange& c) -> decltype(c.begin())
295 {
296 return begin(c);
297 }
299
300 template<typename _tChar>
301 yconstfn _tChar*
302 string_begin(_tChar* str) ynothrow
303 {
304 return yconstraint(str), str;
305 }
306 #if __cplusplus <= 201402L
307 template<typename _tElem>
309 yconstfn auto
310 string_begin(std::initializer_list<_tElem> il) -> decltype(il.begin())
311 {
312 return il.begin();
313 }
314 #endif
315
316
317 template<class _tRange>
318 yconstfn auto
319 string_end(_tRange& c) -> decltype(c.end())
320 {
321 return end(c);
322 }
323 template<class _tRange>
324 yconstfn auto
325 string_end(const _tRange& c) -> decltype(c.end())
326 {
327 return end(c);
328 }
330
331 template<typename _tChar>
332 yconstfn _tChar*
333 string_end(_tChar* str) ynothrow
334 {
335 return str + ystdex::ntctslen(str);
336 }
337 #if __cplusplus <= 201402L
338 template<typename _tElem>
340 yconstfn auto
341 string_end(std::initializer_list<_tElem> il) -> decltype(il.end())
342 {
343 return il.end();
344 }
345 #endif
346
347
348
349
362 template<typename _type>
363 inline size_t
364 string_length(const _type* str) ynothrow
365 {
366 return std::char_traits<_type>::length(str);
367 }
368 template<typename _type>
369 yconstfn auto
370 string_length(const _type& str) -> decltype(size(str))
371 {
372 return size(str);
373 }
374 #if __cplusplus <= 201402L
375 template<typename _tElem>
377 yconstfn size_t
378 string_length(std::initializer_list<_tElem> il)
379 {
380 return il.size();
381 }
382 #endif
383
384
385
393
395 template<typename _tRange1, typename _tRange2, typename _fPred>
397 bool
398 begins_with(const _tRange1& input, const _tRange2& test, _fPred comp)
399 {
400 return ystdex::string_length(test) <= ystdex::string_length(input)
401 && std::equal(string_begin(test), string_end(test),
402 string_begin(input), comp);
403 }
405 template<typename _tRange1, typename _tRange2>
406 inline bool
407 begins_with(const _tRange1& input, const _tRange2& test)
408 {
409 return ystdex::begins_with(input, test, is_equal());
410 }
412
414
415 template<typename _tRange1, typename _tRange2, typename _fPred>
416 inline bool
417 ends_with(const _tRange1& input, const _tRange2& test, _fPred comp)
418 {
419 // NOTE: See $2014-07 @ %Documentation::Workflow::Annual2014.
420 return details::ends_with_iter_dispatch(string_begin(input),
421 string_end(input), string_begin(test), string_end(test), comp, typename
422 std::iterator_traits<remove_reference_t<decltype(string_begin(input))>>
423 ::iterator_category());
424 }
425 template<typename _tRange1, typename _tRange2>
426 inline bool
427 ends_with(const _tRange1& input, const _tRange2& test)
428 {
429 return ystdex::ends_with(input, test, is_equal());
430 }
432
433
434
441 template<class _tString, typename _type>
442 inline bool
443 exists_substr(const _tString& str, const _type& sub)
444 {
445 return str.find(sub) != _tString::npos;
446 }
447 template<class _tString, typename _type>
448 inline bool
449 exists_substr(const _tString& str, const typename _tString::value_type* p_sub)
450 {
451 yconstraint(p_sub);
452
453 return str.find(p_sub) != _tString::npos;
454 }
456
457
459
460
465 template<class _tString>
466 auto
467 normalize(_tString& str) -> decltype(str.resize(ystdex::ntctslen(str.c_str())))
468 {
469 return str.resize(ystdex::ntctslen(str.c_str()));
470 }
471
479 template<class _tString,
481 yimpl(typename = ystdex::enable_for_string_class_t<_tString>)>
482 inline _tString&&
483 ntctsncpy(_tString&& str, const typename string_traits<_tString>::const_pointer
484 s, const typename string_traits<_tString>::size_type n)
485 {
486 yconstraint(s);
487 return static_cast<_tString&&>(str = decay_t<_tString>(s, n));
488 }
489 template<class _tString,
490 yimpl(typename = ystdex::enable_for_string_class_t<_tString>)>
491 inline _tString&&
492 ntctsncpy(_tString&& str, _tString&& s,
493 const typename string_traits<_tString>::size_type n)
494 {
495 auto sub(yforward(s));
496
497 sub.resize(n);
498 return static_cast<_tString&&>(str = std::move(sub));
499 }
501
502
503
508 template<class _tString>
509 inline _tString&&
510 restrict_length(_tString&& str,
511 const typename string_traits<_tString>::size_type n)
512 {
513 if(n < str.length())
514 str.resize(n);
515 return static_cast<_tString&&>(str);
516 }
517
518
523 template<class _tString>
524 _tString
525 alph(_tString& str)
526 {
527 _tString res(str);
528
529 ystdex::sort_unique(res);
530 return res;
531 }
532
541 template<class _tString>
542 void
543 concat(_tString& str, size_t n)
544 {
545 yconstraint(n != 0);
546 if(1 < n)
547 {
548 const auto len(str.length());
549
550 ystdex::concat(str, n / 2);
551 str.append(str.data(), str.length());
552 if(n % 2 != 0)
553 str.append(str.data(), len);
554 }
555 }
556
558
559
561
563 template<class _tString>
564 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
565 erase_left(typename string_traits<_tString>::size_type pos, _tString&& str)
566 {
567 return static_cast<_tString&&>(pos != decay_t<_tString>::npos
568 ? details::str_algo<>::erase_left(str, pos) : str);
569 }
570 template<class _tString>
571 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
572 erase_left(_tString&& str, typename string_traits<_tString>::value_type c)
573 {
574 return
575 static_cast<_tString&&>(ystdex::erase_left(str.find_first_of(c), str));
576 }
577 template<class _tString>
578 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
579 erase_left(_tString&& str, const remove_reference_t<_tString>& t)
580 {
581 return
582 static_cast<_tString&&>(ystdex::erase_left(str.find_first_of(t), str));
583 }
588 template<class _tString>
589 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
590 erase_left(_tString&& str, typename string_traits<_tString>::const_pointer t
591 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
592 {
593 yconstraint(t);
594 return
595 static_cast<_tString&&>(ystdex::erase_left(str.find_first_of(t), str));
596 }
598
600
601 template<class _tString>
602 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
603 erase_right(typename string_traits<_tString>::size_type pos, _tString&& str)
604 {
605 return static_cast<_tString&&>(pos != decay_t<_tString>::npos
606 ? details::str_algo<>::erase_right(str, pos) : str);
607 }
608 template<class _tString>
609 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
610 erase_right(_tString&& str, typename string_traits<_tString>::value_type c)
611 {
612 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(c),
613 str));
614 }
616 template<class _tString>
617 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
618 erase_right(_tString&& str, const remove_reference_t<_tString>& t)
619 {
620 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(t),
621 str));
622 }
627 template<class _tString>
628 inline yimpl(enable_if_t)<is_class<decay_t<_tString>>::value, _tString&&>
629 erase_right(_tString&& str, typename string_traits<_tString>::const_pointer t
630 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
631 {
632 yconstraint(t);
633 return static_cast<_tString&&>(ystdex::erase_right(str.find_last_of(t),
634 str));
635 }
637
638
640
641
643 template<class _tString>
644 yconstfn _tString&&
645 ltrim(_tString&& str, typename string_traits<_tString>::value_type c)
646 {
647 return static_cast<_tString&&>(
648 details::str_algo<>::trim_left_pos(str, str.find_first_not_of(c)));
649 }
651 template<class _tString>
652 inline _tString&&
653 ltrim(_tString&& str, const _tString& t)
654 {
655 return static_cast<_tString&&>(
656 details::str_algo<>::trim_left_pos(str, str.find_first_not_of(t)));
657 }
662 template<class _tString>
663 yconstfn _tString&&
664 ltrim(_tString&& str, typename string_traits<_tString>::const_pointer t
665 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
666 {
667 return yconstraint(t), static_cast<_tString&&>(
668 details::str_algo<>::trim_left_pos(str, str.find_first_not_of(t)));
669 }
671
673
674 template<class _tString>
675 yconstfn _tString&&
676 rtrim(_tString&& str, typename string_traits<_tString>::value_type c)
677 {
678 return static_cast<_tString&&>(
679 details::str_algo<>::trim_right_pos(str, str.find_last_not_of(c)));
680 }
682 template<class _tString>
683 yconstfn _tString&&
684 rtrim(_tString&& str, const remove_reference_t<_tString>& t) ynothrowv
685 {
686 return static_cast<_tString&&>(
687 details::str_algo<>::trim_right_pos(str, str.find_last_not_of(t)));
688 }
693 template<class _tString>
694 yconstfn _tString&&
695 rtrim(_tString&& str, typename string_traits<_tString>::const_pointer t
696 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
697 {
698 return yconstraint(t), static_cast<_tString&&>(
699 details::str_algo<>::trim_right_pos(str, str.find_last_not_of(t)));
700 }
702
704
705 template<class _tString>
706 yconstfn _tString&&
707 trim(_tString&& str, typename string_traits<_tString>::value_type c)
708 {
709 return
710 yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), c)), c));
711 }
713 template<class _tString>
714 yconstfn _tString&&
715 trim(_tString&& str, const _tString& t) ynothrowv
716 {
717 return
718 yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), t)), t));
719 }
724 template<class _tString>
725 yconstfn _tString&&
726 trim(_tString&& str, typename string_traits<_tString>::const_pointer t
727 = &to_array<typename string_traits<_tString>::value_type>(" \f\n\r\t\v")[0])
728 {
729 return yconstraint(t),
730 yforward(ystdex::ltrim(yforward(ystdex::rtrim(yforward(str), t)), t));
731 }
733
734
735
736
738
739
741 template<typename _tString, typename... _tParams>
742 inline _tString
743 find_prefix(const _tString& str, _tParams&&... args)
744 {
745 if(!str.empty())
746 {
747 const auto pos(str.find(yforward(args)...));
748
749 if(pos != _tString::npos)
750 return str.substr(0, pos);
751 }
752 return {};
753 }
755
757
758 template<typename _tString, typename... _tParams>
759 inline _tString
760 find_suffix(const _tString& str, _tParams&&... args)
761 {
762 if(!str.empty())
763 {
764 const auto pos(str.rfind(yforward(args)...));
765
766 if(pos != _tString::npos)
767 return str.substr(pos + 1);
768 }
769 return {};
770 }
772
773
784 template<typename _tString>
785 yconstfn typename string_traits<_tString>::value_type
786 get_quote_mark_nonstrict(const _tString& str)
787 {
788 return str.front() == str.back() ? str.front()
789 : typename string_traits<_tString>::value_type();
790 }
792
799 template<typename _tString>
800 inline _tString
801 quote(const _tString& str, typename string_traits<_tString>::value_type c
802 = typename string_traits<_tString>::value_type('"'))
803 {
804 return c + str + c;
805 }
806 template<typename _tString, typename _tString2>
807 inline yimpl(enable_if_t)<!is_convertible<_tString2,
808 typename string_traits<_tString>::value_type>::value ,_tString>
809 quote(const _tString& str, const _tString2& s)
810 {
811 return s + str + s;
812 }
813 template<typename _tString, typename _tPrefix, typename _tSuffix>
814 inline _tString
815 quote(const _tString& str, const _tPrefix& pfx, const _tSuffix& sfx)
816 {
817 return pfx + str + sfx;
818 }
820
827 template<typename _tString>
828 inline _tString
829 get_mid(const _tString& str, typename _tString::size_type l = 1)
830 {
831 yassume(!(str.size() < l * 2));
832 return str.substr(l, str.size() - l * 2);
833 }
834 template<typename _tString>
835 inline _tString
836 get_mid(const _tString& str, typename _tString::size_type l,
837 typename _tString::size_type r)
838 {
839 yassume(!(str.size() < l + r));
840 return str.substr(l, str.size() - l - r);
841 }
843
844
845
846
852 template<typename _tChar, class _tTraits, class _tAlloc, typename _func>
854 std::basic_istream<_tChar, _tTraits>&
855 extract(std::basic_istream<_tChar, _tTraits>& is,
856 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _func f)
857 {
858 std::string::size_type n(0);
859 auto st(std::ios_base::goodbit);
860
861 if(const auto k
862 = typename std::basic_istream<_tChar, _tTraits>::sentry(is, true))
863 {
864 const auto msize(str.max_size());
865 const auto p_buf(is.rdbuf());
866
867 yassume(p_buf);
868 str.erase();
869 try
870 {
871 const auto eof(_tTraits::eof());
872
873 for(auto c(p_buf->sgetc()); ; c = p_buf->snextc())
874 {
875 if(_tTraits::eq_int_type(c, eof))
876 {
877 st |= std::ios_base::eofbit;
878 break;
879 }
880 if(f(c, *p_buf))
881 {
882 ++n;
883 break;
884 }
885 if(!(str.length() < msize))
886 {
887 st |= std::ios_base::failbit;
888 break;
889 }
890 str.append(1, _tTraits::to_char_type(c));
891 ++n;
892 }
893 }
894 catch(...)
895 {
896 // NOTE: See LWG 91.
897 rethrow_badstate(is, std::ios_base::badbit);
898 }
899 }
900 if(n == 0)
901 st |= std::ios_base::failbit;
902 if(st)
903 is.setstate(st);
904 return is;
905 }
906
908
909 template<typename _tChar, class _tTraits, class _tAlloc>
910 std::basic_istream<_tChar, _tTraits>&
911 extract_line(std::basic_istream<_tChar, _tTraits>& is,
912 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _tChar delim)
913 {
914 const auto d(_tTraits::to_int_type(delim));
915
916 return ystdex::extract(is, str,
917 [d, &str](typename std::basic_istream<_tChar, _tTraits>::int_type c,
918 std::basic_streambuf<_tChar, _tTraits>& sb) -> bool{
919 if(_tTraits::eq_int_type(c, d))
920 {
921 sb.sbumpc();
922 // NOTE: If not appended here, this function template shall be
923 // equivalent with %std::getline.
924 str.append(1, d);
925 return true;
926 }
927 return {};
928 });
929 }
930 template<typename _tChar, class _tTraits, class _tAlloc>
931 inline std::basic_istream<_tChar, _tTraits>&
932 extract_line(std::basic_istream<_tChar, _tTraits>& is,
933 std::basic_string<_tChar, _tTraits, _tAlloc>& str)
934 {
935 return ystdex::extract_line(is, str, is.widen('\n'));
936 }
937
943 template<typename _tChar, class _tTraits, class _tAlloc>
944 std::basic_istream<_tChar, _tTraits>&
945 extract_line_cr(std::basic_istream<_tChar, _tTraits>& is,
946 std::basic_string<_tChar, _tTraits, _tAlloc>& str, _tChar delim_cr = '\r',
947 _tChar delim = '\n')
948 {
949 const auto cr(_tTraits::to_int_type(delim_cr));
950 const auto d(_tTraits::to_int_type(delim));
951
952 return ystdex::extract(is, str,
953 [cr, d, &str](typename std::basic_istream<_tChar, _tTraits>::int_type c,
954 std::basic_streambuf<_tChar, _tTraits>& sb) -> bool{
955 if(_tTraits::eq_int_type(c, d))
956 str.append(1, d);
957 else if(_tTraits::eq_int_type(c, cr)
958 && _tTraits::eq_int_type(sb.sgetc(), d))
959 {
960 sb.sbumpc();
961 str.append(1, cr);
962 str.append(1, d);
963 }
964 else
965 return {};
966 sb.sbumpc();
967 return true;
968 });
969 }
971
972
973
979 template<typename _tChar, class _tString>
980 std::basic_ostream<_tChar, typename _tString::traits_type>&
981 write(std::basic_ostream<_tChar, typename _tString::traits_type>& os,
982 const _tString& str, typename _tString::size_type pos = 0,
983 typename _tString::size_type n = _tString::npos)
984 {
985 const auto len(str.length());
986
987 if(pos < len)
988 os.write(&str[pos], std::streamsize(std::min(n, len - pos)));
989 return os;
990 }
992 template<typename _tChar, class _tTraits, size_t _vN>
993 std::basic_ostream<_tChar, _tTraits>&
994 write(std::basic_ostream<_tChar, _tTraits>& os, const _tChar(&s)[_vN])
995 {
996 return os.write(std::addressof(s[0]), std::streamsize(size(s)));
997 }
998
1003 template<typename _tChar, class _tTraits, size_t _vN>
1004 std::basic_ostream<_tChar, _tTraits>&
1005 write_literal(std::basic_ostream<_tChar, _tTraits>& os, const _tChar(&s)[_vN])
1006 {
1007 static_assert(0 < _vN, "Empty string literal found.");
1008
1009 return
1010 os.write(std::addressof(s[0]), std::streamsize(size(s) - 1));
1011 }
1013
1014
1020
1022 inline std::string
1023 to_string(unsigned char val)
1024 {
1025 return std::to_string(unsigned(val));
1026 }
1027 inline std::string
1028 to_string(unsigned short val)
1029 {
1030 return std::to_string(unsigned(val));
1031 }
1033 template<typename _type>
1034 inline yimpl(enable_if_t)<is_enum<_type>::value, std::string>
1035 to_string(_type val)
1036 {
1037 using std::to_string;
1038 using ystdex::to_string;
1039
1040 return to_string(ystdex::underlying(val));
1041 }
1043 template<typename _type, class _tStream = std::ostringstream>
1044 yimpl(enable_if_t)<is_class<_type>::value,
1045 decltype(std::declval<_tStream&>().str())>
1046 to_string(const _type& x)
1047 {
1048 _tStream oss;
1049
1050 oss << x;
1051 return oss.str();
1052 }
1054
1056
1057 inline std::wstring
1058 to_wstring(unsigned char val)
1059 {
1060 return std::to_wstring(unsigned(val));
1061 }
1062 inline std::wstring
1063 to_wstring(unsigned short val)
1064 {
1065 return std::to_wstring(unsigned(val));
1066 }
1068 template<typename _type>
1069 inline yimpl(enable_if_t)<is_enum<_type>::value, std::wstring>
1070 to_wstring(_type val)
1071 {
1072 using std::to_wstring;
1073 using ystdex::to_wstring;
1074
1075 return to_wstring(ystdex::underlying(val));
1076 }
1077 template<typename _type, class _tStream = std::wostringstream>
1078 yimpl(enable_if_t)<is_class<_type>::value,
1079 decltype(std::declval<_tStream&>().str())>
1080 to_wstring(const _type& x)
1081 {
1082 _tStream oss;
1083
1084 oss << x;
1085 return oss.str();
1086 }
1088
1089
1090
1092 namespace details
1093 {
1094
1095 template<typename _tString, typename _type>
1096 struct ston_dispatcher;
1097
1098 #define YB_Impl_String_ston_begin(_tString, _type, _n, ...) \
1099 template<> \
1100 struct ston_dispatcher<_tString, _type> \
1101 { \
1102 static _type \
1103 cast(const _tString& str, __VA_ARGS__) \
1104 { \
1105 return _n(str
1106 #define YB_Impl_String_ston_end \
1107 ); \
1108 } \
1109 };
1110
1111 #define YB_Impl_String_ston_i(_tString, _type, _n) \
1112 YB_Impl_String_ston_begin(_tString, _type, _n, size_t* idx = {}, \
1113 int base = 10), idx, base \
1114 YB_Impl_String_ston_end
1115 #define YB_Impl_String_ston_i_std(_type, _n) \
1116 YB_Impl_String_ston_i(std::string, _type, std::_n)
1117 YB_Impl_String_ston_i_std(int, stoi)
1118 YB_Impl_String_ston_i_std(long, stol)
1119 YB_Impl_String_ston_i_std(unsigned long, stoul)
1120 YB_Impl_String_ston_i_std(long long, stoll)
1121 YB_Impl_String_ston_i_std(unsigned long long, stoull)
1122 #undef YB_Impl_String_ston_i_std
1123 #undef YB_Impl_String_ston_i
1124
1125 #define YB_Impl_String_ston_f(_tString, _type, _n) \
1126 YB_Impl_String_ston_begin(_tString, _type, _n, size_t* idx = {}), idx \
1127 YB_Impl_String_ston_end
1128 #define YB_Impl_String_ston_f_std(_type, _n) \
1129 YB_Impl_String_ston_f(std::string, _type, std::_n)
1130 # ifndef __BIONIC__
1131 YB_Impl_String_ston_f_std(float, stof)
1132 YB_Impl_String_ston_f_std(double, stod)
1133 YB_Impl_String_ston_f_std(long double, stold)
1134 # endif
1135 #undef YB_Impl_String_ston_f_std
1136 #undef YB_Impl_String_ston_f
1137
1138 #undef YB_Impl_String_ston_end
1139 #undef YB_Impl_String_ston_begin
1140
1141 } // namespace details;
1142
1149 template<typename _type, typename _tString, typename... _tParams>
1150 inline _type
1151 ston(const _tString& str, _tParams&&... args)
1152 {
1153 return details::ston_dispatcher<decay_t<_tString>, _type>::cast(str,
1154 yforward(args)...);
1155 }
1156
1157
1169 template<typename _tChar, class _tString = std::basic_string<_tChar>>
1170 YB_NONNULL(1) _tString
1171 vsfmt(const _tChar* fmt, std::va_list args)
1172 {
1173 std::va_list ap;
1174
1175 va_copy(ap, args);
1176
1177 const auto l(ystdex::vfmtlen(fmt, ap));
1178
1179 va_end(ap);
1180 if(l == size_t(-1))
1181 throw std::runtime_error("Failed to write formatted string.");
1182
1183 _tString str(l, _tChar());
1184
1185 if(l != 0)
1186 {
1187 yassume(str.length() > 0 && str[0] == _tChar());
1188 std::vsprintf(&str[0], fmt, args);
1189 }
1190 return str;
1191 }
1192
1198 template<typename _tChar>
1199 YB_NONNULL(1) auto
1200 sfmt(const _tChar* fmt, ...)
1201 -> decltype(vsfmt(fmt, std::declval<std::va_list>()))
1202 {
1203 std::va_list args;
1204
1205 va_start(args, fmt);
1206 try
1207 {
1208 auto str(vsfmt(fmt, args));
1209
1210 va_end(args);
1211 return str;
1212 }
1213 catch(...)
1214 {
1215 va_end(args);
1216 throw;
1217 }
1218 }
1220
1226 template YB_ATTR_gnu_printf(1, 2) YB_NONNULL(1) std::string
1227 sfmt<char>(const char*, ...);
1228
1229
1235 template<typename _type, typename _tString, typename _func>
1236 bool
1237 filter_prefix(const _tString& str, const _type& prefix, _func f)
1238 {
1239 if(ystdex::begins_with(str, prefix))
1240 {
1241 auto&& sub(str.substr(string_length(prefix)));
1242
1243 if(!sub.empty())
1244 f(std::move(sub));
1245 return true;
1246 }
1247 return {};
1248 }
1249
1255 template<typename _type, typename _tString>
1256 _tString
1257 cond_prefix(const _tString& str, const _type& prefix, _tString&& val = {})
1258 {
1259 ystdex::filter_prefix(str, prefix, [&](_tString&& s)
1260 ynoexcept(is_nothrow_move_assignable<decay_t<_tString>>()){
1261 val = std::move(s);
1262 });
1263 return std::move(val);
1264 }
1265
1266 } // namespace ystdex;
1267
1268 #endif
1269
ystdex::details::str_algos< 1 >::erase_left
static auto erase_left(_tString &s, _tSize n) -> decltype(s.erase(0, n))
Definition: string.hpp:166
ystdex::details::str_algos< 0 >::erase_right
static auto erase_right(_tString &s, _tSize n) -> decltype(s.remove_suffix(n), s)
Definition: string.hpp:130
ystdex::details::str_algo
Definition: string.hpp:205
ystdex::get_mid
_tString get_mid(const _tString &str, typename _tString::size_type l=1)
取删除前缀和后缀的子字符串。
Definition: string.hpp:829
ystdex::exists_substr
bool exists_substr(const _tString &str, const _type &sub)
判断是否存在子串。
Definition: string.hpp:443
platform::containers::wstring
basic_string< wchar_t > wstring
Definition: Container.h:108
ystdex::filter_prefix
bool filter_prefix(const _tString &str, const _type &prefix, _func f)
过滤前缀：存在前缀时处理移除前缀后的子串。
Definition: string.hpp:1237
ystdex::true_
bool_< true > true_
Definition: type_traits.hpp:391
ystdex::string_traits::string_type
remove_rcv_t< _tString > string_type
Definition: string.hpp:57
yconstfn
#define yconstfn
指定编译时常量函数。
Definition: ydef.h:680
ystdex::begins_with
bool begins_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一个参数指定的串是否以第二个参数起始。
Definition: string.hpp:398
ystdex::get_quote_mark_nonstrict
string_traits< _tString >::value_type get_quote_mark_nonstrict(const _tString &str)
取相同的前缀和后缀元素。
Definition: string.hpp:786
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:855
ystdex::string_begin
auto string_begin(_tRange &c) -> decltype(c.begin())
Definition: string.hpp:288
ystdex::string_traits::traits_type
typename std::char_traits< value_type > traits_type
Definition: string.hpp:59
ystdex::to_string
std::string to_string(const std::thread::id &)
转换 thread::id 为字符串表示。
ystdex::cpp2014::index_sequence
integer_sequence< size_t, _vSeq... > index_sequence
Definition: integer_sequence.hpp:63
YB_ATTR_gnu_printf
#define YB_ATTR_gnu_printf(...)
GNU 风格 printf 属性。
Definition: ydef.h:398
ystdex::string_traits::const_pointer
const value_type * const_pointer
Definition: string.hpp:70
ystdex::remove_rcv_t
_t< remove_rcv< _type >> remove_rcv_t
Definition: type_op.hpp:267
NPL::x
const TermNode &term ynothrow const TermNode &term ynothrow const TermNode &term ynothrow TermNode &term const TermNode &term ValueNode &node const ValueNode &node const _type & x
Definition: SContext.h:94
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
ystdex::false_
bool_< false > false_
Definition: type_traits.hpp:392
ystdex::ends_with
bool ends_with(const _tRange1 &input, const _tRange2 &test, _fPred comp)
判断第一个参数指定的串是否以第二个参数结束。
Definition: string.hpp:417
CHRLib::f
f(d, s)
ystdex::write_literal
std::basic_ostream< _tChar, _tTraits > & write_literal(std::basic_ostream< _tChar, _tTraits > &os, const _tChar(&s)[_vN])
Definition: string.hpp:1005
yimpl
#define yimpl(...)
实现标签。
Definition: ydef.h:262
ystdex::details::str_algos< 0 >::trim_left_pos
static auto trim_left_pos(_tString &s, _tSize n) -> decltype(s.remove_prefix(n), s)
Definition: string.hpp:140
ystdex::string_traits::size_type
typename std::allocator_traits< allocator_type >::size_type size_type
Definition: string.hpp:63
ystdex::ntctslen
size_t ntctslen(const _tChar *s)
计算简单 NTCTS 长度。
Definition: cstring.h:456
ystdex::cpp2014::enable_if_t
typename enable_if< _bCond, _type >::type enable_if_t
Definition: type_traits.hpp:343
ystdex::is_string_class
判断指定类型是否为字符串类类型。
Definition: string.hpp:261
string.h
标准库实现 修正。
CHRLib::args
_tParams && args
Definition: CharacterProcessing.h:538
platform::containers::string
basic_string< char > string
Definition: Container.h:101
YB_Impl_String_ston_f_std
#define YB_Impl_String_ston_f_std(_type, _n)
Definition: string.hpp:1128
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:274
ystdex::cpp2011::end
_type * end(_type(&&array)[_vN])
Definition: range.hpp:54
ystdex::string_end
auto string_end(_tRange &c) -> decltype(c.end())
Definition: string.hpp:319
ystdex::string_traits
字符串特征。
Definition: string.hpp:55
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:565
ystdex::ston
_type ston(const _tString &str, _tParams &&...args)
转换表示数的字符串。
Definition: string.hpp:1151
ystdex::find_prefix
_tString find_prefix(const _tString &str, _tParams &&...args)
取前缀子字符串。
Definition: string.hpp:743
ystdex::to_wstring
std::wstring to_wstring(unsigned char val)
Definition: string.hpp:1058
ystdex::details::str_algos< 1 >::trim_left_pos
static auto trim_left_pos(_tString &s, _tSize n) -> decltype(s.erase(0, n))
Definition: string.hpp:186
ystdex::string_length
size_t string_length(const _type *str)
计算字符串长度。
Definition: string.hpp:364
ystdex::details::str_algos< 1 >::erase_right
static auto erase_right(_tString &s, _tSize n) -> decltype(s.erase(n+1))
Definition: string.hpp:176
ystdex::quote
_tString quote(const _tString &str, typename string_traits< _tString >::value_type c=typename string_traits< _tString >::value_type('"'))
取添加前缀和后缀的字符串。
Definition: string.hpp:801
ystdex::string_traits::reference
value_type & reference
Definition: string.hpp:66
ystdex::find_suffix
_tString find_suffix(const _tString &str, _tParams &&...args)
取后缀子字符串。
Definition: string.hpp:760
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::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:945
ystdex::cpp2014::equal
bool equal(_tIn1 first1, _tIn1 last1, _tIn2 first2, _tIn2 last2, _fBiPred binary_pred)
Definition: algorithm.hpp:181
ystdex::string_traits::pointer
value_type * pointer
Definition: string.hpp:69
ystdex::cond_prefix
_tString cond_prefix(const _tString &str, const _type &prefix, _tString &&val={})
选择性过滤前缀。
Definition: string.hpp:1257
ystdex::details::str_algos
Definition: string.hpp:111
ynothrow
#define ynothrow
YSLib 无异常抛出保证：若支持 noexcept 关键字， 指定特定的 noexcept 异常规范。
Definition: ydef.h:766
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:911
container.hpp
通用容器操作。
ystdex::cpp2014::decay_t
typename decay< _type >::type decay_t
Definition: type_traits.hpp:340
CHRLib::s
_tDst const _tSrc * s
Definition: CharacterProcessing.h:140
ystdex::sfmt
auto sfmt(const _tChar *fmt,...) -> decltype(vsfmt(fmt, std::declval< std::va_list >()))
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1200
ystdex
特性测试宏。
Definition: ydef.h:822
ystdex::normalize
auto normalize(_tString &str) -> decltype(str.resize(ystdex::ntctslen(str.c_str())))
NTCTS 正规化：保留空字符之前的字符。
Definition: string.hpp:467
YSLib::i
return i
Definition: YCoreUtilities.h:176
ios.hpp
ISO C++ 标准库输入/输出流基类扩展。
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::restrict_length
_tString && restrict_length(_tString &&str, const typename string_traits< _tString >::size_type n)
限制长度不超过指定参数。
Definition: string.hpp:510
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
YB_Impl_String_ston_i_std
#define YB_Impl_String_ston_i_std(_type, _n)
Definition: string.hpp:1115
ystdex::concat
void concat(_tCon &con, _tIn first, _tIn last)
插入元素到容器末尾。
Definition: container.hpp:436
ystdex::string_traits::const_reference
const value_type & const_reference
Definition: string.hpp:67
ystdex::details::str_algos< 1 >::trim_right_pos
static auto trim_right_pos(_tString &s, _tSize n) -> decltype(s.erase(n+1))
Definition: string.hpp:196
ystdex::min
const _type & min(const _type &a, const _type &b, _fComp comp=less< _type >())
取较小的元素。
Definition: algorithm.hpp:527
ystdex::to_wstring
enable_if_t< is_class< _type >::value, decltype(std::declval< _tStream & >).str())> to_wstring(const _type &x)
Definition: string.hpp:1080
ystdex::string_traits::initializer
std::initializer_list< value_type > initializer
Definition: string.hpp:71
ystdex::vfmtlen
size_t vfmtlen(const char *, std::va_list)
计算指定格式字符串输出的占用的字节数。
Definition: cstdio.cpp:39
ystdex::_t
typename _type::type _t
嵌套类型别名。
Definition: type_traits.hpp:97
cstring.h
ISO C 标准字符串扩展。
memory.hpp
存储和智能指针特性。
ystdex::details::is_string_like
Definition: string.hpp:82
ynothrowv
#define ynothrowv
YSLib 无异常抛出保证验证：有条件地使用无异常抛出规范。
Definition: ydef.h:786
ystdex::ntctsncpy
enable_if_irreplaceable_char_t< _tChar, _tChar * > ntctsncpy(_tChar *s1, const _tChar *s2, size_t n)
复制不超过指定长度的 NTCTS 。
Definition: cstring.h:315
ystdex::underlying
underlying_type_t< _type > underlying(_type val)
取枚举值的底层整数。
Definition: utility.hpp:240
ystdex::rtrim
_tString && rtrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续后缀字符。
Definition: string.hpp:676
CHRLib::e
const char const char * e
Definition: CharacterProcessing.h:109
ystdex::to_array
std::array< _type, _vN > to_array(const _tSrc &src)
转换指定参数为 std::array 对象。
Definition: array.hpp:87
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:590
ystdex::cpp2014::remove_reference_t
typename remove_reference< _type >::type remove_reference_t
Definition: type_traits.hpp:299
array.hpp
数组操作。
ystdex::string_traits::allocator_type
_t< nested_allocator< string_type >> allocator_type
Definition: string.hpp:62
std
Definition: memory.hpp:1183
ystdex::is_equal
相等关系仿函数。
Definition: functor.hpp:204
cstdio.h
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:603
ystdex::alph
_tString alph(_tString &str)
取字母表：有序的字符串的不重复序列。
Definition: string.hpp:525
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:629
YSLib::Text::str
const char const char * str
Definition: TextFile.h:81
CHRLib::c
c
Definition: CharacterProcessing.h:81
yforward
#define yforward(_expr)
根据参数类型使用 std::forward 传递对应参数。
Definition: ydef.h:995
yassume
#define yassume(_expr)
假定：环境语义。
Definition: cassert.h:105
ystdex::details::ston_dispatcher
Definition: string.hpp:1096
ystdex::sort_unique
_tRandom sort_unique(_tRandom first, _tRandom last)
排序指定序列范围，保留不重复元素的区间。
Definition: algorithm.hpp:512
ystdex::cpp2011::begin
_type * begin(_type(&&array)[_vN])
Definition: range.hpp:46
ystdex::details::str_algos< 0 >::trim_right_pos
static auto trim_right_pos(_tString &s, _tSize n) -> decltype(s.remove_suffix(n), s)
Definition: string.hpp:151
CHRLib::d
_tDst * d
Definition: CharacterProcessing.h:139
ystdex::to_string
enable_if_t< is_class< _type >::value, decltype(std::declval< _tStream & >).str())> to_string(const _type &x)
Definition: string.hpp:1046
ystdex::string_traits::value_type
remove_rcv_t< decltype(std::declval< string_type >()[0])> value_type
Definition: string.hpp:58
ystdex::size
auto size(const _tRange &c) -> decltype(c.size())
类容器访问。
Definition: range.hpp:233
yconstraint
#define yconstraint(_expr)
约束：接口语义。
Definition: cassert.h:88
ystdex::is_string_like
判断指定类型是否为类字符串类型。
Definition: string.hpp:253
ystdex::and_
逻辑操作元函数。
Definition: type_traits.hpp:420
ystdex::trim
_tString && trim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀与后缀字符。
Definition: string.hpp:707
ystdex::ltrim
_tString && ltrim(_tString &&str, typename string_traits< _tString >::value_type c)
删除字符串中指定的连续前缀字符。
Definition: string.hpp:645
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:981
ystdex::string_traits::difference_type
typename std::allocator_traits< allocator_type >::difference_type difference_type
Definition: string.hpp:65
ystdex::vsfmt
_tString vsfmt(const _tChar *fmt, std::va_list args)
以 C 标准输出格式的输出 std::basic_string 实例的对象。
Definition: string.hpp:1171
ynoexcept
#define ynoexcept(...)
YSLib 无异常抛出保证：指定特定的异常规范。
Definition: ydef.h:746