regex_compiler.tcc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. // class template regex -*- C++ -*-
  2. // Copyright (C) 2013-2022 Free Software Foundation, Inc.
  3. //
  4. // This file is part of the GNU ISO C++ Library. This library is free
  5. // software; you can redistribute it and/or modify it under the
  6. // terms of the GNU General Public License as published by the
  7. // Free Software Foundation; either version 3, or (at your option)
  8. // any later version.
  9. // This library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // Under Section 7 of GPL version 3, you are granted additional
  14. // permissions described in the GCC Runtime Library Exception, version
  15. // 3.1, as published by the Free Software Foundation.
  16. // You should have received a copy of the GNU General Public License and
  17. // a copy of the GCC Runtime Library Exception along with this program;
  18. // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
  19. // <http://www.gnu.org/licenses/>.
  20. /**
  21. * @file bits/regex_compiler.tcc
  22. * This is an internal header file, included by other library headers.
  23. * Do not attempt to use it directly. @headername{regex}
  24. */
  25. // FIXME make comments doxygen format.
  26. /*
  27. // This compiler refers to "Regular Expression Matching Can Be Simple And Fast"
  28. // (http://swtch.com/~rsc/regexp/regexp1.html),
  29. // but doesn't strictly follow it.
  30. //
  31. // When compiling, states are *chained* instead of tree- or graph-constructed.
  32. // It's more like structured programs: there's if statement and loop statement.
  33. //
  34. // For alternative structure (say "a|b"), aka "if statement", two branches
  35. // should be constructed. However, these two shall merge to an "end_tag" at
  36. // the end of this operator:
  37. //
  38. // branch1
  39. // / \
  40. // => begin_tag end_tag =>
  41. // \ /
  42. // branch2
  43. //
  44. // This is the difference between this implementation and that in Russ's
  45. // article.
  46. //
  47. // That's why we introduced dummy node here ------ "end_tag" is a dummy node.
  48. // All dummy nodes will be eliminated at the end of compilation.
  49. */
  50. namespace std _GLIBCXX_VISIBILITY(default)
  51. {
  52. _GLIBCXX_BEGIN_NAMESPACE_VERSION
  53. namespace __detail
  54. {
  55. template<typename _TraitsT>
  56. _Compiler<_TraitsT>::
  57. _Compiler(const _CharT* __b, const _CharT* __e,
  58. const typename _TraitsT::locale_type& __loc, _FlagT __flags)
  59. : _M_flags(_S_validate(__flags)),
  60. _M_scanner(__b, __e, _M_flags, __loc),
  61. _M_nfa(make_shared<_RegexT>(__loc, _M_flags)),
  62. _M_traits(_M_nfa->_M_traits),
  63. _M_ctype(std::use_facet<_CtypeT>(__loc))
  64. {
  65. _StateSeqT __r(*_M_nfa, _M_nfa->_M_start());
  66. __r._M_append(_M_nfa->_M_insert_subexpr_begin());
  67. this->_M_disjunction();
  68. if (!_M_match_token(_ScannerT::_S_token_eof))
  69. __throw_regex_error(regex_constants::error_paren);
  70. __r._M_append(_M_pop());
  71. __glibcxx_assert(_M_stack.empty());
  72. __r._M_append(_M_nfa->_M_insert_subexpr_end());
  73. __r._M_append(_M_nfa->_M_insert_accept());
  74. _M_nfa->_M_eliminate_dummy();
  75. }
  76. template<typename _TraitsT>
  77. void
  78. _Compiler<_TraitsT>::
  79. _M_disjunction()
  80. {
  81. this->_M_alternative();
  82. while (_M_match_token(_ScannerT::_S_token_or))
  83. {
  84. _StateSeqT __alt1 = _M_pop();
  85. this->_M_alternative();
  86. _StateSeqT __alt2 = _M_pop();
  87. auto __end = _M_nfa->_M_insert_dummy();
  88. __alt1._M_append(__end);
  89. __alt2._M_append(__end);
  90. // __alt2 is state._M_next, __alt1 is state._M_alt. The executor
  91. // executes _M_alt before _M_next, as well as executing left
  92. // alternative before right one.
  93. _M_stack.push(_StateSeqT(*_M_nfa,
  94. _M_nfa->_M_insert_alt(
  95. __alt2._M_start, __alt1._M_start, false),
  96. __end));
  97. }
  98. }
  99. template<typename _TraitsT>
  100. void
  101. _Compiler<_TraitsT>::
  102. _M_alternative()
  103. {
  104. if (this->_M_term())
  105. {
  106. _StateSeqT __re = _M_pop();
  107. this->_M_alternative();
  108. __re._M_append(_M_pop());
  109. _M_stack.push(__re);
  110. }
  111. else
  112. _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_dummy()));
  113. }
  114. template<typename _TraitsT>
  115. bool
  116. _Compiler<_TraitsT>::
  117. _M_term()
  118. {
  119. if (this->_M_assertion())
  120. return true;
  121. if (this->_M_atom())
  122. {
  123. while (this->_M_quantifier())
  124. ;
  125. return true;
  126. }
  127. return false;
  128. }
  129. template<typename _TraitsT>
  130. bool
  131. _Compiler<_TraitsT>::
  132. _M_assertion()
  133. {
  134. if (_M_match_token(_ScannerT::_S_token_line_begin))
  135. _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_line_begin()));
  136. else if (_M_match_token(_ScannerT::_S_token_line_end))
  137. _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->_M_insert_line_end()));
  138. else if (_M_match_token(_ScannerT::_S_token_word_bound))
  139. // _M_value[0] == 'n' means it's negative, say "not word boundary".
  140. _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->
  141. _M_insert_word_bound(_M_value[0] == 'n')));
  142. else if (_M_match_token(_ScannerT::_S_token_subexpr_lookahead_begin))
  143. {
  144. auto __neg = _M_value[0] == 'n';
  145. this->_M_disjunction();
  146. if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
  147. __throw_regex_error(regex_constants::error_paren);
  148. auto __tmp = _M_pop();
  149. __tmp._M_append(_M_nfa->_M_insert_accept());
  150. _M_stack.push(
  151. _StateSeqT(
  152. *_M_nfa,
  153. _M_nfa->_M_insert_lookahead(__tmp._M_start, __neg)));
  154. }
  155. else
  156. return false;
  157. return true;
  158. }
  159. template<typename _TraitsT>
  160. bool
  161. _Compiler<_TraitsT>::
  162. _M_quantifier()
  163. {
  164. bool __neg = (_M_flags & regex_constants::ECMAScript);
  165. auto __init = [this, &__neg]()
  166. {
  167. if (_M_stack.empty())
  168. __throw_regex_error(regex_constants::error_badrepeat);
  169. __neg = __neg && _M_match_token(_ScannerT::_S_token_opt);
  170. };
  171. if (_M_match_token(_ScannerT::_S_token_closure0))
  172. {
  173. __init();
  174. auto __e = _M_pop();
  175. _StateSeqT __r(*_M_nfa,
  176. _M_nfa->_M_insert_repeat(_S_invalid_state_id,
  177. __e._M_start, __neg));
  178. __e._M_append(__r);
  179. _M_stack.push(__r);
  180. }
  181. else if (_M_match_token(_ScannerT::_S_token_closure1))
  182. {
  183. __init();
  184. auto __e = _M_pop();
  185. __e._M_append(_M_nfa->_M_insert_repeat(_S_invalid_state_id,
  186. __e._M_start, __neg));
  187. _M_stack.push(__e);
  188. }
  189. else if (_M_match_token(_ScannerT::_S_token_opt))
  190. {
  191. __init();
  192. auto __e = _M_pop();
  193. auto __end = _M_nfa->_M_insert_dummy();
  194. _StateSeqT __r(*_M_nfa,
  195. _M_nfa->_M_insert_repeat(_S_invalid_state_id,
  196. __e._M_start, __neg));
  197. __e._M_append(__end);
  198. __r._M_append(__end);
  199. _M_stack.push(__r);
  200. }
  201. else if (_M_match_token(_ScannerT::_S_token_interval_begin))
  202. {
  203. if (_M_stack.empty())
  204. __throw_regex_error(regex_constants::error_badrepeat);
  205. if (!_M_match_token(_ScannerT::_S_token_dup_count))
  206. __throw_regex_error(regex_constants::error_badbrace);
  207. _StateSeqT __r(_M_pop());
  208. _StateSeqT __e(*_M_nfa, _M_nfa->_M_insert_dummy());
  209. long __min_rep = _M_cur_int_value(10);
  210. bool __infi = false;
  211. long __n = 0;
  212. // {3
  213. if (_M_match_token(_ScannerT::_S_token_comma))
  214. {
  215. if (_M_match_token(_ScannerT::_S_token_dup_count)) // {3,7}
  216. __n = _M_cur_int_value(10) - __min_rep;
  217. else
  218. __infi = true;
  219. }
  220. if (!_M_match_token(_ScannerT::_S_token_interval_end))
  221. __throw_regex_error(regex_constants::error_brace);
  222. __neg = __neg && _M_match_token(_ScannerT::_S_token_opt);
  223. for (long __i = 0; __i < __min_rep; ++__i)
  224. __e._M_append(__r._M_clone());
  225. if (__infi)
  226. {
  227. auto __tmp = __r._M_clone();
  228. _StateSeqT __s(*_M_nfa,
  229. _M_nfa->_M_insert_repeat(_S_invalid_state_id,
  230. __tmp._M_start, __neg));
  231. __tmp._M_append(__s);
  232. __e._M_append(__s);
  233. }
  234. else
  235. {
  236. if (__n < 0)
  237. __throw_regex_error(regex_constants::error_badbrace);
  238. auto __end = _M_nfa->_M_insert_dummy();
  239. // _M_alt is the "match more" branch, and _M_next is the
  240. // "match less" one. Switch _M_alt and _M_next of all created
  241. // nodes. This is a hack but IMO works well.
  242. std::stack<_StateIdT> __stack;
  243. for (long __i = 0; __i < __n; ++__i)
  244. {
  245. auto __tmp = __r._M_clone();
  246. auto __alt = _M_nfa->_M_insert_repeat(__tmp._M_start,
  247. __end, __neg);
  248. __stack.push(__alt);
  249. __e._M_append(_StateSeqT(*_M_nfa, __alt, __tmp._M_end));
  250. }
  251. __e._M_append(__end);
  252. while (!__stack.empty())
  253. {
  254. auto& __tmp = (*_M_nfa)[__stack.top()];
  255. __stack.pop();
  256. std::swap(__tmp._M_next, __tmp._M_alt);
  257. }
  258. }
  259. _M_stack.push(__e);
  260. }
  261. else
  262. return false;
  263. return true;
  264. }
  265. #define __INSERT_REGEX_MATCHER(__func, ...)\
  266. do {\
  267. if (!(_M_flags & regex_constants::icase))\
  268. if (!(_M_flags & regex_constants::collate))\
  269. __func<false, false>(__VA_ARGS__);\
  270. else\
  271. __func<false, true>(__VA_ARGS__);\
  272. else\
  273. if (!(_M_flags & regex_constants::collate))\
  274. __func<true, false>(__VA_ARGS__);\
  275. else\
  276. __func<true, true>(__VA_ARGS__);\
  277. } while (false)
  278. template<typename _TraitsT>
  279. bool
  280. _Compiler<_TraitsT>::
  281. _M_atom()
  282. {
  283. if (_M_match_token(_ScannerT::_S_token_anychar))
  284. {
  285. if (!(_M_flags & regex_constants::ECMAScript))
  286. __INSERT_REGEX_MATCHER(_M_insert_any_matcher_posix);
  287. else
  288. __INSERT_REGEX_MATCHER(_M_insert_any_matcher_ecma);
  289. }
  290. else if (_M_try_char())
  291. __INSERT_REGEX_MATCHER(_M_insert_char_matcher);
  292. else if (_M_match_token(_ScannerT::_S_token_backref))
  293. _M_stack.push(_StateSeqT(*_M_nfa, _M_nfa->
  294. _M_insert_backref(_M_cur_int_value(10))));
  295. else if (_M_match_token(_ScannerT::_S_token_quoted_class))
  296. __INSERT_REGEX_MATCHER(_M_insert_character_class_matcher);
  297. else if (_M_match_token(_ScannerT::_S_token_subexpr_no_group_begin))
  298. {
  299. _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_dummy());
  300. this->_M_disjunction();
  301. if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
  302. __throw_regex_error(regex_constants::error_paren);
  303. __r._M_append(_M_pop());
  304. _M_stack.push(__r);
  305. }
  306. else if (_M_match_token(_ScannerT::_S_token_subexpr_begin))
  307. {
  308. _StateSeqT __r(*_M_nfa, _M_nfa->_M_insert_subexpr_begin());
  309. this->_M_disjunction();
  310. if (!_M_match_token(_ScannerT::_S_token_subexpr_end))
  311. __throw_regex_error(regex_constants::error_paren);
  312. __r._M_append(_M_pop());
  313. __r._M_append(_M_nfa->_M_insert_subexpr_end());
  314. _M_stack.push(__r);
  315. }
  316. else if (!_M_bracket_expression())
  317. return false;
  318. return true;
  319. }
  320. template<typename _TraitsT>
  321. bool
  322. _Compiler<_TraitsT>::
  323. _M_bracket_expression()
  324. {
  325. bool __neg =
  326. _M_match_token(_ScannerT::_S_token_bracket_neg_begin);
  327. if (!(__neg || _M_match_token(_ScannerT::_S_token_bracket_begin)))
  328. return false;
  329. __INSERT_REGEX_MATCHER(_M_insert_bracket_matcher, __neg);
  330. return true;
  331. }
  332. #undef __INSERT_REGEX_MATCHER
  333. template<typename _TraitsT>
  334. template<bool __icase, bool __collate>
  335. void
  336. _Compiler<_TraitsT>::
  337. _M_insert_any_matcher_ecma()
  338. {
  339. _M_stack.push(_StateSeqT(*_M_nfa,
  340. _M_nfa->_M_insert_matcher
  341. (_AnyMatcher<_TraitsT, true, __icase, __collate>
  342. (_M_traits))));
  343. }
  344. template<typename _TraitsT>
  345. template<bool __icase, bool __collate>
  346. void
  347. _Compiler<_TraitsT>::
  348. _M_insert_any_matcher_posix()
  349. {
  350. _M_stack.push(_StateSeqT(*_M_nfa,
  351. _M_nfa->_M_insert_matcher
  352. (_AnyMatcher<_TraitsT, false, __icase, __collate>
  353. (_M_traits))));
  354. }
  355. template<typename _TraitsT>
  356. template<bool __icase, bool __collate>
  357. void
  358. _Compiler<_TraitsT>::
  359. _M_insert_char_matcher()
  360. {
  361. _M_stack.push(_StateSeqT(*_M_nfa,
  362. _M_nfa->_M_insert_matcher
  363. (_CharMatcher<_TraitsT, __icase, __collate>
  364. (_M_value[0], _M_traits))));
  365. }
  366. template<typename _TraitsT>
  367. template<bool __icase, bool __collate>
  368. void
  369. _Compiler<_TraitsT>::
  370. _M_insert_character_class_matcher()
  371. {
  372. __glibcxx_assert(_M_value.size() == 1);
  373. _BracketMatcher<__icase, __collate> __matcher
  374. (_M_ctype.is(_CtypeT::upper, _M_value[0]), _M_traits);
  375. __matcher._M_add_character_class(_M_value, false);
  376. __matcher._M_ready();
  377. _M_stack.push(_StateSeqT(*_M_nfa,
  378. _M_nfa->_M_insert_matcher(std::move(__matcher))));
  379. }
  380. template<typename _TraitsT>
  381. template<bool __icase, bool __collate>
  382. void
  383. _Compiler<_TraitsT>::
  384. _M_insert_bracket_matcher(bool __neg)
  385. {
  386. _BracketMatcher<__icase, __collate> __matcher(__neg, _M_traits);
  387. _BracketState __last_char;
  388. if (_M_try_char())
  389. __last_char.set(_M_value[0]);
  390. else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
  391. // Dash as first character is a normal character.
  392. __last_char.set('-');
  393. while (_M_expression_term(__last_char, __matcher))
  394. ;
  395. if (__last_char._M_is_char())
  396. __matcher._M_add_char(__last_char.get());
  397. __matcher._M_ready();
  398. _M_stack.push(_StateSeqT(
  399. *_M_nfa,
  400. _M_nfa->_M_insert_matcher(std::move(__matcher))));
  401. }
  402. template<typename _TraitsT>
  403. template<bool __icase, bool __collate>
  404. bool
  405. _Compiler<_TraitsT>::
  406. _M_expression_term(_BracketState& __last_char,
  407. _BracketMatcher<__icase, __collate>& __matcher)
  408. {
  409. if (_M_match_token(_ScannerT::_S_token_bracket_end))
  410. return false;
  411. // Add any previously cached char into the matcher and update cache.
  412. const auto __push_char = [&](_CharT __ch)
  413. {
  414. if (__last_char._M_is_char())
  415. __matcher._M_add_char(__last_char.get());
  416. __last_char.set(__ch);
  417. };
  418. // Add any previously cached char into the matcher and update cache.
  419. const auto __push_class = [&]
  420. {
  421. if (__last_char._M_is_char())
  422. __matcher._M_add_char(__last_char.get());
  423. // We don't cache anything here, just record that the last thing
  424. // processed was a character class (or similar).
  425. __last_char.reset(_BracketState::_Type::_Class);
  426. };
  427. if (_M_match_token(_ScannerT::_S_token_collsymbol))
  428. {
  429. auto __symbol = __matcher._M_add_collate_element(_M_value);
  430. if (__symbol.size() == 1)
  431. __push_char(__symbol[0]);
  432. else
  433. __push_class();
  434. }
  435. else if (_M_match_token(_ScannerT::_S_token_equiv_class_name))
  436. {
  437. __push_class();
  438. __matcher._M_add_equivalence_class(_M_value);
  439. }
  440. else if (_M_match_token(_ScannerT::_S_token_char_class_name))
  441. {
  442. __push_class();
  443. __matcher._M_add_character_class(_M_value, false);
  444. }
  445. else if (_M_try_char())
  446. __push_char(_M_value[0]);
  447. // POSIX doesn't allow '-' as a start-range char (say [a-z--0]),
  448. // except when the '-' is the first or last character in the bracket
  449. // expression ([--0]). ECMAScript treats all '-' after a range as a
  450. // normal character. Also see above, where _M_expression_term gets called.
  451. //
  452. // As a result, POSIX rejects [-----], but ECMAScript doesn't.
  453. // Boost (1.57.0) always uses POSIX style even in its ECMAScript syntax.
  454. // Clang (3.5) always uses ECMAScript style even in its POSIX syntax.
  455. //
  456. // It turns out that no one reads BNFs ;)
  457. else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
  458. {
  459. if (_M_match_token(_ScannerT::_S_token_bracket_end))
  460. {
  461. // For "-]" the dash is a literal character.
  462. __push_char('-');
  463. return false;
  464. }
  465. else if (__last_char._M_is_class())
  466. {
  467. // "\\w-" is invalid, start of range must be a single char.
  468. __throw_regex_error(regex_constants::error_range,
  469. "Invalid start of '[x-x]' range in "
  470. "regular expression");
  471. }
  472. else if (__last_char._M_is_char())
  473. {
  474. if (_M_try_char())
  475. {
  476. // "x-y"
  477. __matcher._M_make_range(__last_char.get(), _M_value[0]);
  478. __last_char.reset();
  479. }
  480. else if (_M_match_token(_ScannerT::_S_token_bracket_dash))
  481. {
  482. // "x--"
  483. __matcher._M_make_range(__last_char.get(), '-');
  484. __last_char.reset();
  485. }
  486. else
  487. __throw_regex_error(regex_constants::error_range,
  488. "Invalid end of '[x-x]' range in "
  489. "regular expression");
  490. }
  491. else if (_M_flags & regex_constants::ECMAScript)
  492. {
  493. // A dash that is not part of an existing range. Might be the
  494. // start of a new range, or might just be a literal '-' char.
  495. // Only ECMAScript allows that in the middle of a bracket expr.
  496. __push_char('-');
  497. }
  498. else
  499. __throw_regex_error(regex_constants::error_range,
  500. "Invalid location of '-' within '[...]' in "
  501. "POSIX regular expression");
  502. }
  503. else if (_M_match_token(_ScannerT::_S_token_quoted_class))
  504. {
  505. __push_class();
  506. __matcher._M_add_character_class(_M_value,
  507. _M_ctype.is(_CtypeT::upper,
  508. _M_value[0]));
  509. }
  510. else
  511. __throw_regex_error(regex_constants::error_brack,
  512. "Unexpected character within '[...]' in "
  513. "regular expression");
  514. return true;
  515. }
  516. template<typename _TraitsT>
  517. bool
  518. _Compiler<_TraitsT>::
  519. _M_try_char()
  520. {
  521. bool __is_char = false;
  522. if (_M_match_token(_ScannerT::_S_token_oct_num))
  523. {
  524. __is_char = true;
  525. _M_value.assign(1, _M_cur_int_value(8));
  526. }
  527. else if (_M_match_token(_ScannerT::_S_token_hex_num))
  528. {
  529. __is_char = true;
  530. _M_value.assign(1, _M_cur_int_value(16));
  531. }
  532. else if (_M_match_token(_ScannerT::_S_token_ord_char))
  533. __is_char = true;
  534. return __is_char;
  535. }
  536. template<typename _TraitsT>
  537. bool
  538. _Compiler<_TraitsT>::
  539. _M_match_token(_TokenT __token)
  540. {
  541. if (__token == _M_scanner._M_get_token())
  542. {
  543. _M_value = _M_scanner._M_get_value();
  544. _M_scanner._M_advance();
  545. return true;
  546. }
  547. return false;
  548. }
  549. template<typename _TraitsT>
  550. int
  551. _Compiler<_TraitsT>::
  552. _M_cur_int_value(int __radix)
  553. {
  554. long __v = 0;
  555. for (typename _StringT::size_type __i = 0;
  556. __i < _M_value.length(); ++__i)
  557. __v =__v * __radix + _M_traits.value(_M_value[__i], __radix);
  558. return __v;
  559. }
  560. template<typename _TraitsT, bool __icase, bool __collate>
  561. bool
  562. _BracketMatcher<_TraitsT, __icase, __collate>::
  563. _M_apply(_CharT __ch, false_type) const
  564. {
  565. return [this, __ch]
  566. {
  567. if (std::binary_search(_M_char_set.begin(), _M_char_set.end(),
  568. _M_translator._M_translate(__ch)))
  569. return true;
  570. auto __s = _M_translator._M_transform(__ch);
  571. for (auto& __it : _M_range_set)
  572. if (_M_translator._M_match_range(__it.first, __it.second, __s))
  573. return true;
  574. if (_M_traits.isctype(__ch, _M_class_set))
  575. return true;
  576. if (std::find(_M_equiv_set.begin(), _M_equiv_set.end(),
  577. _M_traits.transform_primary(&__ch, &__ch+1))
  578. != _M_equiv_set.end())
  579. return true;
  580. for (auto& __it : _M_neg_class_set)
  581. if (!_M_traits.isctype(__ch, __it))
  582. return true;
  583. return false;
  584. }() ^ _M_is_non_matching;
  585. }
  586. } // namespace __detail
  587. _GLIBCXX_END_NAMESPACE_VERSION
  588. } // namespace