| // -*- C++ -*- |
| // regex utils for the C++ library testsuite. |
| // |
| // Copyright (C) 2012-2021 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<_Bi_iter, _Alloc, _Ch_type, _Rx_traits, |
| _RegexExecutorPolicy::_S_auto, true> |
| (__s, __e, __m, __re, __flags); |
| match_results<_Bi_iter, _Alloc> __mm; |
| auto __res2 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits, |
| _RegexExecutorPolicy::_S_alternate, true> |
| (__s, __e, __mm, __re, __flags); |
| // __m is unspecified if return value is false. |
| if (__res1 == __res2 && (!__res1 || __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<_Bi_iter, _Alloc, _Ch_type, _Rx_traits, |
| _RegexExecutorPolicy::_S_auto, false> |
| (__s, __e, __m, __re, __flags); |
| match_results<_Bi_iter, _Alloc> __mm; |
| auto __res2 = __regex_algo_impl<_Bi_iter, _Alloc, _Ch_type, _Rx_traits, |
| _RegexExecutorPolicy::_S_alternate, false> |
| (__s, __e, __mm, __re, __flags); |
| 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 |