I've split this out of "Refactor std::uninitialized_{copy, fill, fill_n}" because this part can be done separately. Call it [PATCH -1/7] if you like :-)
This fixes the ordering problem that Patrick noticed in [PATCH 1/7], and adds a test for it. It also updates the comments as was previously done in [PATCH 2/7], which Patrick noted could have been done when moving the functions into stl_iterator.h. Note that the __niter_base overloads for reverse_iterator and move_iterator call __niter_base unqualified, which means that in contrast to all other uses of __niter_base they *do* use ADL to find the next __niter_base to call. I think that's necessary so that it works for both reverse_iterator<move_iterator<I>> and the inverse order, move_iterator<reverse_iterator<I>>. I haven't changed that here, they still use unqualified calls. As a further change in this area, I think it would be possible (and maybe nice) to remove __miter_base and replace the uses of it in std::move_backward(I,I,O) and std::move(I,I,O). That's left for another day. Tested x86_64-linux. -- >8 -- Move the functions for unwrapping and rewrapping __normal_iterator objects to the same file as the definition of __normal_iterator itself. This will allow a later commit to make use of std::__niter_base in other headers without having to include all of <bits/stl_algobase.h>. libstdc++-v3/ChangeLog: * include/bits/stl_algobase.h (__niter_base, __niter_wrap): Move to ... * include/bits/stl_iterator.h: ... here. (__niter_base, __miter_base): Move all overloads to the end of the header. * testsuite/24_iterators/normal_iterator/wrapping.cc: New test. --- libstdc++-v3/include/bits/stl_algobase.h | 45 ------ libstdc++-v3/include/bits/stl_iterator.h | 138 +++++++++++++----- .../24_iterators/normal_iterator/wrapping.cc | 29 ++++ 3 files changed, 132 insertions(+), 80 deletions(-) create mode 100644 libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 384e5fdcdc9..751b7ad119b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -308,51 +308,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION return __a; } - // Fallback implementation of the function in bits/stl_iterator.h used to - // remove the __normal_iterator wrapper. See copy, fill, ... - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - inline _Iterator - __niter_base(_Iterator __it) - _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) - { return __it; } - -#if __cplusplus < 201103L - template<typename _Ite, typename _Seq> - _Ite - __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, - std::random_access_iterator_tag>&); - - template<typename _Ite, typename _Cont, typename _Seq> - _Ite - __niter_base(const ::__gnu_debug::_Safe_iterator< - ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq, - std::random_access_iterator_tag>&); -#else - template<typename _Ite, typename _Seq> - _GLIBCXX20_CONSTEXPR - decltype(std::__niter_base(std::declval<_Ite>())) - __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, - std::random_access_iterator_tag>&) - noexcept(std::is_nothrow_copy_constructible<_Ite>::value); -#endif - - // Reverse the __niter_base transformation to get a - // __normal_iterator back again (this assumes that __normal_iterator - // is only used to wrap random access iterators, like pointers). - template<typename _From, typename _To> - _GLIBCXX20_CONSTEXPR - inline _From - __niter_wrap(_From __from, _To __res) - { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); } - - // No need to wrap, iterator already has the right type. - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - inline _Iterator - __niter_wrap(const _Iterator&, _Iterator __res) - { return __res; } - // All of these auxiliary structs serve two purposes. (1) Replace // calls to copy with memmove whenever possible. (Memmove, not memcpy, // because the input and output ranges are permitted to overlap.) diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 28a600c81cb..be3fa6f7a34 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -654,24 +654,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION # endif // C++20 # endif // __glibcxx_make_reverse_iterator - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - auto - __niter_base(reverse_iterator<_Iterator> __it) - -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) - { return __make_reverse_iterator(__niter_base(__it.base())); } - template<typename _Iterator> struct __is_move_iterator<reverse_iterator<_Iterator> > : __is_move_iterator<_Iterator> { }; - - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - auto - __miter_base(reverse_iterator<_Iterator> __it) - -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) - { return __make_reverse_iterator(__miter_base(__it.base())); } #endif // C++11 // 24.4.2.2.1 back_insert_iterator @@ -1336,19 +1322,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return __normal_iterator<_Iterator, _Container>(__i.base() + __n); } _GLIBCXX_END_NAMESPACE_VERSION -} // namespace +} // namespace __gnu_cxx namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION - template<typename _Iterator, typename _Container> - _GLIBCXX20_CONSTEXPR - _Iterator - __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) - _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) - { return __it.base(); } - #if __cplusplus >= 201103L && __cplusplus <= 201703L // Need to overload __to_address because the pointer_traits primary template // will deduce element_type of __normal_iterator<T*, C> as T* rather than T. @@ -1820,13 +1799,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __make_move_if_noexcept_iterator(_Tp* __i) { return _ReturnType(__i); } - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - auto - __niter_base(move_iterator<_Iterator> __it) - -> decltype(make_move_iterator(__niter_base(__it.base()))) - { return make_move_iterator(__niter_base(__it.base())); } - template<typename _Iterator> struct __is_move_iterator<move_iterator<_Iterator> > { @@ -1834,12 +1806,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typedef __true_type __type; }; - template<typename _Iterator> - _GLIBCXX20_CONSTEXPR - auto - __miter_base(move_iterator<_Iterator> __it) - -> decltype(__miter_base(__it.base())) - { return __miter_base(__it.base()); } #define _GLIBCXX_MAKE_MOVE_ITERATOR(_Iter) std::make_move_iterator(_Iter) #define _GLIBCXX_MAKE_MOVE_IF_NOEXCEPT_ITERATOR(_Iter) \ @@ -2985,6 +2951,108 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @} group iterators +_GLIBCXX_END_NAMESPACE_VERSION +} // namespace std + +namespace __gnu_debug +{ + template<typename _Iterator, typename _Sequence, typename _Category> + class _Safe_iterator; +} + +namespace std _GLIBCXX_VISIBILITY(default) +{ +_GLIBCXX_BEGIN_NAMESPACE_VERSION + /// @cond undocumented + + // Unwrap a __normal_iterator to get the underlying iterator + // (usually a pointer). See uses in std::copy, std::fill, etc. + template<typename _Iterator, typename _Container> + _GLIBCXX20_CONSTEXPR + _Iterator + __niter_base(__gnu_cxx::__normal_iterator<_Iterator, _Container> __it) + _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) + { return __it.base(); } + + // Fallback implementation used for iterators that can't be unwrapped. + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + inline _Iterator + __niter_base(_Iterator __it) + _GLIBCXX_NOEXCEPT_IF(std::is_nothrow_copy_constructible<_Iterator>::value) + { return __it; } + + // Overload for _Safe_iterator needs to be declared before uses of + // std::__niter_base because we call it qualified so isn't found by ADL. +#if __cplusplus < 201103L + template<typename _Ite, typename _Seq> + _Ite + __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, + std::random_access_iterator_tag>&); + + template<typename _Ite, typename _Cont, typename _Seq> + _Ite + __niter_base(const ::__gnu_debug::_Safe_iterator< + ::__gnu_cxx::__normal_iterator<_Ite, _Cont>, _Seq, + std::random_access_iterator_tag>&); +#else + template<typename _Ite, typename _Seq> + _GLIBCXX20_CONSTEXPR + decltype(std::__niter_base(std::declval<_Ite>())) + __niter_base(const ::__gnu_debug::_Safe_iterator<_Ite, _Seq, + std::random_access_iterator_tag>&) + noexcept(std::is_nothrow_copy_constructible<_Ite>::value); +#endif + +#if __cplusplus >= 201103L + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + auto + __niter_base(reverse_iterator<_Iterator> __it) + -> decltype(__make_reverse_iterator(__niter_base(__it.base()))) + { return __make_reverse_iterator(__niter_base(__it.base())); } + + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + auto + __niter_base(move_iterator<_Iterator> __it) + -> decltype(make_move_iterator(__niter_base(__it.base()))) + { return make_move_iterator(__niter_base(__it.base())); } + + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + auto + __miter_base(reverse_iterator<_Iterator> __it) + -> decltype(__make_reverse_iterator(__miter_base(__it.base()))) + { return __make_reverse_iterator(__miter_base(__it.base())); } + + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + auto + __miter_base(move_iterator<_Iterator> __it) + -> decltype(__miter_base(__it.base())) + { return __miter_base(__it.base()); } +#endif + + // Reverse the __niter_base transformation to get a __normal_iterator + // back again (this assumes that __normal_iterator is only used to wrap + // random access iterators, like pointers). + // All overloads of std::__niter_base must be declared before this. + template<typename _From, typename _To> + _GLIBCXX20_CONSTEXPR + inline _From + __niter_wrap(_From __from, _To __res) + { return __from + (std::__niter_base(__res) - std::__niter_base(__from)); } + + // No need to wrap, iterator already has the right type. + template<typename _Iterator> + _GLIBCXX20_CONSTEXPR + inline _Iterator + __niter_wrap(const _Iterator&, _Iterator __res) + { return __res; } + + /// @endcond + #if __cpp_deduction_guides >= 201606 // These helper traits are used for deduction guides // of associative containers. diff --git a/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc b/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc new file mode 100644 index 00000000000..bbfd4264a36 --- /dev/null +++ b/libstdc++-v3/testsuite/24_iterators/normal_iterator/wrapping.cc @@ -0,0 +1,29 @@ +#include <iterator> +#include <algorithm> +#include <vector> +#ifndef _GLIBCXX_DEBUG +#include <debug/vector> +#endif + +struct S { }; + +int main() +{ + S s[1]; + std::vector<S> v(1); + std::copy(s, s, v.rbegin()); +#if __cplusplus >= 201103L + std::copy(s, s, std::make_move_iterator(v.begin())); + std::copy(s, s, std::make_move_iterator(v.rbegin())); +#endif + +#ifndef _GLIBCXX_DEBUG + __gnu_debug::vector<S> dv(1); + std::copy(s, s, dv.rbegin()); +#if __cplusplus >= 201103L + std::copy(s, s, std::make_move_iterator(dv.begin())); + std::copy(s, s, std::make_move_iterator(dv.rbegin())); +#endif +#endif +} + -- 2.46.2