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