Patchwork [4/4] std::regex refactoring

login
register
mail settings
Submitter Jonathan Wakely
Date Nov. 8, 2013, 2:31 p.m.
Message ID <CAH6eHdSRGuFm_oMJnjLniZFw2nKdnKncCowOv_o4M7Ud3xgiLQ@mail.gmail.com>
Download mbox | patch
Permalink /patch/289850/
State New
Headers show

Comments

Jonathan Wakely - Nov. 8, 2013, 2:31 p.m.
As I suggested yesterday on the libstdc++ list, this adds an overload
for string and vector iterators to extract a raw pointer and re-use
the _Compiler<const C*,...> specialization, so that std::regex(".")
and std::regex(std::string(".")) and std::regex(std::vector<char>(1,
'.')) only instantiate _Compiler<It,Tr> once.

2013-11-08  Jonathan Wakely  <jwakely.gcc@gmail.com>

        * include/bits/regex_compiler.h (__detail::__compile_nfa): Overload
        so that std::basic_string<C> and std::vector<C> iterators dispatch to
        the const C* compiler.

Tested x86_64-linux, committed to trunk.
commit 76e9d5349657d9eed04d3429dbf7b6527bf03deb
Author: Jonathan Wakely <jwakely.gcc@gmail.com>
Date:   Fri Nov 8 13:33:06 2013 +0000

    	* include/bits/regex_compiler.h (__detail::__compile_nfa): Overload
    	so that std::basic_string<C> and std::vector<C> iterators dispatch to
    	the const C* compiler.
Daniel Krügler - Nov. 8, 2013, 2:51 p.m.
2013/11/8 Jonathan Wakely <jwakely.gcc@gmail.com>:
> As I suggested yesterday on the libstdc++ list, this adds an overload
> for string and vector iterators to extract a raw pointer and re-use
> the _Compiler<const C*,...> specialization, so that std::regex(".")
> and std::regex(std::string(".")) and std::regex(std::vector<char>(1,
> '.')) only instantiate _Compiler<It,Tr> once.
>
> 2013-11-08  Jonathan Wakely  <jwakely.gcc@gmail.com>
>
>         * include/bits/regex_compiler.h (__detail::__compile_nfa): Overload
>         so that std::basic_string<C> and std::vector<C> iterators dispatch to
>         the const C* compiler.

I have fully not grasped for which T the specializations of
__has_contiguous_iter are intended to be used, but given the fact that

+  template<typename _Tp, typename _Alloc>
+    struct __has_contiguous_iter<std::vector<_Tp, _Alloc>>
+    : std::true_type
+    { };

exists I think you really want to exclude any vector<bool, Allocator>
by additionally adding

+  template<typename _Alloc>
+    struct __has_contiguous_iter<std::vector<bool, _Alloc>>
+    : std::false_type
+    { };

- Daniel
Jonathan Wakely - Nov. 8, 2013, 3:41 p.m.
On 8 November 2013 14:51, Daniel Krügler wrote:
> I have fully not grasped for which T the specializations of
> __has_contiguous_iter are intended to be used,

Currently, only std::container iterators passed to a basic_regex
constructor, but in theory the trait could get moved to another header
and used elsewhere in future.

> but given the fact that
>
> +  template<typename _Tp, typename _Alloc>
> +    struct __has_contiguous_iter<std::vector<_Tp, _Alloc>>
> +    : std::true_type
> +    { };
>
> exists I think you really want to exclude any vector<bool, Allocator>
> by additionally adding
>
> +  template<typename _Alloc>
> +    struct __has_contiguous_iter<std::vector<bool, _Alloc>>
> +    : std::false_type
> +    { };

Hmm, I didn't think of that, damn vector<bool>!  It's only needed in
case someone does this:

  std::vector<bool> v;
  std::regex re(v.begin(), v.end());

which would be pretty crazy, but it has well-defined behaviour and
should throw regex_error.

I'll add the specialization, thanks for catching it.
Jonathan Wakely - Nov. 8, 2013, 4:03 p.m.
On 8 November 2013 15:41, Jonathan Wakely wrote:
> On 8 November 2013 14:51, Daniel Krügler wrote:
>> I have fully not grasped for which T the specializations of
>> __has_contiguous_iter are intended to be used,
>
> Currently, only std::container iterators passed to a basic_regex
> constructor, but in theory the trait could get moved to another header
> and used elsewhere in future.

Currently the vector<bool> specialization can never be reached,
because std::vector<bool> doesn't use __gnu_cxx::__normal_iterator
(and trying to pass vector<bool>::iterator to a regex ctor fails
anyway) so this is only a theoretical problem if we re-use
__has_contiguous_iter elsewhere.

Patch

diff --git a/libstdc++-v3/include/bits/regex_compiler.h b/libstdc++-v3/include/bits/regex_compiler.h
index 406d9a9..741098f 100644
--- a/libstdc++-v3/include/bits/regex_compiler.h
+++ b/libstdc++-v3/include/bits/regex_compiler.h
@@ -129,8 +129,40 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _StackT         _M_stack;
     };
 
+  template<typename _Tp>
+    struct __has_contiguous_iter : std::false_type { };
+
+  template<typename _Ch, typename _Tr, typename _Alloc>
+    struct __has_contiguous_iter<std::basic_string<_Ch, _Tr, _Alloc>>
+    : std::true_type
+    { };
+
+  template<typename _Tp, typename _Alloc>
+    struct __has_contiguous_iter<std::vector<_Tp, _Alloc>>
+    : std::true_type
+    { };
+
+  template<typename _Tp>
+    struct __is_contiguous_normal_iter : std::false_type { };
+
+  template<typename _Tp, typename _Cont>
+    struct
+    __is_contiguous_normal_iter<__gnu_cxx::__normal_iterator<_Tp, _Cont>>
+    : __has_contiguous_iter<_Cont>::type
+    { };
+
+  template<typename _Iter, typename _TraitsT>
+    using __enable_if_contiguous_normal_iter
+      = typename enable_if< __is_contiguous_normal_iter<_Iter>::value,
+			    std::shared_ptr<_NFA<_TraitsT>> >::type;
+
+  template<typename _Iter, typename _TraitsT>
+    using __disable_if_contiguous_normal_iter
+      = typename enable_if< !__is_contiguous_normal_iter<_Iter>::value,
+			    std::shared_ptr<_NFA<_TraitsT>> >::type;
+
   template<typename _FwdIter, typename _TraitsT>
-    inline std::shared_ptr<_NFA<_TraitsT>>
+    inline __disable_if_contiguous_normal_iter<_FwdIter, _TraitsT>
     __compile_nfa(_FwdIter __first, _FwdIter __last, const _TraitsT& __traits,
 		  regex_constants::syntax_option_type __flags)
     {
@@ -138,6 +170,16 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
       return _Cmplr(__first, __last, __traits, __flags)._M_get_nfa();
     }
 
+  template<typename _Iter, typename _TraitsT>
+    inline __enable_if_contiguous_normal_iter<_Iter, _TraitsT>
+    __compile_nfa(_Iter __first, _Iter __last, const _TraitsT& __traits,
+		  regex_constants::syntax_option_type __flags)
+    {
+      size_t __len = __last - __first;
+      const auto* __cfirst = __len ? std::__addressof(*__first) : nullptr;
+      return __compile_nfa(__cfirst, __cfirst + __len, __traits, __flags);
+    }
+
   template<typename _TraitsT>
     struct _AnyMatcher
     {