Hi
I abandon the idea of providing Debug algos, it would be too much
code to add and maintain. However I haven't quit on reducing Debug mode
performance impact.
So this patch make use of the existing std::__niter_base to get rid
of the debug layer around __gnu_debug::vector<>::iterator so that
__builtin_memmove replacement can take place.
As _Safe_iterator<> do not have a constructor taking a pointer I
change algos implementation so that we do not try to instantiate the
iterator type ourselves but rather rely on its operators + or -.
The small drawback is that for std::equal algo where we can't use
the __glibcxx_can_increment we need to keep the debug layer to make sure
we don't reach past-the-end iterator. So I had to remove usage of
__niter_base when in Debug mode, doing so it also disable potential
usage of __builtin_memcmp when calling std::equal on
std::__cxx1998::vector<> iterators. A rather rare situation I think.
Note that I don't know how to test that __builtin_memmove has been
indeed used. So I've been through some debug sessions to check that.
I am not really happy with ChangeLog entry I came up with, I'll try
to improve it before this patch is validated.
* include/bits/stl_algobase.h
(__copy_move<_IsMove, _IsSimple, random_access_iterator_tag>
::__copy_impl): New.
(__copy_move<_IsMove, _IsSimple, random_access_iterator_tag>
::__copy_m): Use latter.
(__copy_move<_IsMove, true, random_access_iterator_tag>::__copy_m):
Add __base_res parameter.
(__copy_move<_IsMove, true, random_access_iterator_tag>::__copy_m): Add
__res_base parameter and use it to call __builtin_memmove.
(__copy_move_a): Adapt.
(__copy_move_a2): Adapt.
(__copy_move_backward<_IsMove, _IsSimple, random_access_iterator_tag>
::__copy_b_impl): New.
(__copy_move_backward<_IsMove, _IsSimple, random_access_iterator_tag>
::__copy_move_b): Use latter.
(__copy_move_backward<_IsMove, true, random_access_iterator_tag>
::__copy_move_b): Add __res_base parameter and use it to call
__builtin_memmove.
(__copy_move_backward_a): Adapt.
(__copy_move_backward_a2): Adapt.
(__fill_n_a): Add _OI template parameter.
(std::equal<>(_II1, _II1, _II2)): Remove usage of __niter_base on
__first2 in _GLIBCXX_DEBUG mode.
* include/debug/stl_iterator.h
(std::__niter_base(const __gnu_cxx::_Safe_iterator<
__gnu_cxx::__normal_iterator<>, _Sequence>&)): New declaration.
* include/debug/vector (__niter_base(const __gnu_cxx::_Safe_iterator<
__gnu_cxx::__normal_iterator<>, _Sequence>&)): New.
Tested under x86_64 linux.
Ok to commit ?
François
diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h
index d429943..100676b 100644
--- a/libstdc++-v3/include/bits/stl_algobase.h
+++ b/libstdc++-v3/include/bits/stl_algobase.h
@@ -286,9 +286,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool, bool, typename>
struct __copy_move
{
- template<typename _II, typename _OI>
+ template<typename _II, typename _OI, typename _OIBase>
static _OI
- __copy_m(_II __first, _II __last, _OI __result)
+ __copy_m(_II __first, _II __last, _OI __result, _OIBase)
{
for (; __first != __last; ++__result, (void)++__first)
*__result = *__first;
@@ -300,9 +300,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Category>
struct __copy_move<true, false, _Category>
{
- template<typename _II, typename _OI>
+ template<typename _II, typename _OI, typename _OIBase>
static _OI
- __copy_m(_II __first, _II __last, _OI __result)
+ __copy_m(_II __first, _II __last, _OI __result, _OIBase)
{
for (; __first != __last; ++__result, (void)++__first)
*__result = std::move(*__first);
@@ -314,9 +314,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<>
struct __copy_move<false, false, random_access_iterator_tag>
{
+ private:
template<typename _II, typename _OI>
static _OI
- __copy_m(_II __first, _II __last, _OI __result)
+ __copy_impl(_II __first, _II __last, _OI __result)
{
typedef typename iterator_traits<_II>::difference_type _Distance;
for (_Distance __n = __last - __first; __n > 0; --__n)
@@ -327,15 +328,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
return __result;
}
+
+ public:
+ template<typename _II, typename _OI>
+ static _OI
+ __copy_m(_II __first, _II __last, _OI __result, _OI)
+ { return __copy_impl(__first, __last, __result); }
+
+ template<typename _II, typename _OI, typename _OIBase>
+ static _OI
+ __copy_m(_II __first, _II __last, _OI __result, _OIBase __res_base)
+ {
+ _OIBase __end = __copy_impl(__first, __last, __res_base);
+ return __result + (__end - __res_base);
+ }
};
#if __cplusplus >= 201103L
template<>
struct __copy_move<true, false, random_access_iterator_tag>
{
+ private:
template<typename _II, typename _OI>
static _OI
- __copy_m(_II __first, _II __last, _OI __result)
+ __copy_impl(_II __first, _II __last, _OI __result)
{
typedef typename iterator_traits<_II>::difference_type _Distance;
for (_Distance __n = __last - __first; __n > 0; --__n)
@@ -346,15 +362,30 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
return __result;
}
+
+ public:
+ template<typename _II, typename _OI>
+ static _OI
+ __copy_m(_II __first, _II __last, _OI __result, _OI)
+ { return __copy_impl(__first, __last, __result); }
+
+ template<typename _II, typename _OI, typename _OIBase>
+ static _OI
+ __copy_m(_II __first, _II __last, _OI __result, _OIBase __res_base)
+ {
+ _OIBase __end = __copy_impl(__first, __last, __res_base);
+ return __result + (__end - __res_base);
+ }
};
#endif
template<bool _IsMove>
struct __copy_move<_IsMove, true, random_access_iterator_tag>
{
- template<typename _Tp>
- static _Tp*
- __copy_m(const _Tp* __first, const _Tp* __last, _Tp* __result)
+ template<typename _Tp, typename _OI>
+ static _OI
+ __copy_m(const _Tp* __first, const _Tp* __last, _OI __result,
+ _Tp* __res_base)
{
#if __cplusplus >= 201103L
using __assignable = conditional<_IsMove,
@@ -365,25 +396,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
const ptrdiff_t _Num = __last - __first;
if (_Num)
- __builtin_memmove(__result, __first, sizeof(_Tp) * _Num);
+ __builtin_memmove(__res_base, __first, sizeof(_Tp) * _Num);
return __result + _Num;
}
};
- template<bool _IsMove, typename _II, typename _OI>
+ template<bool _IsMove, typename _II, typename _OI, typename _OIBase>
inline _OI
- __copy_move_a(_II __first, _II __last, _OI __result)
+ __copy_move_a(_II __first, _II __last, _OI __result, _OIBase __res_base)
{
typedef typename iterator_traits<_II>::value_type _ValueTypeI;
- typedef typename iterator_traits<_OI>::value_type _ValueTypeO;
+ typedef typename iterator_traits<_OIBase>::value_type _ValueTypeO;
typedef typename iterator_traits<_II>::iterator_category _Category;
const bool __simple = (__is_trivial(_ValueTypeI)
&& __is_pointer<_II>::__value
- && __is_pointer<_OI>::__value
+ && __is_pointer<_OIBase>::__value
&& __are_same<_ValueTypeI, _ValueTypeO>::__value);
- return std::__copy_move<_IsMove, __simple,
- _Category>::__copy_m(__first, __last, __result);
+ return std::__copy_move<_IsMove, __simple, _Category>
+ ::__copy_m(__first, __last, __result, __res_base);
}
// Helpers for streambuf iterators (either istream or ostream).
@@ -419,9 +450,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline _OI
__copy_move_a2(_II __first, _II __last, _OI __result)
{
- return _OI(std::__copy_move_a<_IsMove>(std::__niter_base(__first),
+ return std::__copy_move_a<_IsMove>(std::__niter_base(__first),
std::__niter_base(__last),
- std::__niter_base(__result)));
+ __result,
+ std::__niter_base(__result));
}
/**
@@ -495,9 +527,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<bool, bool, typename>
struct __copy_move_backward
{
- template<typename _BI1, typename _BI2>
+ template<typename _BI1, typename _BI2, typename _BI2Base>
static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result, _BI2Base)
{
while (__first != __last)
*--__result = *--__last;
@@ -509,9 +541,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Category>
struct __copy_move_backward<true, false, _Category>
{
- template<typename _BI1, typename _BI2>
+ template<typename _BI1, typename _BI2, typename _BI2Base>
static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result, _BI2Base)
{
while (__first != __last)
*--__result = std::move(*--__last);
@@ -523,39 +555,72 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<>
struct __copy_move_backward<false, false, random_access_iterator_tag>
{
+ private:
template<typename _BI1, typename _BI2>
static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+ __copy_b_impl(_BI1 __first, _BI1 __last, _BI2 __result)
{
typename iterator_traits<_BI1>::difference_type __n;
for (__n = __last - __first; __n > 0; --__n)
*--__result = *--__last;
return __result;
}
+
+ public:
+ template<typename _BI1, typename _BI2>
+ static _BI2
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result, _BI2)
+ { return __copy_b_impl(__first, __last, __result); }
+
+ template<typename _BI1, typename _BI2, typename _BI2Base>
+ static _BI2
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result,
+ _BI2Base __res_base)
+ {
+ _BI2Base __rend = __copy_b_impl(__first, __last, __res_base);
+ return __result + (__rend - __res_base);
+ }
};
#if __cplusplus >= 201103L
template<>
struct __copy_move_backward<true, false, random_access_iterator_tag>
{
+ private:
template<typename _BI1, typename _BI2>
static _BI2
- __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result)
+ __copy_b_impl(_BI1 __first, _BI1 __last, _BI2 __result)
{
typename iterator_traits<_BI1>::difference_type __n;
for (__n = __last - __first; __n > 0; --__n)
*--__result = std::move(*--__last);
return __result;
}
+
+ public:
+ template<typename _BI1, typename _BI2>
+ static _BI2
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result, _BI2)
+ { return __copy_b_impl(__first, __last, __result); }
+
+ template<typename _BI1, typename _BI2, typename _BI2Base>
+ static _BI2
+ __copy_move_b(_BI1 __first, _BI1 __last, _BI2 __result,
+ _BI2Base __res_base)
+ {
+ _BI2Base __rend = __copy_b_impl(__first, __last, __res_base);
+ return __result + (__rend - __res_base);
+ }
};
#endif
template<bool _IsMove>
struct __copy_move_backward<_IsMove, true, random_access_iterator_tag>
{
- template<typename _Tp>
- static _Tp*
- __copy_move_b(const _Tp* __first, const _Tp* __last, _Tp* __result)
+ template<typename _Tp, typename _BI2>
+ static _BI2
+ __copy_move_b(const _Tp* __first, const _Tp* __last, _BI2 __result,
+ _Tp* __res_base)
{
#if __cplusplus >= 201103L
using __assignable = conditional<_IsMove,
@@ -566,36 +631,35 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#endif
const ptrdiff_t _Num = __last - __first;
if (_Num)
- __builtin_memmove(__result - _Num, __first, sizeof(_Tp) * _Num);
+ __builtin_memmove(__res_base - _Num, __first, sizeof(_Tp) * _Num);
return __result - _Num;
}
};
- template<bool _IsMove, typename _BI1, typename _BI2>
+ template<bool _IsMove, typename _BI1, typename _BI2, typename _BI2Base>
inline _BI2
- __copy_move_backward_a(_BI1 __first, _BI1 __last, _BI2 __result)
+ __copy_move_backward_a(_BI1 __first, _BI1 __last, _BI2 __result,
+ _BI2Base __res_base)
{
typedef typename iterator_traits<_BI1>::value_type _ValueType1;
- typedef typename iterator_traits<_BI2>::value_type _ValueType2;
+ typedef typename iterator_traits<_BI2Base>::value_type _ValueType2;
typedef typename iterator_traits<_BI1>::iterator_category _Category;
const bool __simple = (__is_trivial(_ValueType1)
&& __is_pointer<_BI1>::__value
- && __is_pointer<_BI2>::__value
+ && __is_pointer<_BI2Base>::__value
&& __are_same<_ValueType1, _ValueType2>::__value);
- return std::__copy_move_backward<_IsMove, __simple,
- _Category>::__copy_move_b(__first,
- __last,
- __result);
+ return std::__copy_move_backward<_IsMove, __simple, _Category>
+ ::__copy_move_b(__first, __last, __result, __res_base);
}
template<bool _IsMove, typename _BI1, typename _BI2>
inline _BI2
__copy_move_backward_a2(_BI1 __first, _BI1 __last, _BI2 __result)
{
- return _BI2(std::__copy_move_backward_a<_IsMove>
+ return std::__copy_move_backward_a<_IsMove>
(std::__niter_base(__first), std::__niter_base(__last),
- std::__niter_base(__result)));
+ __result, std::__niter_base(__result));
}
/**
@@ -749,10 +813,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__value);
}
- template<typename _OutputIterator, typename _Size, typename _Tp>
+ template<typename _OutputIterator, typename _OI, typename _Size, typename _Tp>
inline typename
__gnu_cxx::__enable_if<!__is_scalar<_Tp>::__value, _OutputIterator>::__type
- __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
+ __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value, _OI)
{
for (__decltype(__n + 0) __niter = __n;
__niter > 0; --__niter, (void) ++__first)
@@ -760,10 +824,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __first;
}
- template<typename _OutputIterator, typename _Size, typename _Tp>
+ template<typename _OutputIterator, typename _OI, typename _Size, typename _Tp>
inline typename
__gnu_cxx::__enable_if<__is_scalar<_Tp>::__value, _OutputIterator>::__type
- __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value)
+ __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __value, _OI)
{
const _Tp __tmp = __value;
for (__decltype(__n + 0) __niter = __n;
@@ -772,12 +836,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
return __first;
}
- template<typename _Size, typename _Tp>
+ template<typename _OutputIterator, typename _Size, typename _Tp>
inline typename
- __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, _Tp*>::__type
- __fill_n_a(_Tp* __first, _Size __n, const _Tp& __c)
+ __gnu_cxx::__enable_if<__is_byte<_Tp>::__value, _OutputIterator>::__type
+ __fill_n_a(_OutputIterator __first, _Size __n, const _Tp& __c, _Tp* __res)
{
- std::__fill_a(__first, __first + __n, __c);
+ std::__fill_a(__res, __res + __n, __c);
return __first + __n;
}
@@ -804,7 +868,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__glibcxx_function_requires(_OutputIteratorConcept<_OI, _Tp>)
__glibcxx_requires_can_increment(__first, __n);
- return _OI(std::__fill_n_a(std::__niter_base(__first), __n, __value));
+ return std::__fill_n_a(__first, __n, __value, std::__niter_base(__first));
}
template<bool _BoolType>
@@ -1066,7 +1130,11 @@ _GLIBCXX_BEGIN_NAMESPACE_ALGO
return std::__equal_aux(std::__niter_base(__first1),
std::__niter_base(__last1),
+#if _GLIBCXX_DEBUG
+ __first2);
+#else
std::__niter_base(__first2));
+#endif
}
/**
diff --git a/libstdc++-v3/include/debug/stl_iterator.h b/libstdc++-v3/include/debug/stl_iterator.h
index a6a2a76..eca7203 100644
--- a/libstdc++-v3/include/debug/stl_iterator.h
+++ b/libstdc++-v3/include/debug/stl_iterator.h
@@ -120,4 +120,19 @@ namespace __gnu_debug
#endif
}
+#if __cplusplus >= 201103L
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+template<typename _Iterator, typename _Container, typename _Sequence>
+ _Iterator
+ __niter_base(const __gnu_debug::_Safe_iterator<
+ __gnu_cxx::__normal_iterator<_Iterator, _Container>,
+ _Sequence>&);
+
+_GLIBCXX_END_NAMESPACE_VERSION
+}
+#endif
+
#endif
diff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector
index 8d60da3..40a991f 100644
--- a/libstdc++-v3/include/debug/vector
+++ b/libstdc++-v3/include/debug/vector
@@ -783,6 +783,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return std::hash<_GLIBCXX_STD_C::vector<bool, _Alloc>>()(__b); }
};
+ template<typename _Iterator, typename _Container, typename _Sequence>
+ _Iterator
+ __niter_base(const __gnu_debug::_Safe_iterator<
+ __gnu_cxx::__normal_iterator<_Iterator, _Container>,
+ _Sequence>& __it)
+ { return std::__niter_base(__it.base()); }
+
_GLIBCXX_END_NAMESPACE_VERSION
#endif