|  | // -*- C++ -*- | 
|  | // regex utils for the C++ library testsuite. | 
|  | // | 
|  | // Copyright (C) 2012-2025 Free Software Foundation, Inc. | 
|  | // | 
|  | // This file is part of the GNU ISO C++ Library.  This library is free | 
|  | // software; you can redistribute it and/or modify it under the | 
|  | // terms of the GNU General Public License as published by the | 
|  | // Free Software Foundation; either version 3, or (at your option) | 
|  | // any later version. | 
|  | // | 
|  | // This library is distributed in the hope that it will be useful, | 
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | // GNU General Public License for more details. | 
|  | // | 
|  | // You should have received a copy of the GNU General Public License along | 
|  | // with this library; see the file COPYING3.  If not see | 
|  | // <http://www.gnu.org/licenses/>. | 
|  | // | 
|  |  | 
|  | #ifndef _TESTSUITE_REGEX_H | 
|  | #define _TESTSUITE_REGEX_H 1 | 
|  |  | 
|  | #include <regex> | 
|  | #include <stdexcept> | 
|  | #include <iostream> | 
|  |  | 
|  | namespace __gnu_test | 
|  | { | 
|  | // Test on a compilation of simple expressions, throw regex_error on error. | 
|  | typedef std::regex				regex_type; | 
|  | typedef regex_type::flag_type			flag_type; | 
|  | typedef std::regex_constants::match_flag_type	match_flag_type; | 
|  | typedef std::regex_constants::error_type	error_type; | 
|  | typedef std::size_t				size_type; | 
|  | typedef std::string				string_type; | 
|  | using std::basic_regex; | 
|  | using std::match_results; | 
|  |  | 
|  | // Utilities | 
|  | struct regex_expected_fail { }; | 
|  |  | 
|  | const error_type regex_error_internal(static_cast<error_type>(-1)); | 
|  |  | 
|  | // Stringify error codes for text logging. | 
|  | const char* regex_error_codes[] = | 
|  | { | 
|  | "error_collate", | 
|  | "error_ctype", | 
|  | "error_escape", | 
|  | "error_backref", | 
|  | "error_brack", | 
|  | "error_paren", | 
|  | "error_brace", | 
|  | "error_badbrace", | 
|  | "error_range", | 
|  | "error_space", | 
|  | "error_badrepeat", | 
|  | "error_complexity", | 
|  | "error_stack" | 
|  | }; | 
|  |  | 
|  | void | 
|  | show_regex_error_codes() | 
|  | { | 
|  | using namespace std; | 
|  | using namespace std::regex_constants; | 
|  | const char tab('\t'); | 
|  | cout << "error_collate =   " << tab << error_collate << endl; | 
|  | cout << "error_ctype =     " << tab << error_ctype << endl; | 
|  | cout << "error_escape =    " << tab << error_escape << endl; | 
|  | cout << "error_backref =   " << tab << error_backref << endl; | 
|  | cout << "error_brack =     " << tab << error_brack << endl; | 
|  | cout << "error_paren =     " << tab << error_paren << endl; | 
|  | cout << "error_brace =     " << tab << error_brace << endl; | 
|  | cout << "error_badbrace =  " << tab << error_badbrace << endl; | 
|  | cout << "error_range =     " << tab << error_range << endl; | 
|  | cout << "error_space =     " << tab << error_space << endl; | 
|  | cout << "error_badrepeat = " << tab << error_badrepeat << endl; | 
|  | cout << "error_complexity =" << tab << error_complexity << endl; | 
|  | cout << "error_stack =     " << tab << error_stack << endl; | 
|  | } | 
|  |  | 
|  | // Arguments | 
|  | // string __res: the regular expression string | 
|  | // flag_type __f: flag | 
|  | // __error: expected error, if any | 
|  | void | 
|  | regex_sanity_check(const string_type& __res, | 
|  | flag_type __f = regex_type::basic, | 
|  | error_type __error =  regex_error_internal) | 
|  | { | 
|  | using namespace std; | 
|  |  | 
|  | try | 
|  | { | 
|  | regex_type reo(__res, __f); | 
|  | auto n = reo.mark_count(); | 
|  | cout << "regex_type::mark_count " << n << endl; | 
|  | } | 
|  | catch (const regex_error& e) | 
|  | { | 
|  | cout << "regex_sanity_check: "  << __res << endl; | 
|  | cout << "regex_error::what " << e.what() << endl; | 
|  |  | 
|  | show_regex_error_codes(); | 
|  | cout << "regex_error::code " << regex_error_codes[e.code()] << endl; | 
|  |  | 
|  | if (__error != regex_error_internal) | 
|  | { | 
|  | // Then expected error_type is __error. Check. | 
|  | if (__error != e.code()) | 
|  | { | 
|  | throw regex_expected_fail(); | 
|  | } | 
|  | } | 
|  | throw; | 
|  | } | 
|  | catch (const logic_error& e) | 
|  | { | 
|  | cout << "logic_error::what " << e.what() << endl; | 
|  | throw; | 
|  | } | 
|  | catch (const std::exception& e) | 
|  | { | 
|  | cout << "exception: " << endl; | 
|  | throw; | 
|  | } | 
|  | } | 
|  |  | 
|  | // regex_match_debug behaves like regex_match, but will run *two* executors | 
|  | // (if there's no back-reference) and check if their results agree. If not, | 
|  | // an exception is thrown. The arguments are the same as for regex_match. | 
|  | template<typename _Bi_iter, typename _Alloc, | 
|  | typename _Ch_type, typename _Rx_traits> | 
|  | bool | 
|  | regex_match_debug(_Bi_iter                                 __s, | 
|  | _Bi_iter                                 __e, | 
|  | match_results<_Bi_iter, _Alloc>&         __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __flags | 
|  | = std::regex_constants::match_default) | 
|  | { | 
|  | using namespace std::__detail; | 
|  | auto __res1 = __regex_algo_impl(__s, __e, __m, __re, __flags, | 
|  | _RegexExecutorPolicy::_S_auto, | 
|  | true); | 
|  | match_results<_Bi_iter, _Alloc> __mm; | 
|  | auto __res2 = __regex_algo_impl(__s, __e, __mm, __re, __flags, | 
|  | _RegexExecutorPolicy::_S_alternate, | 
|  | true); | 
|  | if (__res1 == __res2 && __m == __mm) | 
|  | return __res1; | 
|  | throw std::exception(); | 
|  | } | 
|  |  | 
|  | // No match_results version | 
|  | template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_match_debug(_Bi_iter                                 __first, | 
|  | _Bi_iter                                 __last, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __flags | 
|  | = std::regex_constants::match_default) | 
|  | { | 
|  | match_results<_Bi_iter> __what; | 
|  | return regex_match_debug(__first, __last, __what, __re, __flags); | 
|  | } | 
|  |  | 
|  | // C-string version | 
|  | template<typename _Ch_type, typename _Alloc, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_match_debug(const _Ch_type*                          __s, | 
|  | match_results<const _Ch_type*, _Alloc>&  __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_match_debug(__s, __s + _Rx_traits::length(__s), | 
|  | __m, __re, __f); } | 
|  |  | 
|  | // C-string version without match_results | 
|  | template<typename _Ch_type, class _Rx_traits> | 
|  | inline bool | 
|  | regex_match_debug(const _Ch_type*                          __s, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_match_debug(__s, __s + _Rx_traits::length(__s), | 
|  | __re, __f); } | 
|  |  | 
|  | // std::basic_string version | 
|  | template<typename _Ch_traits, typename _Ch_alloc, | 
|  | typename _Alloc, typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits, | 
|  | _Ch_alloc>& __s, | 
|  | match_results<typename std::basic_string<_Ch_type, | 
|  | _Ch_traits, _Ch_alloc>::const_iterator, | 
|  | _Alloc>& __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __flags | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_match_debug(__s.begin(), __s.end(), | 
|  | __m, __re, __flags); } | 
|  |  | 
|  | // std::basic_string version without match_results | 
|  | template<typename _Ch_traits, typename _Str_allocator, | 
|  | typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_match_debug(const std::basic_string<_Ch_type, _Ch_traits, | 
|  | _Str_allocator>&                         __s, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __flags | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_match_debug(__s.begin(), __s.end(), __re, __flags); } | 
|  |  | 
|  | // regex_match_debug behaves like regex_match, but will run *two* executors | 
|  | // (if there's no back-reference) and check if their results agree. If not, | 
|  | // an exception throws. One can use them just in the way of using regex_match. | 
|  | template<typename _Bi_iter, typename _Alloc, | 
|  | typename _Ch_type, typename _Rx_traits> | 
|  | bool | 
|  | regex_search_debug(_Bi_iter                                 __s, | 
|  | _Bi_iter                                 __e, | 
|  | match_results<_Bi_iter, _Alloc>&         __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type   __flags | 
|  | = std::regex_constants::match_default) | 
|  | { | 
|  | using namespace std::__detail; | 
|  | auto __res1 = __regex_algo_impl(__s, __e, __m, __re, __flags, | 
|  | _RegexExecutorPolicy::_S_auto, | 
|  | false); | 
|  | match_results<_Bi_iter, _Alloc> __mm; | 
|  | auto __res2 = __regex_algo_impl(__s, __e, __mm, __re, __flags, | 
|  | _RegexExecutorPolicy::_S_alternate, | 
|  | false); | 
|  | if (__res1 == __res2 && __m == __mm) | 
|  | return __res1; | 
|  | throw(std::exception()); // Let test fail. Give it a name. | 
|  | } | 
|  |  | 
|  | // No match_results version | 
|  | template<typename _Bi_iter, typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_search_debug(_Bi_iter                                 __first, | 
|  | _Bi_iter                                 __last, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __re, | 
|  | match_flag_type                          __flags | 
|  | = std::regex_constants::match_default) | 
|  | { | 
|  | match_results<_Bi_iter> __what; | 
|  | return regex_search_debug(__first, __last, __what, __re, __flags); | 
|  | } | 
|  |  | 
|  | // C-string version | 
|  | template<typename _Ch_type, class _Alloc, class _Rx_traits> | 
|  | inline bool | 
|  | regex_search_debug(const _Ch_type*                          __s, | 
|  | match_results<const _Ch_type*, _Alloc>&  __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __e, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_search_debug(__s, __s + _Rx_traits::length(__s), | 
|  | __m, __e, __f); } | 
|  |  | 
|  | // C-string version without match_results | 
|  | template<typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_search_debug(const _Ch_type*                          __s, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __e, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_search_debug(__s, __s + _Rx_traits::length(__s), | 
|  | __e, __f); } | 
|  |  | 
|  | // std::basic_string version | 
|  | template<typename _Ch_traits, typename _Ch_alloc, | 
|  | typename _Alloc, typename _Ch_type, | 
|  | typename _Rx_traits> | 
|  | inline bool | 
|  | regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits, | 
|  | _Ch_alloc>& __s, | 
|  | match_results<typename std::basic_string<_Ch_type, | 
|  | _Ch_traits, _Ch_alloc>::const_iterator, _Alloc>& | 
|  | __m, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __e, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_search_debug(__s.begin(), __s.end(), __m, __e, __f); } | 
|  |  | 
|  | // std::basic_string version without match_results | 
|  | template<typename _Ch_traits, typename _String_allocator, | 
|  | typename _Ch_type, typename _Rx_traits> | 
|  | inline bool | 
|  | regex_search_debug(const std::basic_string<_Ch_type, _Ch_traits, | 
|  | _String_allocator>&                      __s, | 
|  | const basic_regex<_Ch_type, _Rx_traits>& __e, | 
|  | match_flag_type                          __f | 
|  | = std::regex_constants::match_default) | 
|  | { return regex_search_debug(__s.begin(), __s.end(), __e, __f); } | 
|  |  | 
|  | } // namespace __gnu_test | 
|  | #endif |