On 15/09/17 16:39 +0100, Jonathan Wakely wrote:
On 04/09/17 03:31 -0700, Tim Shen via libstdc++ wrote:
This fixes the follow-up comments in 71500.

Back-reference matching is different from other matching, as the
content the back-reference refers to is at "run-time", aka during
regex_match(), not regex() compilation.

For compilation we do have an abstraction layer to catch all
comparison customizations, namely _M_translator in regex_compiler.h.
Until this patch, we don't have an abstraction for "run-time"
matching. I believe that back-reference is the only place that needs
run-time matching, so I just build a _Backref_matcher in
regex_executot.tcc.

Tested on x86_64-linux-gnu.

Thanks!

--
Regards,
Tim Shen

commit a97b7fecd319e031ffc489a956b8cf3dc63eeb26
Author: Tim Shen <tims...@google.com>
Date:   Mon Sep 4 03:19:35 2017 -0700

          PR libstdc++/71500
          * include/bits/regex_executor.tcc: Support icase in
          regex_tratis<...> for back reference matches.
          * testsuite/28_regex/regression.cc: Test case.

diff --git a/libstdc++-v3/include/bits/regex_executor.tcc 
b/libstdc++-v3/include/bits/regex_executor.tcc
index 226e05856e1..f6149fecf9d 100644
--- a/libstdc++-v3/include/bits/regex_executor.tcc
+++ b/libstdc++-v3/include/bits/regex_executor.tcc
@@ -335,6 +335,54 @@ namespace __detail
          _M_states._M_queue(__state._M_next, _M_cur_results);
   }

+  template<typename _BiIter, typename _TraitsT>
+    struct _Backref_matcher
+    {
+      _Backref_matcher(bool __icase, const _TraitsT& __traits)
+      : _M_traits(__traits) { }
+
+      bool
+      _M_apply(_BiIter __expected_begin,
+              _BiIter __expected_end, _BiIter __actual_begin,
+              _BiIter __actual_end)
+      {
+       return _M_traits.transform(__expected_begin, __expected_end)
+           == _M_traits.transform(__actual_begin, __actual_end);
+      }
+
+      const _TraitsT& _M_traits;
+    };
+
+  template<typename _BiIter, typename _CharT>
+    struct _Backref_matcher<_BiIter, std::regex_traits<_CharT>>
+    {
+      using _TraitsT = std::regex_traits<_CharT>;
+      _Backref_matcher(bool __icase, const _TraitsT& __traits)
+      : _M_icase(__icase), _M_traits(__traits) { }
+
+      bool
+      _M_apply(_BiIter __expected_begin,
+              _BiIter __expected_end, _BiIter __actual_begin,
+              _BiIter __actual_end)
+      {
+       if (!_M_icase)
+         return std::equal(__expected_begin, __expected_end,
+                           __actual_begin, __actual_end);

This is only valid in C++14 and higher, because the 4-argument version
of std::equal isn't present in C++11.

+       typedef std::ctype<_CharT> __ctype_type;
+       const auto& __fctyp = use_facet<__ctype_type>(_M_traits.getloc());
+       return std::equal(__expected_begin, __expected_end,
+                         __actual_begin, __actual_end,

Same here.

+                         [this, &__fctyp](_CharT __lhs, _CharT __rhs)
+                         {
+                           return __fctyp.tolower(__lhs)
+                               == __fctyp.tolower(__rhs);
+                         });

We need to rewrite this to check the lengths are equal first, and then
call the 3-argument version of std::equal.

Alternatively, we could move the implementation of the C++14
std::equal overloads to __equal and make that available for C++11.
I'll try that.

Here's a proof of concept patch for that. It's a bit ugly.


diff --git a/libstdc++-v3/include/bits/regex_executor.tcc b/libstdc++-v3/include/bits/regex_executor.tcc
index f6149fecf9d..4b185cc9d1e 100644
--- a/libstdc++-v3/include/bits/regex_executor.tcc
+++ b/libstdc++-v3/include/bits/regex_executor.tcc
@@ -366,17 +366,21 @@ namespace __detail
 	       _BiIter __actual_end)
       {
 	if (!_M_icase)
-	  return std::equal(__expected_begin, __expected_end,
-			    __actual_begin, __actual_end);
+	  return std::__equal4(__expected_begin, __expected_end,
+			       __actual_begin, __actual_end,
+			       std::__iterator_category(__expected_begin),
+			       std::__iterator_category(__actual_begin));
 	typedef std::ctype<_CharT> __ctype_type;
 	const auto& __fctyp = use_facet<__ctype_type>(_M_traits.getloc());
-	return std::equal(__expected_begin, __expected_end,
-			  __actual_begin, __actual_end,
-			  [this, &__fctyp](_CharT __lhs, _CharT __rhs)
-			  {
-			    return __fctyp.tolower(__lhs)
-				== __fctyp.tolower(__rhs);
-			  });
+	return std::__equal4_p(__expected_begin, __expected_end,
+			       __actual_begin, __actual_end,
+			       [this, &__fctyp](_CharT __lhs, _CharT __rhs)
+			       {
+				 return __fctyp.tolower(__lhs)
+				   == __fctyp.tolower(__rhs);
+			       },
+			       std::__iterator_category(__expected_begin),
+			       std::__iterator_category(__actual_begin));
       }
 
       bool _M_icase;
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index f68ecb22b82..b7848b3de99 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -1082,6 +1082,59 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
       return true;
     }
 
+#if __cplusplus >= 201103L
+  template<typename _II1, typename _II2>
+    inline bool
+    __equal4(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2,
+	     random_access_iterator_tag, random_access_iterator_tag)
+    {
+      auto __d1 = std::distance(__first1, __last1);
+      auto __d2 = std::distance(__first2, __last2);
+      if (__d1 != __d2)
+	return false;
+      return _GLIBCXX_STD_A::equal(__first1, __last1, __first2);
+    }
+
+  template<typename _II1, typename _II2, typename _Cat1, typename _Cat2>
+    inline bool
+    __equal4(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2,
+	     _Cat1, _Cat2)
+    {
+      for (; __first1 != __last1 && __first2 != __last2;
+	  ++__first1, (void)++__first2)
+	if (!(*__first1 == *__first2))
+	  return false;
+      return __first1 == __last1 && __first2 == __last2;
+    }
+
+  template<typename _II1, typename _II2, typename _BinaryPredicate>
+    inline bool
+    __equal4_p(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2,
+	       _BinaryPredicate __binary_pred, random_access_iterator_tag,
+	       random_access_iterator_tag)
+    {
+      auto __d1 = std::distance(__first1, __last1);
+      auto __d2 = std::distance(__first2, __last2);
+      if (__d1 != __d2)
+	return false;
+      return _GLIBCXX_STD_A::equal(__first1, __last1, __first2,
+				   __binary_pred);
+    }
+
+  template<typename _II1, typename _II2, typename _BinaryPredicate,
+	   typename _Cat1, typename _Cat2>
+    inline bool
+    __equal4_p(_II1 __first1, _II1 __last1, _II2 __first2, _II2 __last2,
+	       _BinaryPredicate __binary_pred, _Cat1, _Cat2)
+    {
+      for (; __first1 != __last1 && __first2 != __last2;
+	  ++__first1, (void)++__first2)
+	if (!bool(__binary_pred(*__first1, *__first2)))
+	  return false;
+      return __first1 == __last1 && __first2 == __last2;
+    }
+#endif // C++11
+
 #if __cplusplus > 201103L
 
 #define __cpp_lib_robust_nonmodifying_seq_ops 201304
@@ -1112,24 +1165,9 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
       __glibcxx_requires_valid_range(__first1, __last1);
       __glibcxx_requires_valid_range(__first2, __last2);
 
-      using _RATag = random_access_iterator_tag;
-      using _Cat1 = typename iterator_traits<_II1>::iterator_category;
-      using _Cat2 = typename iterator_traits<_II2>::iterator_category;
-      using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
-      if (_RAIters())
-	{
-	  auto __d1 = std::distance(__first1, __last1);
-	  auto __d2 = std::distance(__first2, __last2);
-	  if (__d1 != __d2)
-	    return false;
-	  return _GLIBCXX_STD_A::equal(__first1, __last1, __first2);
-	}
-
-      for (; __first1 != __last1 && __first2 != __last2;
-	  ++__first1, (void)++__first2)
-	if (!(*__first1 == *__first2))
-	  return false;
-      return __first1 == __last1 && __first2 == __last2;
+      return _GLIBCXX_STD_A::__equal4(__first1, __last1, __first2, __last2,
+				      __iterator_category(__first1),
+				      __iterator_category(__first2));
     }
 
   /**
@@ -1159,27 +1197,12 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
       __glibcxx_requires_valid_range(__first1, __last1);
       __glibcxx_requires_valid_range(__first2, __last2);
 
-      using _RATag = random_access_iterator_tag;
-      using _Cat1 = typename iterator_traits<_IIter1>::iterator_category;
-      using _Cat2 = typename iterator_traits<_IIter2>::iterator_category;
-      using _RAIters = __and_<is_same<_Cat1, _RATag>, is_same<_Cat2, _RATag>>;
-      if (_RAIters())
-	{
-	  auto __d1 = std::distance(__first1, __last1);
-	  auto __d2 = std::distance(__first2, __last2);
-	  if (__d1 != __d2)
-	    return false;
-	  return _GLIBCXX_STD_A::equal(__first1, __last1, __first2,
-				       __binary_pred);
-	}
-
-      for (; __first1 != __last1 && __first2 != __last2;
-	  ++__first1, (void)++__first2)
-	if (!bool(__binary_pred(*__first1, *__first2)))
-	  return false;
-      return __first1 == __last1 && __first2 == __last2;
+      return _GLIBCXX_STD_A::__equal4_p(__first1, __last1, __first2, __last2,
+					__binary_pred,
+					__iterator_category(__first1),
+					__iterator_category(__first2));
     }
-#endif
+#endif // C++14
 
   /**
    *  @brief Performs @b dictionary comparison on ranges.

Reply via email to