1111
1212namespace strtpl {
1313
14+ // TYPED_LITERAL
15+ // See https://github.com/microsoft/STL/blob/17fde2cbab6e8724d81c9555237c9a623d7fb954/tests/std/tests/P0220R1_string_view/test.cpp#L260-L277
16+
17+ template <class CharT >
18+ struct choose_literal ; // not defined
19+
20+ template <>
21+ struct choose_literal <char > {
22+ static constexpr const char *
23+ choose (const char * s, const wchar_t *) {
24+ return s;
25+ }
26+ };
27+
28+ template <>
29+ struct choose_literal <wchar_t > {
30+ static constexpr const wchar_t *
31+ choose (const char *, const wchar_t * s) {
32+ return s;
33+ }
34+ };
35+
36+ #define TYPED_LITERAL (CharT, Literal ) (choose_literal<CharT>::choose(Literal, L##Literal))
37+
1438 // match_results_format
1539
16- template <class BidirectionalIter , class Allocator , class OutputIter , class ST >
40+ template <class BiIter , class Allocator , class OutputIter , class ST >
1741 OutputIter
1842 match_results_format (
19- const std::match_results<BidirectionalIter , Allocator>& mo, OutputIter out,
20- std::basic_string_view<typename std::iterator_traits<BidirectionalIter >::value_type, ST> fmt,
43+ const std::match_results<BiIter , Allocator>& mo, OutputIter out,
44+ std::basic_string_view<typename std::iterator_traits<BiIter >::value_type, ST> fmt,
2145 std::regex_constants::match_flag_type flags = std::regex_constants::format_default) {
2246 return mo.format (out, fmt.data (), fmt.data () + fmt.size (), flags);
2347 }
@@ -30,8 +54,9 @@ namespace strtpl {
3054 std::regex_constants::match_flag_type flags = std::regex_constants::match_default) {
3155 std::basic_string<CharT, ST> r;
3256 // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
33- const std::basic_regex<CharT> re{R"( [.*+?^${}()|[\]\\])" };
34- std::regex_replace (std::back_inserter (r), s.begin (), s.end (), re, " \\ $&" , flags);
57+ const std::basic_regex<CharT> re (TYPED_LITERAL (CharT, R"( [.*+?^${}()|[\]\\])" ));
58+ std::regex_replace (std::back_inserter (r), s.begin (), s.end (), re, TYPED_LITERAL (CharT, " \\ $&" ),
59+ flags);
3560 return r;
3661 }
3762
@@ -44,30 +69,29 @@ namespace strtpl {
4469 struct is_std_basic_string_view_with_char_type <std::basic_string_view<CharT, ST>, CharT>
4570 : std::true_type {};
4671
47- template <class BidirectionalIter , class Traits , class CharT , class Fn >
48- inline constexpr bool regex_replace_fn_constraint = std::conjunction_v<
49- std::is_invocable<Fn&, const std::match_results<BidirectionalIter >&>,
50- is_std_basic_string_view_with_char_type<
51- std::invoke_result_t <Fn&, const std::match_results<BidirectionalIter >&>, CharT>>;
72+ template <class BiIter , class Traits , class CharT , class Fn >
73+ inline constexpr bool regex_replace_fn_constraint =
74+ std::conjunction_v<std:: is_invocable<Fn&, const std::match_results<BiIter >&>,
75+ is_std_basic_string_view_with_char_type<
76+ std::invoke_result_t <Fn&, const std::match_results<BiIter >&>, CharT>>;
5277
5378 // clang-format off
54- template <class OutputIter , class BidirectionalIter , class Traits , class CharT , class Fn >
55- requires regex_replace_fn_constraint<BidirectionalIter , Traits, CharT, Fn>
79+ template <class OutputIter , class BiIter , class Traits , class CharT , class Fn >
80+ requires regex_replace_fn_constraint<BiIter , Traits, CharT, Fn>
5681 OutputIter
5782 // clang-format on
5883 regex_replace_fn (
59- OutputIter out, BidirectionalIter first, BidirectionalIter last,
60- const std::basic_regex<CharT, Traits>& re, Fn fn,
84+ OutputIter out, BiIter first, BiIter last, const std::basic_regex<CharT, Traits>& re, Fn fn,
6185 std::regex_constants::match_flag_type flags = std::regex_constants::match_default) {
62- using Iter = std::regex_iterator<BidirectionalIter , CharT, Traits>;
86+ using Iter = std::regex_iterator<BiIter , CharT, Traits>;
6387 Iter i (first, last, re, flags);
6488 Iter eof;
6589 const bool format_copy = !(flags & std::regex_constants::format_no_copy);
6690 if (i == eof) {
6791 if (format_copy)
6892 out = std::copy (first, last, out);
6993 } else {
70- std::sub_match<BidirectionalIter > lm;
94+ std::sub_match<BiIter > lm;
7195 const bool format_first_only = flags & std::regex_constants::format_first_only;
7296 for (; i != eof; ++i) {
7397 if (format_copy)
@@ -97,19 +121,18 @@ namespace strtpl {
97121
98122 // regex_count
99123
100- template <class BidirectionalIter , class Traits , class CharT >
124+ template <class BiIter , class Traits , class CharT >
101125 std::pair<std::ptrdiff_t , std::ptrdiff_t >
102- regex_count (BidirectionalIter first, BidirectionalIter last,
103- const std::basic_regex<CharT, Traits>& re,
126+ regex_count (BiIter first, BiIter last, const std::basic_regex<CharT, Traits>& re,
104127 std::regex_constants::match_flag_type flags = std::regex_constants::match_default) {
105- using Iter = std::regex_iterator<BidirectionalIter , CharT, Traits>;
128+ using Iter = std::regex_iterator<BiIter , CharT, Traits>;
106129 Iter i (first, last, re, flags);
107130 Iter eof;
108131 std::ptrdiff_t n = 0 , m = 0 ;
109132 if (i == eof) {
110133 m = std::distance (first, last);
111134 } else {
112- std::sub_match<BidirectionalIter > lm;
135+ std::sub_match<BiIter > lm;
113136 const bool format_first_only = flags & std::regex_constants::format_first_only;
114137 for (; i != eof; ++i) {
115138 ++n;
@@ -159,12 +182,12 @@ namespace strtpl {
159182 return i == end (map) ? throw std::out_of_range (" strtpl::at" ) : get<1 >(*i);
160183 }
161184
162- template <class BidirectionalIter >
185+ template <class BiIter >
163186 void
164- _invalid (BidirectionalIter first, BidirectionalIter last) {
187+ _invalid (BiIter first, BiIter last) {
188+ using CharT = typename std::iterator_traits<BiIter>::value_type;
165189 // See https://docs.python.org/ja/3/library/stdtypes.html#str.splitlines
166- const std::basic_regex<typename std::iterator_traits<BidirectionalIter>::value_type> re{
167- R"( (\r\n?|[\n\v\f]))" };
190+ const std::basic_regex<CharT> re (TYPED_LITERAL (CharT, R"( (\r\n?|[\n\v\f]))" ));
168191 const auto [lineno, colno] = regex_count (first, last, re);
169192 auto msg = " Invalid placeholder in string: line " + std::to_string (lineno + 1 ) + " , col "
170193 + std::to_string (colno + 1 );
@@ -178,7 +201,7 @@ namespace strtpl {
178201 std::basic_string_view<CharT> delimiter{};
179202 std::basic_string_view<CharT> idpattern{};
180203 std::basic_string_view<CharT> braceidpattern{};
181- const std::basic_string_view<CharT> invalid{" ()" };
204+ const std::basic_string_view<CharT> invalid{TYPED_LITERAL (CharT, " ()" ) };
182205 std::regex_constants::match_flag_type flags = std::regex_constants::match_default;
183206
184207 string_template () = default ;
@@ -202,10 +225,12 @@ namespace strtpl {
202225 const std::basic_regex<CharT> re{[this ] {
203226 using namespace hidden_ops ::string_view_ops;
204227 const auto delim = regex_escape (delimiter);
205- const auto escape = " (" + delim + " )" ;
206- return delim + " (?:" + idpattern + " |\\ {" + braceidpattern + " \\ }|" + escape + " |" + invalid
207- + " )" ;
228+ const auto escape = TYPED_LITERAL (CharT, " (" ) + delim + TYPED_LITERAL (CharT, " )" );
229+ return delim + TYPED_LITERAL (CharT, " (?:" ) + idpattern + TYPED_LITERAL (CharT, " |\\ {" )
230+ + braceidpattern + TYPED_LITERAL (CharT, " \\ }|" ) + escape + TYPED_LITERAL (CharT, " |" )
231+ + invalid + TYPED_LITERAL (CharT, " )" );
208232 }()};
233+
209234 const auto convert =
210235 [&delim = delimiter, first = s.begin (),
211236 &map](const std::match_results<typename std::basic_string_view<CharT, ST>::iterator>& mo)
@@ -225,12 +250,16 @@ namespace strtpl {
225250 }
226251 throw std::runtime_error (" Unrecognized group in pattern" );
227252 };
253+
228254 return regex_replace_fn (s, re, convert, flags);
229255 }
230256 }; // struct string_template
231257
232258 inline namespace cpo {
233259 // See https://github.com/python/cpython/blob/971343eb569a3418aa9a0bad9b638cccf1470ef8/Lib/string.py#L57
234260 inline constexpr string_template<char > substitute{" $" , " ([_a-zA-Z][_a-zA-Z0-9]*)" };
261+ inline constexpr string_template<wchar_t > wsubstitute{L" $" , L" ([_a-zA-Z][_a-zA-Z0-9]*)" };
235262 } // namespace cpo
263+
264+ #undef TYPED_LITERAL
236265} // namespace strtpl
0 commit comments