Skip to content

Commit d41c6d5

Browse files
author
Arthur O'Dwyer
committed
[libc++] Rationalize our treatment of contiguous iterators and __unwrap_iter().
- Implement C++20's changes to `reverse_iterator`, so that it won't be accidentally counted as a contiguous iterator in C++20 mode. - Implement C++20's changes to `move_iterator` as well. - `move_iterator` should not be contiguous. This fixes a bug where we optimized `std::copy`-of-move-iterators in an observable way. Add a regression test for that bugfix. - Add libcxx tests for `__is_cpp17_contiguous_iterator` of all relevant standard iterator types. Particularly check that vector::iterator is still considered contiguous in all C++ modes, even C++03. After this patch, there continues to be no supported way to write your own iterator type in C++17-and-earlier such that libc++ will consider it "contiguous"; however, we now fully support the C++20 approach (in C++20 mode only). If you want user-defined contiguous iterators in C++17-and-earlier, libc++'s position is "please upgrade to C++20." Differential Revision: https://reviews.llvm.org/D94807
1 parent 9db6114 commit d41c6d5

File tree

11 files changed

+653
-170
lines changed

11 files changed

+653
-170
lines changed

libcxx/include/__memory/pointer_traits.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,70 @@ struct __rebind_pointer {
162162
#endif
163163
};
164164

165+
// to_address
166+
167+
template <bool _UsePointerTraits> struct __to_address_helper;
168+
169+
template <> struct __to_address_helper<true> {
170+
template <class _Pointer>
171+
using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval<const _Pointer&>()));
172+
173+
template <class _Pointer>
174+
_LIBCPP_CONSTEXPR
175+
static __return_type<_Pointer>
176+
__do_it(const _Pointer &__p) _NOEXCEPT { return pointer_traits<_Pointer>::to_address(__p); }
177+
};
178+
179+
template <class _Pointer, bool _Dummy = true>
180+
using __choose_to_address = __to_address_helper<_IsValidExpansion<__to_address_helper<_Dummy>::template __return_type, _Pointer>::value>;
181+
182+
template <class _Tp>
183+
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
184+
_Tp*
185+
__to_address(_Tp* __p) _NOEXCEPT
186+
{
187+
static_assert(!is_function<_Tp>::value, "_Tp is a function type");
188+
return __p;
189+
}
190+
191+
template <class _Pointer>
192+
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
193+
typename __choose_to_address<_Pointer>::template __return_type<_Pointer>
194+
__to_address(const _Pointer& __p) _NOEXCEPT
195+
{
196+
return __choose_to_address<_Pointer>::__do_it(__p);
197+
}
198+
199+
template <> struct __to_address_helper<false> {
200+
template <class _Pointer>
201+
using __return_type = typename pointer_traits<_Pointer>::element_type*;
202+
203+
template <class _Pointer>
204+
_LIBCPP_CONSTEXPR
205+
static __return_type<_Pointer>
206+
__do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); }
207+
};
208+
209+
210+
#if _LIBCPP_STD_VER > 17
211+
template <class _Tp>
212+
inline _LIBCPP_INLINE_VISIBILITY constexpr
213+
_Tp*
214+
to_address(_Tp* __p) _NOEXCEPT
215+
{
216+
static_assert(!is_function_v<_Tp>, "_Tp is a function type");
217+
return __p;
218+
}
219+
220+
template <class _Pointer>
221+
inline _LIBCPP_INLINE_VISIBILITY constexpr
222+
auto
223+
to_address(const _Pointer& __p) _NOEXCEPT
224+
{
225+
return _VSTD::__to_address(__p);
226+
}
227+
#endif
228+
165229
_LIBCPP_END_NAMESPACE_STD
166230

167231
_LIBCPP_POP_MACROS

libcxx/include/algorithm

Lines changed: 29 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1639,68 +1639,42 @@ search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const
16391639
__value_, __equal_to<__v, _Tp>());
16401640
}
16411641

1642-
// copy
1643-
template <class _Iter>
1644-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
1645-
_Iter
1646-
__unwrap_iter(_Iter __i)
1647-
{
1648-
return __i;
1649-
}
1650-
1651-
template <class _Tp>
1652-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
1653-
typename enable_if
1654-
<
1655-
is_trivially_copy_assignable<_Tp>::value,
1656-
_Tp*
1657-
>::type
1658-
__unwrap_iter(move_iterator<_Tp*> __i)
1659-
{
1660-
return __i.base();
1661-
}
1642+
// __unwrap_iter
1643+
1644+
// The job of __unwrap_iter is to lower iterators-that-are-tantamount-to-pointers
1645+
// (such as vector<T>::iterator) into pointers, to reduce the number of template
1646+
// instantiations and to enable pointer-based optimizations e.g. in std::copy.
1647+
// In debug mode, we don't do this.
1648+
1649+
template <class _Iter, bool = __is_cpp17_contiguous_iterator<_Iter>::value>
1650+
struct __unwrap_iter_impl {
1651+
static _LIBCPP_CONSTEXPR _Iter
1652+
__apply(_Iter __i) _NOEXCEPT {
1653+
return __i;
1654+
}
1655+
};
16621656

16631657
#if _LIBCPP_DEBUG_LEVEL < 2
16641658

1665-
template <class _Tp>
1666-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
1667-
typename enable_if
1668-
<
1669-
is_trivially_copy_assignable<_Tp>::value,
1670-
_Tp*
1671-
>::type
1672-
__unwrap_iter(__wrap_iter<_Tp*> __i)
1673-
{
1674-
return __i.base();
1675-
}
1676-
1677-
template <class _Tp>
1678-
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
1679-
typename enable_if
1680-
<
1681-
is_trivially_copy_assignable<_Tp>::value,
1682-
const _Tp*
1683-
>::type
1684-
__unwrap_iter(__wrap_iter<const _Tp*> __i)
1685-
{
1686-
return __i.base();
1687-
}
1659+
template <class _Iter>
1660+
struct __unwrap_iter_impl<_Iter, true> {
1661+
static _LIBCPP_CONSTEXPR decltype(_VSTD::__to_address(declval<_Iter>()))
1662+
__apply(_Iter __i) _NOEXCEPT {
1663+
return _VSTD::__to_address(__i);
1664+
}
1665+
};
16881666

1689-
#else
1667+
#endif // _LIBCPP_DEBUG_LEVEL < 2
16901668

1691-
template <class _Tp>
1669+
template<class _Iter, class _Impl = __unwrap_iter_impl<_Iter> >
16921670
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
1693-
typename enable_if
1694-
<
1695-
is_trivially_copy_assignable<_Tp>::value,
1696-
__wrap_iter<_Tp*>
1697-
>::type
1698-
__unwrap_iter(__wrap_iter<_Tp*> __i)
1671+
decltype(_Impl::__apply(_VSTD::declval<_Iter>()))
1672+
__unwrap_iter(_Iter __i) _NOEXCEPT
16991673
{
1700-
return __i;
1674+
return _Impl::__apply(__i);
17011675
}
17021676

1703-
#endif // _LIBCPP_DEBUG_LEVEL < 2
1677+
// copy
17041678

17051679
template <class _InputIterator, class _OutputIterator>
17061680
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
@@ -1894,7 +1868,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
18941868
typename enable_if
18951869
<
18961870
is_same<typename remove_const<_Tp>::type, _Up>::value &&
1897-
is_trivially_copy_assignable<_Up>::value,
1871+
is_trivially_move_assignable<_Up>::value,
18981872
_Up*
18991873
>::type
19001874
__move(_Tp* __first, _Tp* __last, _Up* __result)
@@ -1942,7 +1916,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
19421916
typename enable_if
19431917
<
19441918
is_same<typename remove_const<_Tp>::type, _Up>::value &&
1945-
is_trivially_copy_assignable<_Up>::value,
1919+
is_trivially_move_assignable<_Up>::value,
19461920
_Up*
19471921
>::type
19481922
__move_backward(_Tp* __first, _Tp* __last, _Up* __result)

libcxx/include/filesystem

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T
14951495
"'char' or 'char8_t'");
14961496
#if defined(_LIBCPP_WIN32API)
14971497
using _Traits = __is_pathable<_Source>;
1498-
return u8path(__unwrap_iter(_Traits::__range_begin(__s)), __unwrap_iter(_Traits::__range_end(__s)));
1498+
return u8path(_VSTD::__unwrap_iter(_Traits::__range_begin(__s)), _VSTD::__unwrap_iter(_Traits::__range_end(__s)));
14991499
#else
15001500
return path(__s);
15011501
#endif

0 commit comments

Comments
 (0)