forked from OSchip/llvm-project
[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
This commit is contained in:
parent
9db6114296
commit
d41c6d51cb
|
@ -162,6 +162,70 @@ struct __rebind_pointer {
|
|||
#endif
|
||||
};
|
||||
|
||||
// to_address
|
||||
|
||||
template <bool _UsePointerTraits> struct __to_address_helper;
|
||||
|
||||
template <> struct __to_address_helper<true> {
|
||||
template <class _Pointer>
|
||||
using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval<const _Pointer&>()));
|
||||
|
||||
template <class _Pointer>
|
||||
_LIBCPP_CONSTEXPR
|
||||
static __return_type<_Pointer>
|
||||
__do_it(const _Pointer &__p) _NOEXCEPT { return pointer_traits<_Pointer>::to_address(__p); }
|
||||
};
|
||||
|
||||
template <class _Pointer, bool _Dummy = true>
|
||||
using __choose_to_address = __to_address_helper<_IsValidExpansion<__to_address_helper<_Dummy>::template __return_type, _Pointer>::value>;
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
_Tp*
|
||||
__to_address(_Tp* __p) _NOEXCEPT
|
||||
{
|
||||
static_assert(!is_function<_Tp>::value, "_Tp is a function type");
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <class _Pointer>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename __choose_to_address<_Pointer>::template __return_type<_Pointer>
|
||||
__to_address(const _Pointer& __p) _NOEXCEPT
|
||||
{
|
||||
return __choose_to_address<_Pointer>::__do_it(__p);
|
||||
}
|
||||
|
||||
template <> struct __to_address_helper<false> {
|
||||
template <class _Pointer>
|
||||
using __return_type = typename pointer_traits<_Pointer>::element_type*;
|
||||
|
||||
template <class _Pointer>
|
||||
_LIBCPP_CONSTEXPR
|
||||
static __return_type<_Pointer>
|
||||
__do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); }
|
||||
};
|
||||
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
_Tp*
|
||||
to_address(_Tp* __p) _NOEXCEPT
|
||||
{
|
||||
static_assert(!is_function_v<_Tp>, "_Tp is a function type");
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <class _Pointer>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
auto
|
||||
to_address(const _Pointer& __p) _NOEXCEPT
|
||||
{
|
||||
return _VSTD::__to_address(__p);
|
||||
}
|
||||
#endif
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
_LIBCPP_POP_MACROS
|
||||
|
|
|
@ -1639,69 +1639,43 @@ search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const
|
|||
__value_, __equal_to<__v, _Tp>());
|
||||
}
|
||||
|
||||
// copy
|
||||
template <class _Iter>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
_Iter
|
||||
__unwrap_iter(_Iter __i)
|
||||
{
|
||||
return __i;
|
||||
}
|
||||
// __unwrap_iter
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
_Tp*
|
||||
>::type
|
||||
__unwrap_iter(move_iterator<_Tp*> __i)
|
||||
{
|
||||
return __i.base();
|
||||
}
|
||||
// The job of __unwrap_iter is to lower iterators-that-are-tantamount-to-pointers
|
||||
// (such as vector<T>::iterator) into pointers, to reduce the number of template
|
||||
// instantiations and to enable pointer-based optimizations e.g. in std::copy.
|
||||
// In debug mode, we don't do this.
|
||||
|
||||
template <class _Iter, bool = __is_cpp17_contiguous_iterator<_Iter>::value>
|
||||
struct __unwrap_iter_impl {
|
||||
static _LIBCPP_CONSTEXPR _Iter
|
||||
__apply(_Iter __i) _NOEXCEPT {
|
||||
return __i;
|
||||
}
|
||||
};
|
||||
|
||||
#if _LIBCPP_DEBUG_LEVEL < 2
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
_Tp*
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*> __i)
|
||||
{
|
||||
return __i.base();
|
||||
}
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
const _Tp*
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<const _Tp*> __i)
|
||||
{
|
||||
return __i.base();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
__wrap_iter<_Tp*>
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*> __i)
|
||||
{
|
||||
return __i;
|
||||
}
|
||||
template <class _Iter>
|
||||
struct __unwrap_iter_impl<_Iter, true> {
|
||||
static _LIBCPP_CONSTEXPR decltype(_VSTD::__to_address(declval<_Iter>()))
|
||||
__apply(_Iter __i) _NOEXCEPT {
|
||||
return _VSTD::__to_address(__i);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _LIBCPP_DEBUG_LEVEL < 2
|
||||
|
||||
template<class _Iter, class _Impl = __unwrap_iter_impl<_Iter> >
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
decltype(_Impl::__apply(_VSTD::declval<_Iter>()))
|
||||
__unwrap_iter(_Iter __i) _NOEXCEPT
|
||||
{
|
||||
return _Impl::__apply(__i);
|
||||
}
|
||||
|
||||
// copy
|
||||
|
||||
template <class _InputIterator, class _OutputIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
|
||||
_OutputIterator
|
||||
|
@ -1894,7 +1868,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
|||
typename enable_if
|
||||
<
|
||||
is_same<typename remove_const<_Tp>::type, _Up>::value &&
|
||||
is_trivially_copy_assignable<_Up>::value,
|
||||
is_trivially_move_assignable<_Up>::value,
|
||||
_Up*
|
||||
>::type
|
||||
__move(_Tp* __first, _Tp* __last, _Up* __result)
|
||||
|
@ -1942,7 +1916,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
|||
typename enable_if
|
||||
<
|
||||
is_same<typename remove_const<_Tp>::type, _Up>::value &&
|
||||
is_trivially_copy_assignable<_Up>::value,
|
||||
is_trivially_move_assignable<_Up>::value,
|
||||
_Up*
|
||||
>::type
|
||||
__move_backward(_Tp* __first, _Tp* __last, _Up* __result)
|
||||
|
|
|
@ -1495,7 +1495,7 @@ _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_WITH_CHAR8_T
|
|||
"'char' or 'char8_t'");
|
||||
#if defined(_LIBCPP_WIN32API)
|
||||
using _Traits = __is_pathable<_Source>;
|
||||
return u8path(__unwrap_iter(_Traits::__range_begin(__s)), __unwrap_iter(_Traits::__range_end(__s)));
|
||||
return u8path(_VSTD::__unwrap_iter(_Traits::__range_begin(__s)), _VSTD::__unwrap_iter(_Traits::__range_end(__s)));
|
||||
#else
|
||||
return path(__s);
|
||||
#endif
|
||||
|
|
|
@ -421,6 +421,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
|
|||
#include <cstddef>
|
||||
#include <initializer_list>
|
||||
#include <__memory/base.h>
|
||||
#include <__memory/pointer_traits.h>
|
||||
#include <version>
|
||||
|
||||
#include <__debug>
|
||||
|
@ -439,9 +440,7 @@ struct _LIBCPP_TEMPLATE_VIS forward_iterator_tag : public input_iterator_t
|
|||
struct _LIBCPP_TEMPLATE_VIS bidirectional_iterator_tag : public forward_iterator_tag {};
|
||||
struct _LIBCPP_TEMPLATE_VIS random_access_iterator_tag : public bidirectional_iterator_tag {};
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
// TODO(EricWF) contiguous_iterator_tag is provided as an extension prior to
|
||||
// C++20 to allow optimizations for users providing wrapped iterator types.
|
||||
struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag: public random_access_iterator_tag { };
|
||||
struct _LIBCPP_TEMPLATE_VIS contiguous_iterator_tag : public random_access_iterator_tag {};
|
||||
#endif
|
||||
|
||||
template <class _Iter>
|
||||
|
@ -517,6 +516,17 @@ public:
|
|||
static const bool value = sizeof(__test<_Tp>(nullptr)) == 1;
|
||||
};
|
||||
|
||||
template <class _Tp>
|
||||
struct __has_iterator_concept
|
||||
{
|
||||
private:
|
||||
struct __two {char __lx; char __lxx;};
|
||||
template <class _Up> static __two __test(...);
|
||||
template <class _Up> static char __test(typename _Up::iterator_concept* = nullptr);
|
||||
public:
|
||||
static const bool value = sizeof(__test<_Tp>(nullptr)) == 1;
|
||||
};
|
||||
|
||||
template <class _Iter, bool> struct __iterator_traits_impl {};
|
||||
|
||||
template <class _Iter>
|
||||
|
@ -568,11 +578,19 @@ struct _LIBCPP_TEMPLATE_VIS iterator_traits<_Tp*>
|
|||
|
||||
template <class _Tp, class _Up, bool = __has_iterator_category<iterator_traits<_Tp> >::value>
|
||||
struct __has_iterator_category_convertible_to
|
||||
: public integral_constant<bool, is_convertible<typename iterator_traits<_Tp>::iterator_category, _Up>::value>
|
||||
: _BoolConstant<is_convertible<typename iterator_traits<_Tp>::iterator_category, _Up>::value>
|
||||
{};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
struct __has_iterator_category_convertible_to<_Tp, _Up, false> : public false_type {};
|
||||
struct __has_iterator_category_convertible_to<_Tp, _Up, false> : false_type {};
|
||||
|
||||
template <class _Tp, class _Up, bool = __has_iterator_concept<_Tp>::value>
|
||||
struct __has_iterator_concept_convertible_to
|
||||
: _BoolConstant<is_convertible<typename _Tp::iterator_concept, _Up>::value>
|
||||
{};
|
||||
|
||||
template <class _Tp, class _Up>
|
||||
struct __has_iterator_concept_convertible_to<_Tp, _Up, false> : false_type {};
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_cpp17_input_iterator : public __has_iterator_category_convertible_to<_Tp, input_iterator_tag> {};
|
||||
|
@ -586,14 +604,26 @@ struct __is_cpp17_bidirectional_iterator : public __has_iterator_category_conver
|
|||
template <class _Tp>
|
||||
struct __is_cpp17_random_access_iterator : public __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag> {};
|
||||
|
||||
// __is_cpp17_contiguous_iterator determines if an iterator is contiguous,
|
||||
// either because it advertises itself as such (in C++20) or because it
|
||||
// is a pointer type or a known trivial wrapper around a pointer type,
|
||||
// such as __wrap_iter<T*>.
|
||||
//
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
template <class _Tp>
|
||||
struct __is_cpp17_contiguous_iterator : public __has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag> {};
|
||||
struct __is_cpp17_contiguous_iterator : _Or<
|
||||
__has_iterator_category_convertible_to<_Tp, contiguous_iterator_tag>,
|
||||
__has_iterator_concept_convertible_to<_Tp, contiguous_iterator_tag>
|
||||
> {};
|
||||
#else
|
||||
template <class _Tp>
|
||||
struct __is_cpp17_contiguous_iterator : public false_type {};
|
||||
struct __is_cpp17_contiguous_iterator : false_type {};
|
||||
#endif
|
||||
|
||||
// Any native pointer which is an iterator is also a contiguous iterator.
|
||||
template <class _Up>
|
||||
struct __is_cpp17_contiguous_iterator<_Up*> : true_type {};
|
||||
|
||||
|
||||
template <class _Tp>
|
||||
struct __is_exactly_cpp17_input_iterator
|
||||
|
@ -759,6 +789,14 @@ public:
|
|||
typedef typename iterator_traits<_Iter>::difference_type difference_type;
|
||||
typedef typename iterator_traits<_Iter>::reference reference;
|
||||
typedef typename iterator_traits<_Iter>::pointer pointer;
|
||||
typedef _If<__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
random_access_iterator_tag,
|
||||
typename iterator_traits<_Iter>::iterator_category> iterator_category;
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
typedef _If<__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
random_access_iterator_tag,
|
||||
bidirectional_iterator_tag> iterator_concept;
|
||||
#endif
|
||||
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
reverse_iterator() : __t(), current() {}
|
||||
|
@ -1206,10 +1244,16 @@ private:
|
|||
_Iter __i;
|
||||
public:
|
||||
typedef _Iter iterator_type;
|
||||
typedef typename iterator_traits<iterator_type>::iterator_category iterator_category;
|
||||
typedef typename iterator_traits<iterator_type>::value_type value_type;
|
||||
typedef typename iterator_traits<iterator_type>::difference_type difference_type;
|
||||
typedef iterator_type pointer;
|
||||
typedef _If<__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
random_access_iterator_tag,
|
||||
typename iterator_traits<_Iter>::iterator_category> iterator_category;
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
typedef input_iterator_tag iterator_concept;
|
||||
#endif
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
typedef typename iterator_traits<iterator_type>::reference __reference;
|
||||
typedef typename conditional<
|
||||
|
@ -1393,40 +1437,21 @@ template <class _B1, class _B2> _B2 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_
|
|||
template <class _Ip, class _Op> _Op _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 move(_Ip, _Ip, _Op);
|
||||
template <class _B1, class _B2> _B2 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 move_backward(_B1, _B1, _B2);
|
||||
|
||||
#if _LIBCPP_DEBUG_LEVEL < 2
|
||||
|
||||
template <class _Tp>
|
||||
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
_Tp*
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*>);
|
||||
|
||||
#else
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
__wrap_iter<_Tp*>
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*> __i);
|
||||
|
||||
#endif
|
||||
|
||||
template <class _Iter>
|
||||
class __wrap_iter
|
||||
{
|
||||
public:
|
||||
typedef _Iter iterator_type;
|
||||
typedef typename iterator_traits<iterator_type>::iterator_category iterator_category;
|
||||
typedef typename iterator_traits<iterator_type>::value_type value_type;
|
||||
typedef typename iterator_traits<iterator_type>::difference_type difference_type;
|
||||
typedef typename iterator_traits<iterator_type>::pointer pointer;
|
||||
typedef typename iterator_traits<iterator_type>::reference reference;
|
||||
typedef typename iterator_traits<iterator_type>::iterator_category iterator_category;
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
typedef _If<__is_cpp17_contiguous_iterator<_Iter>::value,
|
||||
contiguous_iterator_tag, iterator_category> iterator_concept;
|
||||
#endif
|
||||
|
||||
private:
|
||||
iterator_type __i;
|
||||
public:
|
||||
|
@ -1603,28 +1628,20 @@ private:
|
|||
template <class _B1, class _B2> friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _B2 copy_backward(_B1, _B1, _B2);
|
||||
template <class _Ip, class _Op> friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _Op move(_Ip, _Ip, _Op);
|
||||
template <class _B1, class _B2> friend _LIBCPP_CONSTEXPR_AFTER_CXX17 _B2 move_backward(_B1, _B1, _B2);
|
||||
|
||||
#if _LIBCPP_DEBUG_LEVEL < 2
|
||||
template <class _Tp>
|
||||
_LIBCPP_CONSTEXPR friend
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
_Tp*
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*>);
|
||||
#else
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR friend
|
||||
typename enable_if
|
||||
<
|
||||
is_trivially_copy_assignable<_Tp>::value,
|
||||
__wrap_iter<_Tp*>
|
||||
>::type
|
||||
__unwrap_iter(__wrap_iter<_Tp*> __i);
|
||||
#endif
|
||||
};
|
||||
|
||||
#if _LIBCPP_STD_VER <= 17
|
||||
template <class _It>
|
||||
struct __is_cpp17_contiguous_iterator<__wrap_iter<_It> > : __is_cpp17_contiguous_iterator<_It> {};
|
||||
#endif
|
||||
|
||||
template <class _Iter>
|
||||
_LIBCPP_CONSTEXPR
|
||||
_EnableIf<__is_cpp17_contiguous_iterator<_Iter>::value, decltype(_VSTD::__to_address(declval<_Iter>()))>
|
||||
__to_address(__wrap_iter<_Iter> __w) _NOEXCEPT {
|
||||
return _VSTD::__to_address(__w.base());
|
||||
}
|
||||
|
||||
template <class _Iter1, class _Iter2>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_IF_NODEBUG
|
||||
bool
|
||||
|
|
|
@ -722,68 +722,6 @@ _ValueType __libcpp_acquire_load(_ValueType const* __value) {
|
|||
#endif
|
||||
}
|
||||
|
||||
template <bool _UsePointerTraits> struct __to_address_helper;
|
||||
|
||||
template <> struct __to_address_helper<true> {
|
||||
template <class _Pointer>
|
||||
using __return_type = decltype(pointer_traits<_Pointer>::to_address(_VSTD::declval<const _Pointer&>()));
|
||||
|
||||
template <class _Pointer>
|
||||
_LIBCPP_CONSTEXPR
|
||||
static __return_type<_Pointer>
|
||||
__do_it(const _Pointer &__p) _NOEXCEPT { return pointer_traits<_Pointer>::to_address(__p); }
|
||||
};
|
||||
|
||||
template <class _Pointer, bool _Dummy = true>
|
||||
using __choose_to_address = __to_address_helper<_IsValidExpansion<__to_address_helper<_Dummy>::template __return_type, _Pointer>::value>;
|
||||
|
||||
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
_Tp*
|
||||
__to_address(_Tp* __p) _NOEXCEPT
|
||||
{
|
||||
static_assert(!is_function<_Tp>::value, "_Tp is a function type");
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <class _Pointer>
|
||||
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
|
||||
typename __choose_to_address<_Pointer>::template __return_type<_Pointer>
|
||||
__to_address(const _Pointer& __p) _NOEXCEPT {
|
||||
return __choose_to_address<_Pointer>::__do_it(__p);
|
||||
}
|
||||
|
||||
template <> struct __to_address_helper<false> {
|
||||
template <class _Pointer>
|
||||
using __return_type = typename pointer_traits<_Pointer>::element_type*;
|
||||
|
||||
template <class _Pointer>
|
||||
_LIBCPP_CONSTEXPR
|
||||
static __return_type<_Pointer>
|
||||
__do_it(const _Pointer &__p) _NOEXCEPT { return _VSTD::__to_address(__p.operator->()); }
|
||||
};
|
||||
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
template <class _Tp>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
_Tp*
|
||||
to_address(_Tp* __p) _NOEXCEPT
|
||||
{
|
||||
static_assert(!is_function_v<_Tp>, "_Tp is a function type");
|
||||
return __p;
|
||||
}
|
||||
|
||||
template <class _Pointer>
|
||||
inline _LIBCPP_INLINE_VISIBILITY constexpr
|
||||
auto
|
||||
to_address(const _Pointer& __p) _NOEXCEPT
|
||||
{
|
||||
return _VSTD::__to_address(__p);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class _Tp> class allocator;
|
||||
|
||||
#if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS)
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
// <iterator>
|
||||
|
||||
// __is_cpp17_contiguous_iterator<_Tp>
|
||||
|
||||
// __is_cpp17_contiguous_iterator determines if an iterator is contiguous,
|
||||
// either because it advertises itself as such (in C++20) or because it
|
||||
// is a pointer type or a known trivial wrapper around a pointer type,
|
||||
// such as __wrap_iter<T*>.
|
||||
//
|
||||
|
||||
#include <cassert>
|
||||
#include <deque>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
#if TEST_STD_VER >= 17
|
||||
#include <string_view>
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
#include <span>
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
#define DELETE_FUNCTION = delete
|
||||
#else
|
||||
#define DELETE_FUNCTION
|
||||
#endif
|
||||
|
||||
class T; // incomplete
|
||||
|
||||
class my_input_iterator
|
||||
{
|
||||
struct tag : std::input_iterator_tag {};
|
||||
typedef my_input_iterator Self;
|
||||
int *state_;
|
||||
public:
|
||||
typedef tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef int difference_type;
|
||||
typedef int* pointer;
|
||||
typedef int& reference;
|
||||
|
||||
my_input_iterator();
|
||||
reference operator*() const;
|
||||
pointer operator->() const;
|
||||
|
||||
Self& operator++();
|
||||
Self operator++(int);
|
||||
friend bool operator==(const Self&, const Self&);
|
||||
friend bool operator!=(const Self&, const Self&);
|
||||
};
|
||||
|
||||
class my_random_access_iterator
|
||||
{
|
||||
struct tag : std::random_access_iterator_tag {};
|
||||
typedef my_random_access_iterator Self;
|
||||
int *state_;
|
||||
public:
|
||||
typedef tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef int difference_type;
|
||||
typedef int* pointer;
|
||||
typedef int& reference;
|
||||
|
||||
my_random_access_iterator();
|
||||
reference operator*() const;
|
||||
pointer operator->() const;
|
||||
reference operator[](difference_type) const;
|
||||
|
||||
Self& operator++();
|
||||
Self operator++(int);
|
||||
Self& operator--();
|
||||
Self operator--(int);
|
||||
friend Self& operator+=(Self&, difference_type);
|
||||
friend Self& operator-=(Self&, difference_type);
|
||||
friend Self operator+(Self, difference_type);
|
||||
friend Self operator+(difference_type, Self);
|
||||
friend Self operator-(Self, difference_type);
|
||||
friend difference_type operator-(Self, Self);
|
||||
friend bool operator==(const Self&, const Self&);
|
||||
friend bool operator!=(const Self&, const Self&);
|
||||
friend bool operator<(const Self&, const Self&);
|
||||
friend bool operator>(const Self&, const Self&);
|
||||
friend bool operator<=(const Self&, const Self&);
|
||||
friend bool operator>=(const Self&, const Self&);
|
||||
};
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
class my_contiguous_iterator
|
||||
{
|
||||
struct tag : std::contiguous_iterator_tag {};
|
||||
typedef my_contiguous_iterator Self;
|
||||
int *state_;
|
||||
public:
|
||||
typedef tag iterator_category;
|
||||
typedef int value_type;
|
||||
typedef int difference_type;
|
||||
typedef int* pointer;
|
||||
typedef int& reference;
|
||||
typedef int element_type; // enable to_address via pointer_traits
|
||||
|
||||
my_contiguous_iterator();
|
||||
reference operator*() const;
|
||||
pointer operator->() const;
|
||||
reference operator[](difference_type) const;
|
||||
|
||||
Self& operator++();
|
||||
Self operator++(int);
|
||||
Self& operator--();
|
||||
Self operator--(int);
|
||||
friend Self& operator+=(Self&, difference_type);
|
||||
friend Self& operator-=(Self&, difference_type);
|
||||
friend Self operator+(Self, difference_type);
|
||||
friend Self operator+(difference_type, Self);
|
||||
friend Self operator-(Self, difference_type);
|
||||
friend difference_type operator-(Self, Self);
|
||||
friend bool operator==(const Self&, const Self&);
|
||||
friend bool operator!=(const Self&, const Self&);
|
||||
friend bool operator<(const Self&, const Self&);
|
||||
friend bool operator>(const Self&, const Self&);
|
||||
friend bool operator<=(const Self&, const Self&);
|
||||
friend bool operator>=(const Self&, const Self&);
|
||||
};
|
||||
#endif
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
// basic tests
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<char *>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<const char *>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<int *>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<int **>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<T *>::value), "");
|
||||
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<my_input_iterator>::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<my_random_access_iterator>::value), "");
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<my_contiguous_iterator>::value), "");
|
||||
#endif
|
||||
|
||||
// move_iterator changes value category, which makes it pretty sketchy to use in optimized codepaths
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<const char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<int *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<T *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<my_random_access_iterator> >::value), "");
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::move_iterator<my_contiguous_iterator> >::value), "");
|
||||
#endif
|
||||
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<const char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<int *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<T *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<my_random_access_iterator> >::value), "");
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::reverse_iterator<my_contiguous_iterator> >::value), "");
|
||||
#endif
|
||||
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<char *> >::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<const char *> >::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<int *> >::value), "");
|
||||
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<T *> >::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<T *> > >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::reverse_iterator<T *> > >::value), "");
|
||||
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<my_random_access_iterator> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_random_access_iterator> > >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::reverse_iterator<my_random_access_iterator> > >::value), "");
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<my_contiguous_iterator> >::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::__wrap_iter<my_contiguous_iterator> > >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::reverse_iterator<my_contiguous_iterator> > >::value), "");
|
||||
#endif
|
||||
|
||||
// iterators in the libc++ test suite
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<output_iterator <char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<input_iterator <char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<forward_iterator <char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<bidirectional_iterator<char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<random_access_iterator<char *> >::value), "");
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<contiguous_iterator <char *> >::value), "");
|
||||
#endif
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<ThrowingIterator <char *> >::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<NonThrowingIterator <char *> >::value), "");
|
||||
|
||||
//
|
||||
// iterators from libc++'s containers
|
||||
//
|
||||
|
||||
// vector
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::vector<int>::iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::vector<int>::const_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<int>::reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<int>::const_reverse_iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::vector<int>::iterator> >::value), "");
|
||||
|
||||
// string
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::string::iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::string::const_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::string::reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::string::const_reverse_iterator>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::wstring::iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::wstring::const_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::wstring::reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::wstring::const_reverse_iterator>::value), "");
|
||||
|
||||
// deque is random-access but not contiguous
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::deque<int>::iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::deque<int>::const_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::deque<int>::reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::deque<int>::const_reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::deque<int>::iterator> >::value), "");
|
||||
|
||||
// vector<bool> is random-access but not contiguous
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<bool>::iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<bool>::const_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<bool>::reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::vector<bool>::const_reverse_iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::__wrap_iter<std::vector<bool>::iterator> >::value), "");
|
||||
|
||||
#if TEST_STD_VER >= 11
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::initializer_list<int>::iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::initializer_list<int>::const_iterator>::value), "");
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 17
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::string_view::iterator> ::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::string_view::const_iterator>::value), "");
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::span< int>::iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::span< int>::reverse_iterator>::value), "");
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator<std::span<const int>::iterator> ::value), "");
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator<std::span<const int>::reverse_iterator>::value), "");
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -130,36 +130,42 @@ int main(int, char**)
|
|||
static_assert(( std::__is_cpp17_forward_iterator <char *>::value), "" );
|
||||
static_assert(( std::__is_cpp17_bidirectional_iterator<char *>::value), "" );
|
||||
static_assert(( std::__is_cpp17_random_access_iterator<char *>::value), "" );
|
||||
static_assert(( std::__is_cpp17_contiguous_iterator <char *>::value), "" );
|
||||
static_assert((!std::__is_exactly_cpp17_input_iterator<char *>::value), "" );
|
||||
|
||||
static_assert(( std::__is_cpp17_input_iterator <input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_forward_iterator <input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_bidirectional_iterator<input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_random_access_iterator<input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator <input_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_exactly_cpp17_input_iterator<input_iterator<char *> >::value), "" );
|
||||
|
||||
static_assert(( std::__is_cpp17_input_iterator <forward_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_forward_iterator <forward_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_bidirectional_iterator<forward_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_random_access_iterator<forward_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator <forward_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_exactly_cpp17_input_iterator<forward_iterator<char *> >::value), "" );
|
||||
|
||||
static_assert(( std::__is_cpp17_input_iterator <bidirectional_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_forward_iterator <bidirectional_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_bidirectional_iterator<bidirectional_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_random_access_iterator<bidirectional_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator <bidirectional_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_exactly_cpp17_input_iterator<bidirectional_iterator<char *> >::value), "" );
|
||||
|
||||
static_assert(( std::__is_cpp17_input_iterator <random_access_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_forward_iterator <random_access_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_bidirectional_iterator<random_access_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_cpp17_random_access_iterator<random_access_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator <random_access_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_exactly_cpp17_input_iterator<random_access_iterator<char *> >::value), "" );
|
||||
|
||||
static_assert(( std::__is_cpp17_input_iterator <my_input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_forward_iterator <my_input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_bidirectional_iterator<my_input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_random_access_iterator<my_input_iterator<char *> >::value), "" );
|
||||
static_assert((!std::__is_cpp17_contiguous_iterator <my_input_iterator<char *> >::value), "" );
|
||||
static_assert(( std::__is_exactly_cpp17_input_iterator<my_input_iterator<char *> >::value), "" );
|
||||
|
||||
//
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Older compilers don't support std::is_constant_evaluated
|
||||
// UNSUPPORTED: clang-4, clang-5, clang-6, clang-7, clang-8
|
||||
// UNSUPPORTED: apple-clang-9, apple-clang-10
|
||||
// UNSUPPORTED: c++03
|
||||
|
||||
// <algorithm>
|
||||
|
||||
// We optimize std::copy(_backward) and std::move(_backward) into memmove
|
||||
// when the iterator is trivial and contiguous and the type in question
|
||||
// is also trivially (copyable, movable). This test verifies that the
|
||||
// optimization never eliminates an actually non-trivial copy or move.
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
struct TMBNTC {
|
||||
int *p;
|
||||
constexpr TMBNTC(int& copies) : p(&copies) {}
|
||||
constexpr TMBNTC(const TMBNTC&) = default;
|
||||
TEST_CONSTEXPR_CXX14 TMBNTC& operator=(TMBNTC&&) = default;
|
||||
TEST_CONSTEXPR_CXX14 TMBNTC& operator=(const TMBNTC&) { ++*p; return *this; }
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool
|
||||
test_trivial_moveassign_but_no_trivial_copyassign()
|
||||
{
|
||||
int copies = 0;
|
||||
TMBNTC ia[] = { copies, copies, copies, copies };
|
||||
TMBNTC ib[] = { copies, copies, copies, copies };
|
||||
std::copy(ia, ia+4, ib);
|
||||
assert(copies == 4);
|
||||
copies = 0;
|
||||
std::copy_backward(ia, ia+4, ib+4);
|
||||
assert(copies == 4);
|
||||
|
||||
copies = 0;
|
||||
std::copy(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib);
|
||||
assert(copies == 0);
|
||||
std::copy_backward(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib+4);
|
||||
assert(copies == 0);
|
||||
|
||||
std::move(ia, ia+4, ib);
|
||||
assert(copies == 0);
|
||||
std::move_backward(ia, ia+4, ib+4);
|
||||
assert(copies == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct TCBNTM {
|
||||
int *p;
|
||||
constexpr TCBNTM(int& moves) : p(&moves) {}
|
||||
constexpr TCBNTM(const TCBNTM&) = default;
|
||||
TEST_CONSTEXPR_CXX14 TCBNTM& operator=(TCBNTM&&) { ++*p; return *this; }
|
||||
TEST_CONSTEXPR_CXX14 TCBNTM& operator=(const TCBNTM&) = default;
|
||||
};
|
||||
|
||||
TEST_CONSTEXPR_CXX20 bool
|
||||
test_trivial_copyassign_but_no_trivial_moveassign()
|
||||
{
|
||||
int moves = 0;
|
||||
TCBNTM ia[] = { moves, moves, moves, moves };
|
||||
TCBNTM ib[] = { moves, moves, moves, moves };
|
||||
std::move(ia, ia+4, ib);
|
||||
assert(moves == 4);
|
||||
moves = 0;
|
||||
std::move_backward(ia, ia+4, ib+4);
|
||||
assert(moves == 4);
|
||||
|
||||
moves = 0;
|
||||
std::copy(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib);
|
||||
assert(moves == 4);
|
||||
moves = 0;
|
||||
std::copy_backward(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib+4);
|
||||
assert(moves == 4);
|
||||
|
||||
moves = 0;
|
||||
std::copy(ia, ia+4, ib);
|
||||
assert(moves == 0);
|
||||
std::copy_backward(ia, ia+4, ib+4);
|
||||
assert(moves == 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test_trivial_moveassign_but_no_trivial_copyassign();
|
||||
test_trivial_copyassign_but_no_trivial_moveassign();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
static_assert(test_trivial_moveassign_but_no_trivial_copyassign());
|
||||
static_assert(test_trivial_copyassign_but_no_trivial_moveassign());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -54,7 +54,15 @@ test()
|
|||
#else
|
||||
static_assert((std::is_same<typename R::reference, typename T::reference>::value), "");
|
||||
#endif
|
||||
#if TEST_STD_VER > 17
|
||||
if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
|
||||
static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
|
||||
} else {
|
||||
static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
|
||||
}
|
||||
#else
|
||||
static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
|
@ -94,5 +102,14 @@ int main(int, char**)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
test<contiguous_iterator<char*>>();
|
||||
static_assert(std::is_same_v<typename std::move_iterator<forward_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::move_iterator<bidirectional_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::move_iterator<random_access_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::move_iterator<contiguous_iterator<char*>>::iterator_concept, std::input_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::move_iterator<char*>::iterator_concept, std::input_iterator_tag>);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -49,7 +49,15 @@ test()
|
|||
static_assert((std::is_same<typename R::difference_type, typename T::difference_type>::value), "");
|
||||
static_assert((std::is_same<typename R::reference, typename T::reference>::value), "");
|
||||
static_assert((std::is_same<typename R::pointer, typename std::iterator_traits<It>::pointer>::value), "");
|
||||
#if TEST_STD_VER > 17
|
||||
if constexpr (std::is_same_v<typename T::iterator_category, std::contiguous_iterator_tag>) {
|
||||
static_assert((std::is_same<typename R::iterator_category, std::random_access_iterator_tag>::value), "");
|
||||
} else {
|
||||
static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
|
||||
}
|
||||
#else
|
||||
static_assert((std::is_same<typename R::iterator_category, typename T::iterator_category>::value), "");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
|
@ -58,5 +66,13 @@ int main(int, char**)
|
|||
test<random_access_iterator<char*> >();
|
||||
test<char*>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
test<contiguous_iterator<char*>>();
|
||||
static_assert(std::is_same_v<typename std::reverse_iterator<bidirectional_iterator<char*>>::iterator_concept, std::bidirectional_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::reverse_iterator<random_access_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::reverse_iterator<contiguous_iterator<char*>>::iterator_concept, std::random_access_iterator_tag>);
|
||||
static_assert(std::is_same_v<typename std::reverse_iterator<char*>::iterator_concept, std::random_access_iterator_tag>);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -311,6 +311,85 @@ operator-(const random_access_iterator<T>& x, const random_access_iterator<U>& y
|
|||
return x.base() - y.base();
|
||||
}
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
template <class It>
|
||||
class contiguous_iterator
|
||||
{
|
||||
It it_;
|
||||
|
||||
template <class U> friend class contiguous_iterator;
|
||||
public:
|
||||
typedef std::contiguous_iterator_tag iterator_category;
|
||||
typedef typename std::iterator_traits<It>::value_type value_type;
|
||||
typedef typename std::iterator_traits<It>::difference_type difference_type;
|
||||
typedef It pointer;
|
||||
typedef typename std::iterator_traits<It>::reference reference;
|
||||
typedef typename std::iterator_traits<It>::value_type element_type;
|
||||
|
||||
TEST_CONSTEXPR_CXX14 It base() const {return it_;}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator() : it_() {}
|
||||
explicit TEST_CONSTEXPR_CXX14 contiguous_iterator(It it) : it_(it) {}
|
||||
template <class U>
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator(const contiguous_iterator<U>& u) :it_(u.it_) {}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
|
||||
TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator++() {++it_; return *this;}
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator operator++(int)
|
||||
{contiguous_iterator tmp(*this); ++(*this); return tmp;}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator--() {--it_; return *this;}
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator operator--(int)
|
||||
{contiguous_iterator tmp(*this); --(*this); return tmp;}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator+=(difference_type n) {it_ += n; return *this;}
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n) const
|
||||
{contiguous_iterator tmp(*this); tmp += n; return tmp;}
|
||||
friend TEST_CONSTEXPR_CXX14 contiguous_iterator operator+(difference_type n, contiguous_iterator x)
|
||||
{x += n; return x;}
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator& operator-=(difference_type n) {return *this += -n;}
|
||||
TEST_CONSTEXPR_CXX14 contiguous_iterator operator-(difference_type n) const
|
||||
{contiguous_iterator tmp(*this); tmp -= n; return tmp;}
|
||||
|
||||
TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return it_[n];}
|
||||
|
||||
template <class T>
|
||||
void operator,(T const &) DELETE_FUNCTION;
|
||||
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator-(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() - y.base();
|
||||
}
|
||||
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator<(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() < y.base();
|
||||
}
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator>(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() > y.base();
|
||||
}
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator<=(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() <= y.base();
|
||||
}
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator>=(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() >= y.base();
|
||||
}
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator==(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() == y.base();
|
||||
}
|
||||
friend TEST_CONSTEXPR_CXX14
|
||||
difference_type operator!=(const contiguous_iterator& x, const contiguous_iterator& y) {
|
||||
return x.base() != y.base();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class Iter>
|
||||
inline TEST_CONSTEXPR_CXX14 Iter base(output_iterator<Iter> i) { return i.base(); }
|
||||
|
||||
|
@ -326,6 +405,11 @@ inline TEST_CONSTEXPR_CXX14 Iter base(bidirectional_iterator<Iter> i) { return i
|
|||
template <class Iter>
|
||||
inline TEST_CONSTEXPR_CXX14 Iter base(random_access_iterator<Iter> i) { return i.base(); }
|
||||
|
||||
#if TEST_STD_VER >= 20
|
||||
template <class Iter>
|
||||
inline TEST_CONSTEXPR_CXX14 Iter base(contiguous_iterator<Iter> i) { return i.base(); }
|
||||
#endif
|
||||
|
||||
template <class Iter> // everything else
|
||||
inline TEST_CONSTEXPR_CXX14 Iter base(Iter i) { return i; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue