Implement move_sentinel and C++20 move_iterator.
Differential Revision: https://reviews.llvm.org/D117656
This commit is contained in:
parent
7d70b1a405
commit
2fb026ee4d
|
@ -104,7 +104,7 @@
|
|||
`3123 <https://wg21.link/LWG3123>`__,"``duration`` constructor from representation shouldn't be effectively non-throwing","October 2021","","","|chrono|"
|
||||
`3146 <https://wg21.link/LWG3146>`__,"Excessive unwrapping in ``std::ref/cref``","October 2021","|Complete|","14.0"
|
||||
`3152 <https://wg21.link/LWG3152>`__,"``common_type`` and ``common_reference`` have flaws in common","October 2021","",""
|
||||
`3293 <https://wg21.link/LWG3293>`__,"``move_iterator operator+()`` has incorrect constraints","October 2021","","","|ranges|"
|
||||
`3293 <https://wg21.link/LWG3293>`__,"``move_iterator operator+()`` has incorrect constraints","October 2021","|Complete|","15.0","|ranges|"
|
||||
`3361 <https://wg21.link/LWG3361>`__,"``safe_range<SomeRange&>`` case","October 2021","|Nothing To Do|","","|ranges|"
|
||||
`3392 <https://wg21.link/LWG3392>`__,"``ranges::distance()`` cannot be used on a move-only iterator with a sized sentinel","October 2021","|Complete|","14.0","|ranges|"
|
||||
`3407 <https://wg21.link/LWG3407>`__,"Some problems with the wording changes of P1739R4","October 2021","","","|ranges|"
|
||||
|
|
Can't render this file because it has a wrong number of fields in line 2.
|
|
@ -270,6 +270,7 @@ set(files
|
|||
__iterator/iterator_traits.h
|
||||
__iterator/mergeable.h
|
||||
__iterator/move_iterator.h
|
||||
__iterator/move_sentinel.h
|
||||
__iterator/next.h
|
||||
__iterator/ostream_iterator.h
|
||||
__iterator/ostreambuf_iterator.h
|
||||
|
|
|
@ -10,8 +10,20 @@
|
|||
#ifndef _LIBCPP___ITERATOR_MOVE_ITERATOR_H
|
||||
#define _LIBCPP___ITERATOR_MOVE_ITERATOR_H
|
||||
|
||||
#include <__compare/compare_three_way_result.h>
|
||||
#include <__compare/three_way_comparable.h>
|
||||
#include <__concepts/assignable.h>
|
||||
#include <__concepts/convertible_to.h>
|
||||
#include <__concepts/derived_from.h>
|
||||
#include <__concepts/same_as.h>
|
||||
#include <__config>
|
||||
#include <__iterator/concepts.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/iter_move.h>
|
||||
#include <__iterator/iter_swap.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/move_sentinel.h>
|
||||
#include <__iterator/readable_traits.h>
|
||||
#include <__utility/move.h>
|
||||
#include <type_traits>
|
||||
|
||||
|
@ -21,20 +33,48 @@
|
|||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
template<class _Iter, class = void>
|
||||
struct __move_iter_category_base {};
|
||||
|
||||
template<class _Iter>
|
||||
requires requires { typename iterator_traits<_Iter>::iterator_category; }
|
||||
struct __move_iter_category_base<_Iter> {
|
||||
using iterator_category = _If<
|
||||
derived_from<typename iterator_traits<_Iter>::iterator_category, random_access_iterator_tag>,
|
||||
random_access_iterator_tag,
|
||||
typename iterator_traits<_Iter>::iterator_category
|
||||
>;
|
||||
};
|
||||
|
||||
template<class _Iter, class _Sent>
|
||||
concept __move_iter_comparable = requires {
|
||||
{ declval<const _Iter&>() == declval<_Sent>() } -> convertible_to<bool>;
|
||||
};
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
template <class _Iter>
|
||||
class _LIBCPP_TEMPLATE_VIS move_iterator
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
: public __move_iter_category_base<_Iter>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
typedef input_iterator_tag iterator_concept;
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
using iterator_type = _Iter;
|
||||
using iterator_concept = input_iterator_tag;
|
||||
// iterator_category is inherited and not always present
|
||||
using value_type = iter_value_t<_Iter>;
|
||||
using difference_type = iter_difference_t<_Iter>;
|
||||
using pointer = _Iter;
|
||||
using reference = iter_rvalue_reference_t<_Iter>;
|
||||
#else
|
||||
typedef _Iter iterator_type;
|
||||
typedef _If<
|
||||
__is_cpp17_random_access_iterator<_Iter>::value,
|
||||
random_access_iterator_tag,
|
||||
typename iterator_traits<_Iter>::iterator_category
|
||||
> 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;
|
||||
|
@ -50,11 +90,56 @@ public:
|
|||
typedef typename iterator_traits<iterator_type>::reference reference;
|
||||
#endif
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator() requires is_constructible_v<_Iter> : __current_() {}
|
||||
|
||||
template <class _Up>
|
||||
requires (!_IsSame<_Up, _Iter>::value) && convertible_to<const _Up&, _Iter>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator(const move_iterator<_Up>& __u) : __current_(__u.base()) {}
|
||||
|
||||
template <class _Up>
|
||||
requires (!_IsSame<_Up, _Iter>::value) &&
|
||||
convertible_to<const _Up&, _Iter> &&
|
||||
assignable_from<_Iter&, const _Up&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator& operator=(const move_iterator<_Up>& __u) {
|
||||
__current_ = __u.base();
|
||||
return *this;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr const _Iter& base() const & noexcept { return __current_; }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr _Iter base() && { return std::move(__current_); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
reference operator*() const { return ranges::iter_move(__current_); }
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
reference operator[](difference_type __n) const { return ranges::iter_move(__current_ + __n); }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator& operator++() { ++__current_; return *this; }
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
auto operator++(int)
|
||||
requires forward_iterator<_Iter>
|
||||
{
|
||||
move_iterator __tmp(*this); ++__current_; return __tmp;
|
||||
}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
void operator++(int) { ++__current_; }
|
||||
#else
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator() : __current_() {}
|
||||
explicit move_iterator(_Iter __i) : __current_(std::move(__i)) {}
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
explicit move_iterator(_Iter __i) : __current_(_VSTD::move(__i)) {}
|
||||
move_iterator() : __current_() {}
|
||||
|
||||
template <class _Up, class = __enable_if_t<
|
||||
!is_same<_Up, _Iter>::value && is_convertible<const _Up&, _Iter>::value
|
||||
|
@ -87,6 +172,8 @@ public:
|
|||
move_iterator& operator++() { ++__current_; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator operator++(int) { move_iterator __tmp(*this); ++__current_; return __tmp; }
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator& operator--() { --__current_; return *this; }
|
||||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
|
@ -100,7 +187,48 @@ public:
|
|||
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator& operator-=(difference_type __n) { __current_ -= __n; return *this; }
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
template<sentinel_for<_Iter> _Sent>
|
||||
friend _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
bool operator==(const move_iterator& __x, const move_sentinel<_Sent>& __y)
|
||||
requires __move_iter_comparable<_Iter, _Sent>
|
||||
{
|
||||
return __x.base() == __y.base();
|
||||
}
|
||||
|
||||
template<sized_sentinel_for<_Iter> _Sent>
|
||||
friend _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
iter_difference_t<_Iter> operator-(const move_sentinel<_Sent>& __x, const move_iterator& __y)
|
||||
{
|
||||
return __x.base() - __y.base();
|
||||
}
|
||||
|
||||
template<sized_sentinel_for<_Iter> _Sent>
|
||||
friend _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
iter_difference_t<_Iter> operator-(const move_iterator& __x, const move_sentinel<_Sent>& __y)
|
||||
{
|
||||
return __x.base() - __y.base();
|
||||
}
|
||||
|
||||
friend _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
iter_rvalue_reference_t<_Iter> iter_move(const move_iterator& __i)
|
||||
noexcept(noexcept(ranges::iter_move(__i.__current_)))
|
||||
{
|
||||
return ranges::iter_move(__i.__current_);
|
||||
}
|
||||
|
||||
template<indirectly_swappable<_Iter> _It2>
|
||||
friend _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
void iter_swap(const move_iterator& __x, const move_iterator<_It2>& __y)
|
||||
noexcept(noexcept(ranges::iter_swap(__x.__current_, __y.__current_)))
|
||||
{
|
||||
return ranges::iter_swap(__x.__current_, __y.__current_);
|
||||
}
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
private:
|
||||
template<class _It2> friend class move_iterator;
|
||||
|
||||
_Iter __current_;
|
||||
};
|
||||
|
||||
|
@ -111,12 +239,14 @@ bool operator==(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& _
|
|||
return __x.base() == __y.base();
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER <= 17
|
||||
template <class _Iter1, class _Iter2>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
bool operator!=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y)
|
||||
{
|
||||
return __x.base() != __y.base();
|
||||
}
|
||||
#endif // _LIBCPP_STD_VER <= 17
|
||||
|
||||
template <class _Iter1, class _Iter2>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
|
@ -146,6 +276,20 @@ bool operator>=(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& _
|
|||
return __x.base() >= __y.base();
|
||||
}
|
||||
|
||||
#if _LIBCPP_STD_VER > 17
|
||||
# ifdef _LIBCPP_HAS_NO_CONCEPTS
|
||||
template <class _Iter1, class _Iter2>
|
||||
# else
|
||||
template <class _Iter1, three_way_comparable_with<_Iter1> _Iter2>
|
||||
# endif // _LIBCPP_HAS_NO_CONCEPTS
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
auto operator<=>(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y)
|
||||
-> compare_three_way_result_t<_Iter1, _Iter2>
|
||||
{
|
||||
return __x.base() <=> __y.base();
|
||||
}
|
||||
#endif // _LIBCPP_STD_VER > 17
|
||||
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
template <class _Iter1, class _Iter2>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
|
@ -164,6 +308,15 @@ operator-(const move_iterator<_Iter1>& __x, const move_iterator<_Iter2>& __y)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
template <class _Iter>
|
||||
inline _LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_iterator<_Iter> operator+(iter_difference_t<_Iter> __n, const move_iterator<_Iter>& __x)
|
||||
requires requires { { __x.base() + __n } -> same_as<_Iter>; }
|
||||
{
|
||||
return __x + __n;
|
||||
}
|
||||
#else
|
||||
template <class _Iter>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator<_Iter>
|
||||
|
@ -171,13 +324,14 @@ operator+(typename move_iterator<_Iter>::difference_type __n, const move_iterato
|
|||
{
|
||||
return move_iterator<_Iter>(__x.base() + __n);
|
||||
}
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
template <class _Iter>
|
||||
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
move_iterator<_Iter>
|
||||
make_move_iterator(_Iter __i)
|
||||
{
|
||||
return move_iterator<_Iter>(_VSTD::move(__i));
|
||||
return move_iterator<_Iter>(std::move(__i));
|
||||
}
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
|
57
libcxx/include/__iterator/move_sentinel.h
Normal file
57
libcxx/include/__iterator/move_sentinel.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef _LIBCPP___ITERATOR_MOVE_SENTINEL_H
|
||||
#define _LIBCPP___ITERATOR_MOVE_SENTINEL_H
|
||||
|
||||
#include <__concepts/assignable.h>
|
||||
#include <__concepts/convertible_to.h>
|
||||
#include <__concepts/semiregular.h>
|
||||
#include <__config>
|
||||
#include <__utility/move.h>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
# pragma GCC system_header
|
||||
#endif
|
||||
|
||||
_LIBCPP_BEGIN_NAMESPACE_STD
|
||||
|
||||
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
template <semiregular _Sent>
|
||||
class _LIBCPP_TEMPLATE_VIS move_sentinel
|
||||
{
|
||||
public:
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
move_sentinel() = default;
|
||||
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
explicit move_sentinel(_Sent __s) : __last_(_VSTD::move(__s)) {}
|
||||
|
||||
template <class _S2>
|
||||
requires convertible_to<const _S2&, _Sent>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_sentinel(const move_sentinel<_S2>& __s) : __last_(__s.base()) {}
|
||||
|
||||
template <class _S2>
|
||||
requires assignable_from<_Sent&, const _S2&>
|
||||
_LIBCPP_HIDE_FROM_ABI constexpr
|
||||
move_sentinel& operator=(const move_sentinel<_S2>& __s)
|
||||
{ __last_ = __s.base(); return *this; }
|
||||
|
||||
constexpr _Sent base() const { return __last_; }
|
||||
|
||||
private:
|
||||
_Sent __last_ = _Sent();
|
||||
};
|
||||
|
||||
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_CONCEPTS)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___ITERATOR_MOVE_SENTINEL_H
|
|
@ -660,6 +660,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
|
|||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/mergeable.h>
|
||||
#include <__iterator/move_iterator.h>
|
||||
#include <__iterator/move_sentinel.h>
|
||||
#include <__iterator/next.h>
|
||||
#include <__iterator/ostream_iterator.h>
|
||||
#include <__iterator/ostreambuf_iterator.h>
|
||||
|
|
|
@ -661,6 +661,7 @@ module std [system] {
|
|||
module iterator_traits { private header "__iterator/iterator_traits.h" }
|
||||
module mergeable { private header "__iterator/mergeable.h" }
|
||||
module move_iterator { private header "__iterator/move_iterator.h" }
|
||||
module move_sentinel { private header "__iterator/move_sentinel.h" }
|
||||
module next { private header "__iterator/next.h" }
|
||||
module ostream_iterator { private header "__iterator/ostream_iterator.h" }
|
||||
module ostreambuf_iterator {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// REQUIRES: modules-build
|
||||
|
||||
// WARNING: This test was generated by 'generate_private_header_tests.py'
|
||||
// and should not be edited manually.
|
||||
|
||||
// expected-error@*:* {{use of private header from outside its module: '__iterator/move_sentinel.h'}}
|
||||
#include <__iterator/move_sentinel.h>
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
// move_iterator
|
||||
|
||||
// template <InputIterator Iter1, InputIterator Iter2>
|
||||
// requires HasEqualTo<Iter1, Iter2>
|
||||
// bool
|
||||
// operator==(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
// template <class Iter1, class Iter2>
|
||||
// bool operator==(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
//
|
||||
// constexpr in C++17
|
||||
|
||||
|
@ -23,40 +21,60 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// move_iterator's operator== calls the underlying iterator's operator==
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
TEST_CONSTEXPR_CXX17 friend bool operator==(const CustomIt& a, const CustomIt& b) { return a.p_ == b.p_; }
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 == r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r3 = std::move_iterator<It>(It(a + 2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 == r2), bool);
|
||||
assert( (r1 == r1));
|
||||
assert( (r1 == r2));
|
||||
assert( (r2 == r1));
|
||||
assert(!(r1 == r3));
|
||||
assert(!(r3 == r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<cpp17_input_iterator<int*> >();
|
||||
test_one<forward_iterator<int*> >();
|
||||
test_one<bidirectional_iterator<int*> >();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
test_one<three_way_contiguous_iterator<int*>>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s), true);
|
||||
test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1), false);
|
||||
test(forward_iterator<char*>(s), forward_iterator<char*>(s), true);
|
||||
test(forward_iterator<char*>(s), forward_iterator<char*>(s+1), false);
|
||||
test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s), true);
|
||||
test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1), false);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), true);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
|
||||
test(s, s, true);
|
||||
test(s, s+1, false);
|
||||
|
||||
test();
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert(!(it1 == it2), "");
|
||||
static_assert( (it1 == it3), "");
|
||||
static_assert(!(it2 == it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
// move_iterator
|
||||
|
||||
// template <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
|
||||
// requires HasLess<Iter2, Iter1>
|
||||
// bool
|
||||
// operator>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
// template <class Iter1, class Iter2>
|
||||
// bool operator>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
//
|
||||
// constexpr in C++17
|
||||
|
||||
|
@ -23,36 +21,51 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// move_iterator's operator> calls the underlying iterator's operator>
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
TEST_CONSTEXPR_CXX17 friend bool operator>(const CustomIt& a, const CustomIt& b) { return a.p_ > b.p_; }
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 > r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a+2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 > r2), bool);
|
||||
assert(!(r1 > r1));
|
||||
assert(!(r1 > r2));
|
||||
assert( (r2 > r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), false);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
|
||||
test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), true);
|
||||
test(s, s, false);
|
||||
test(s, s+1, false);
|
||||
test(s+1, s, true);
|
||||
|
||||
assert(test());
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert(!(it1 > it2), "");
|
||||
static_assert(!(it1 > it3), "");
|
||||
static_assert( (it2 > it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
// move_iterator
|
||||
|
||||
// template <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
|
||||
// requires HasLess<Iter1, Iter2>
|
||||
// bool
|
||||
// operator>=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
// template <class Iter1, class Iter2>
|
||||
// bool operator>=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
//
|
||||
// constexpr in C++17
|
||||
|
||||
|
@ -23,36 +21,51 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// move_iterator's operator>= calls the underlying iterator's operator>=
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
TEST_CONSTEXPR_CXX17 friend bool operator>=(const CustomIt& a, const CustomIt& b) { return a.p_ >= b.p_; }
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 >= r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a+2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 >= r2), bool);
|
||||
assert( (r1 >= r1));
|
||||
assert(!(r1 >= r2));
|
||||
assert( (r2 >= r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), true);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), false);
|
||||
test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), true);
|
||||
test(s, s, true);
|
||||
test(s, s+1, false);
|
||||
test(s+1, s, true);
|
||||
|
||||
assert(test());
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert(!(it1 >= it2), "");
|
||||
static_assert( (it1 >= it3), "");
|
||||
static_assert( (it2 >= it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
// move_iterator
|
||||
|
||||
// template <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
|
||||
// requires HasLess<Iter1, Iter2>
|
||||
// bool
|
||||
// operator<(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
// template <class Iter1, class Iter2>
|
||||
// bool operator<(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
//
|
||||
// constexpr in C++17
|
||||
|
||||
|
@ -23,36 +21,51 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// move_iterator's operator< calls the underlying iterator's operator<
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
TEST_CONSTEXPR_CXX17 friend bool operator<(const CustomIt& a, const CustomIt& b) { return a.p_ < b.p_; }
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 < r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a + 2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 < r2), bool);
|
||||
assert(!(r1 < r1));
|
||||
assert( (r1 < r2));
|
||||
assert(!(r2 < r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), false);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
|
||||
test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), false);
|
||||
test(s, s, false);
|
||||
test(s, s+1, true);
|
||||
test(s+1, s, false);
|
||||
|
||||
assert(test());
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert( (it1 < it2), "");
|
||||
static_assert(!(it1 < it3), "");
|
||||
static_assert(!(it2 < it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
// move_iterator
|
||||
|
||||
// template <RandomAccessIterator Iter1, RandomAccessIterator Iter2>
|
||||
// requires HasLess<Iter2, Iter1>
|
||||
// bool
|
||||
// operator<=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
// template <class Iter1, class Iter2>
|
||||
// bool operator<=(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y);
|
||||
//
|
||||
// constexpr in C++17
|
||||
|
||||
|
@ -23,36 +21,51 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// move_iterator's operator<= calls the underlying iterator's operator<=
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
TEST_CONSTEXPR_CXX17 friend bool operator<=(const CustomIt& a, const CustomIt& b) { return a.p_ <= b.p_; }
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 <= r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a + 2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 <= r2), bool);
|
||||
assert( (r1 <= r1));
|
||||
assert( (r1 <= r2));
|
||||
assert(!(r2 <= r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), true);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
|
||||
test(random_access_iterator<char*>(s+1), random_access_iterator<char*>(s), false);
|
||||
test(s, s, true);
|
||||
test(s, s+1, true);
|
||||
test(s+1, s, false);
|
||||
|
||||
assert(test());
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert( (it1 <= it2), "");
|
||||
static_assert( (it1 <= it3), "");
|
||||
static_assert(!(it2 <= it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -23,40 +23,66 @@
|
|||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
// In C++17, move_iterator's operator!= calls the underlying iterator's operator!=
|
||||
// In C++20, move_iterator's operator== calls the underlying iterator's operator==
|
||||
struct CustomIt {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
using reference = int&;
|
||||
using pointer = int*;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
CustomIt() = default;
|
||||
TEST_CONSTEXPR_CXX17 explicit CustomIt(int* p) : p_(p) {}
|
||||
int& operator*() const;
|
||||
CustomIt& operator++();
|
||||
CustomIt operator++(int);
|
||||
#if TEST_STD_VER > 17
|
||||
friend constexpr bool operator==(const CustomIt& a, const CustomIt& b) { return a.p_ == b.p_; }
|
||||
friend bool operator!=(const CustomIt& a, const CustomIt& b) = delete;
|
||||
#else
|
||||
friend TEST_CONSTEXPR_CXX17 bool operator!=(const CustomIt& a, const CustomIt& b) { return a.p_ != b.p_; }
|
||||
#endif
|
||||
int *p_ = nullptr;
|
||||
};
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It l, It r, bool x)
|
||||
TEST_CONSTEXPR_CXX17 void test_one()
|
||||
{
|
||||
const std::move_iterator<It> r1(l);
|
||||
const std::move_iterator<It> r2(r);
|
||||
assert((r1 != r2) == x);
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> r1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r2 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> r3 = std::move_iterator<It>(It(a + 2));
|
||||
ASSERT_SAME_TYPE(decltype(r1 != r2), bool);
|
||||
assert(!(r1 != r1));
|
||||
assert(!(r1 != r2));
|
||||
assert(!(r2 != r1));
|
||||
assert( (r1 != r3));
|
||||
assert( (r3 != r1));
|
||||
}
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
test_one<CustomIt>();
|
||||
test_one<cpp17_input_iterator<int*> >();
|
||||
test_one<forward_iterator<int*> >();
|
||||
test_one<bidirectional_iterator<int*> >();
|
||||
test_one<random_access_iterator<int*> >();
|
||||
test_one<int*>();
|
||||
test_one<const int*>();
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
test_one<contiguous_iterator<int*>>();
|
||||
test_one<three_way_contiguous_iterator<int*>>();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "1234567890";
|
||||
test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s), false);
|
||||
test(cpp17_input_iterator<char*>(s), cpp17_input_iterator<char*>(s+1), true);
|
||||
test(forward_iterator<char*>(s), forward_iterator<char*>(s), false);
|
||||
test(forward_iterator<char*>(s), forward_iterator<char*>(s+1), true);
|
||||
test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s), false);
|
||||
test(bidirectional_iterator<char*>(s), bidirectional_iterator<char*>(s+1), true);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s), false);
|
||||
test(random_access_iterator<char*>(s), random_access_iterator<char*>(s+1), true);
|
||||
test(s, s, false);
|
||||
test(s, s+1, true);
|
||||
|
||||
test();
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p + 5);
|
||||
constexpr MI it3 = std::make_move_iterator(p);
|
||||
static_assert( (it1 != it2), "");
|
||||
static_assert(!(it1 != it3), "");
|
||||
static_assert( (it2 != it3), "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-has-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_iterator
|
||||
|
||||
// template <class Iter1, three_way_comparable_with<Iter1> Iter2>
|
||||
// constexpr auto operator<=>(const move_iterator<Iter1>& x, const move_iterator<Iter2>& y)
|
||||
// -> compare_three_way_result_t<Iter1, Iter2>;
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
|
||||
template<class T, class U> concept HasEquals = requires (T t, U u) { t == u; };
|
||||
template<class T, class U> concept HasSpaceship = requires (T t, U u) { t <=> u; };
|
||||
|
||||
static_assert(!HasSpaceship<std::move_iterator<int*>, std::move_iterator<char*>>);
|
||||
static_assert( HasSpaceship<std::move_iterator<int*>, std::move_iterator<int*>>);
|
||||
static_assert( HasSpaceship<std::move_iterator<int*>, std::move_iterator<const int*>>);
|
||||
static_assert( HasSpaceship<std::move_iterator<const int*>, std::move_iterator<const int*>>);
|
||||
static_assert(!HasSpaceship<std::move_iterator<forward_iterator<int*>>, std::move_iterator<forward_iterator<int*>>>);
|
||||
static_assert(!HasSpaceship<std::move_iterator<random_access_iterator<int*>>, std::move_iterator<random_access_iterator<int*>>>);
|
||||
static_assert(!HasSpaceship<std::move_iterator<contiguous_iterator<int*>>, std::move_iterator<contiguous_iterator<int*>>>);
|
||||
static_assert( HasSpaceship<std::move_iterator<three_way_contiguous_iterator<int*>>, std::move_iterator<three_way_contiguous_iterator<int*>>>);
|
||||
|
||||
static_assert(!HasSpaceship<std::move_iterator<int*>, std::move_sentinel<int*>>);
|
||||
static_assert(!HasSpaceship<std::move_iterator<three_way_contiguous_iterator<int*>>, std::move_sentinel<three_way_contiguous_iterator<int*>>>);
|
||||
|
||||
void test_spaceshippable_but_not_three_way_comparable() {
|
||||
struct A {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
int& operator*() const;
|
||||
A& operator++();
|
||||
A operator++(int);
|
||||
std::strong_ordering operator<=>(const A&) const;
|
||||
};
|
||||
struct B {
|
||||
using value_type = int;
|
||||
using difference_type = int;
|
||||
int& operator*() const;
|
||||
B& operator++();
|
||||
B operator++(int);
|
||||
std::strong_ordering operator<=>(const B&) const;
|
||||
bool operator==(const A&) const;
|
||||
std::strong_ordering operator<=>(const A&) const;
|
||||
};
|
||||
static_assert( std::input_iterator<A>);
|
||||
static_assert( std::input_iterator<B>);
|
||||
static_assert( HasEquals<A, B>);
|
||||
static_assert( HasSpaceship<A, B>);
|
||||
static_assert(!std::three_way_comparable_with<A, B>);
|
||||
static_assert( HasEquals<std::move_iterator<A>, std::move_iterator<B>>);
|
||||
static_assert(!HasSpaceship<std::move_iterator<A>, std::move_iterator<B>>);
|
||||
}
|
||||
|
||||
template <class It, class Jt>
|
||||
constexpr void test_two()
|
||||
{
|
||||
int a[] = {3, 1, 4};
|
||||
const std::move_iterator<It> i1 = std::move_iterator<It>(It(a));
|
||||
const std::move_iterator<It> i2 = std::move_iterator<It>(It(a + 2));
|
||||
const std::move_iterator<Jt> j1 = std::move_iterator<Jt>(Jt(a));
|
||||
const std::move_iterator<Jt> j2 = std::move_iterator<Jt>(Jt(a + 2));
|
||||
ASSERT_SAME_TYPE(decltype(i1 <=> i2), std::strong_ordering);
|
||||
assert((i1 <=> i1) == std::strong_ordering::equal);
|
||||
assert((i1 <=> i2) == std::strong_ordering::less);
|
||||
assert((i2 <=> i1) == std::strong_ordering::greater);
|
||||
ASSERT_SAME_TYPE(decltype(i1 <=> j2), std::strong_ordering);
|
||||
assert((i1 <=> j1) == std::strong_ordering::equal);
|
||||
assert((i1 <=> j2) == std::strong_ordering::less);
|
||||
assert((i2 <=> j1) == std::strong_ordering::greater);
|
||||
}
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
test_two<int*, int*>();
|
||||
test_two<int*, const int*>();
|
||||
test_two<const int*, int*>();
|
||||
test_two<const int*, const int*>();
|
||||
test_two<three_way_contiguous_iterator<int*>, three_way_contiguous_iterator<int*>>();
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
assert(test());
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -16,33 +16,73 @@
|
|||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It i)
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
std::move_iterator<It> r(i);
|
||||
assert(r.base() == i);
|
||||
static_assert( std::is_constructible<std::move_iterator<It>, const It&>::value, "");
|
||||
static_assert( std::is_constructible<std::move_iterator<It>, It&&>::value, "");
|
||||
static_assert(!std::is_convertible<const It&, std::move_iterator<It> >::value, "");
|
||||
static_assert(!std::is_convertible<It&&, std::move_iterator<It> >::value, "");
|
||||
|
||||
char s[] = "123";
|
||||
{
|
||||
It it = It(s);
|
||||
std::move_iterator<It> r(it);
|
||||
assert(base(r.base()) == s);
|
||||
}
|
||||
{
|
||||
It it = It(s);
|
||||
std::move_iterator<It> r(std::move(it));
|
||||
assert(base(r.base()) == s);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class It>
|
||||
TEST_CONSTEXPR_CXX17 bool test_moveonly()
|
||||
{
|
||||
static_assert(!std::is_constructible<std::move_iterator<It>, const It&>::value, "");
|
||||
static_assert( std::is_constructible<std::move_iterator<It>, It&&>::value, "");
|
||||
static_assert(!std::is_convertible<const It&, std::move_iterator<It> >::value, "");
|
||||
static_assert(!std::is_convertible<It&&, std::move_iterator<It> >::value, "");
|
||||
|
||||
char s[] = "123";
|
||||
{
|
||||
It it = It(s);
|
||||
std::move_iterator<It> r(std::move(it));
|
||||
assert(base(r.base()) == s);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "123";
|
||||
test(cpp17_input_iterator<char*>(s));
|
||||
test(forward_iterator<char*>(s));
|
||||
test(bidirectional_iterator<char*>(s));
|
||||
test(random_access_iterator<char*>(s));
|
||||
test(s);
|
||||
test<cpp17_input_iterator<char*> >();
|
||||
test<forward_iterator<char*> >();
|
||||
test<bidirectional_iterator<char*> >();
|
||||
test<random_access_iterator<char*> >();
|
||||
test<char*>();
|
||||
test<const char*>();
|
||||
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
constexpr std::move_iterator<const char *> it(p);
|
||||
static_assert(it.base() == p);
|
||||
}
|
||||
static_assert(test<cpp17_input_iterator<char*>>());
|
||||
static_assert(test<forward_iterator<char*>>());
|
||||
static_assert(test<bidirectional_iterator<char*>>());
|
||||
static_assert(test<random_access_iterator<char*>>());
|
||||
static_assert(test<char*>());
|
||||
static_assert(test<const char*>());
|
||||
#endif
|
||||
|
||||
#if TEST_STD_VER > 17
|
||||
test<contiguous_iterator<char*>>();
|
||||
test_moveonly<cpp20_input_iterator<char*>>();
|
||||
static_assert(test<contiguous_iterator<char*>>());
|
||||
static_assert(test_moveonly<cpp20_input_iterator<char*>>());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -13,35 +13,41 @@
|
|||
// pointer operator->() const;
|
||||
//
|
||||
// constexpr in C++17
|
||||
// removed in C++20
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
template <class It>
|
||||
void
|
||||
test(It i)
|
||||
#if TEST_STD_VER > 17
|
||||
template <class T>
|
||||
concept HasArrow = requires (T t) {
|
||||
t.operator->();
|
||||
};
|
||||
static_assert(!HasArrow<std::move_iterator<int*>>);
|
||||
static_assert(!HasArrow<std::move_iterator<int*>&>);
|
||||
static_assert(!HasArrow<std::move_iterator<int*>&&>);
|
||||
#endif // TEST_STD_VER > 17
|
||||
|
||||
TEST_CONSTEXPR_CXX17 bool test()
|
||||
{
|
||||
std::move_iterator<It> r(i);
|
||||
assert(r.operator->() == i);
|
||||
#if TEST_STD_VER <= 17
|
||||
char a[] = "123456789";
|
||||
std::move_iterator<char *> it1 = std::make_move_iterator(a);
|
||||
std::move_iterator<char *> it2 = std::make_move_iterator(a + 1);
|
||||
assert(it1.operator->() == a);
|
||||
assert(it2.operator->() == a + 1);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
char s[] = "123";
|
||||
test(s);
|
||||
|
||||
test();
|
||||
#if TEST_STD_VER > 14
|
||||
{
|
||||
constexpr const char *p = "123456789";
|
||||
typedef std::move_iterator<const char *> MI;
|
||||
constexpr MI it1 = std::make_move_iterator(p);
|
||||
constexpr MI it2 = std::make_move_iterator(p+1);
|
||||
static_assert(it1.operator->() == p, "");
|
||||
static_assert(it2.operator->() == p + 1, "");
|
||||
}
|
||||
static_assert(test());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -12,16 +12,128 @@
|
|||
|
||||
#include <iterator>
|
||||
|
||||
using iterator = std::move_iterator<int*>;
|
||||
#include "test_iterators.h"
|
||||
#include "test_macros.h"
|
||||
|
||||
static_assert(std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert(std::incrementable<iterator>);
|
||||
static_assert(std::sentinel_for<iterator, iterator>);
|
||||
static_assert(std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_swappable<iterator, iterator>);
|
||||
void test()
|
||||
{
|
||||
{
|
||||
using iterator = std::move_iterator<cpp17_input_iterator<int*>>;
|
||||
|
||||
LIBCPP_STATIC_ASSERT(!std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert(!std::sentinel_for<iterator, iterator>); // not copyable
|
||||
static_assert(!std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<cpp20_input_iterator<int*>>;
|
||||
|
||||
LIBCPP_STATIC_ASSERT(!std::default_initializable<iterator>);
|
||||
static_assert(!std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert(!std::sentinel_for<iterator, iterator>); // not copyable
|
||||
static_assert(!std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<forward_iterator<int*>>;
|
||||
|
||||
static_assert( std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert( std::sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<bidirectional_iterator<int*>>;
|
||||
|
||||
static_assert( std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert( std::sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<random_access_iterator<int*>>;
|
||||
|
||||
static_assert( std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert( std::sentinel_for<iterator, iterator>);
|
||||
static_assert( std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<contiguous_iterator<int*>>;
|
||||
|
||||
static_assert( std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert( std::sentinel_for<iterator, iterator>);
|
||||
static_assert( std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
{
|
||||
using iterator = std::move_iterator<int*>;
|
||||
|
||||
static_assert( std::default_initializable<iterator>);
|
||||
static_assert( std::copyable<iterator>);
|
||||
static_assert( std::input_iterator<iterator>);
|
||||
static_assert(!std::forward_iterator<iterator>);
|
||||
static_assert( std::sentinel_for<iterator, iterator>);
|
||||
static_assert( std::sized_sentinel_for<iterator, iterator>);
|
||||
static_assert(!std::indirectly_movable<int*, iterator>);
|
||||
static_assert(!std::indirectly_movable_storable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable<int*, iterator>);
|
||||
static_assert(!std::indirectly_copyable_storable<int*, iterator>);
|
||||
static_assert( std::indirectly_readable<iterator>);
|
||||
static_assert(!std::indirectly_writable<iterator, int>);
|
||||
static_assert( std::indirectly_swappable<iterator, iterator>);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// template<class S2>
|
||||
// requires assignable_from<S&, const S2&>
|
||||
// constexpr move_sentinel& operator=(const move_sentinel<S2>& s);
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
|
||||
struct NonAssignable {
|
||||
NonAssignable& operator=(int i);
|
||||
};
|
||||
static_assert(std::semiregular<NonAssignable>);
|
||||
static_assert(std::is_assignable_v<NonAssignable, int>);
|
||||
static_assert(!std::assignable_from<NonAssignable, int>);
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
std::move_sentinel<int> m(42);
|
||||
std::move_sentinel<long> m2;
|
||||
m2 = m;
|
||||
assert(m2.base() == 42L);
|
||||
}
|
||||
{
|
||||
std::move_sentinel<long> m2;
|
||||
m2 = std::move_sentinel<int>(43);
|
||||
assert(m2.base() == 43L);
|
||||
}
|
||||
{
|
||||
static_assert( std::is_assignable_v<std::move_sentinel<int>, std::move_sentinel<long>>);
|
||||
static_assert(!std::is_assignable_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);
|
||||
static_assert( std::is_assignable_v<std::move_sentinel<const int*>, std::move_sentinel<int*>>);
|
||||
static_assert(!std::is_assignable_v<std::move_sentinel<NonAssignable>, std::move_sentinel<int>>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// constexpr S base() const;
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
auto m = std::move_sentinel<int>(42);
|
||||
const auto& cm = m;
|
||||
assert(m.base() == 42);
|
||||
assert(cm.base() == 42);
|
||||
assert(std::move(m).base() == 42);
|
||||
assert(std::move(cm).base() == 42);
|
||||
ASSERT_SAME_TYPE(decltype(m.base()), int);
|
||||
ASSERT_SAME_TYPE(decltype(cm.base()), int);
|
||||
ASSERT_SAME_TYPE(decltype(std::move(m).base()), int);
|
||||
ASSERT_SAME_TYPE(decltype(std::move(cm).base()), int);
|
||||
}
|
||||
{
|
||||
int a[] = {1, 2, 3};
|
||||
auto m = std::move_sentinel<const int*>(a);
|
||||
const auto& cm = m;
|
||||
assert(m.base() == a);
|
||||
assert(cm.base() == a);
|
||||
assert(std::move(m).base() == a);
|
||||
assert(std::move(cm).base() == a);
|
||||
ASSERT_SAME_TYPE(decltype(m.base()), const int*);
|
||||
ASSERT_SAME_TYPE(decltype(cm.base()), const int*);
|
||||
ASSERT_SAME_TYPE(decltype(std::move(m).base()), const int*);
|
||||
ASSERT_SAME_TYPE(decltype(std::move(cm).base()), const int*);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
// UNSUPPORTED: libcpp-no-incomplete-ranges
|
||||
|
||||
// <iterator>
|
||||
|
||||
// template<semiregular S>
|
||||
// class move_sentinel;
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include "test_iterators.h"
|
||||
|
||||
void test()
|
||||
{
|
||||
{
|
||||
using It = int*;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = cpp17_input_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = cpp20_input_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = forward_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = bidirectional_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = random_access_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = contiguous_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
{
|
||||
using It = three_way_contiguous_iterator<int*>;
|
||||
static_assert( std::sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<It>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert(!std::sized_sentinel_for<std::move_sentinel<sentinel_wrapper<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
static_assert( std::sized_sentinel_for<std::move_sentinel<sized_sentinel<It>>, std::move_iterator<It>>);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// template<semiregular S>
|
||||
// class move_sentinel;
|
||||
|
||||
#include <iterator>
|
||||
|
||||
template<class T>
|
||||
concept HasMoveSentinel = requires {
|
||||
typename std::move_sentinel<T>;
|
||||
};
|
||||
|
||||
struct Semiregular {};
|
||||
|
||||
struct NotSemiregular {
|
||||
NotSemiregular(int);
|
||||
};
|
||||
|
||||
static_assert( HasMoveSentinel<int>);
|
||||
static_assert( HasMoveSentinel<int*>);
|
||||
static_assert( HasMoveSentinel<Semiregular>);
|
||||
static_assert(!HasMoveSentinel<NotSemiregular>);
|
|
@ -0,0 +1,60 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// template<class S2>
|
||||
// requires convertible_to<const S2&, S>
|
||||
// constexpr move_sentinel(const move_sentinel<S2>& s);
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
#include <concepts>
|
||||
|
||||
struct NonConvertible {
|
||||
explicit NonConvertible();
|
||||
NonConvertible(int i);
|
||||
explicit NonConvertible(long i) = delete;
|
||||
};
|
||||
static_assert(std::semiregular<NonConvertible>);
|
||||
static_assert(std::is_convertible_v<long, NonConvertible>);
|
||||
static_assert(!std::convertible_to<long, NonConvertible>);
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
std::move_sentinel<int> m(42);
|
||||
std::move_sentinel<long> m2 = m;
|
||||
assert(m2.base() == 42L);
|
||||
}
|
||||
{
|
||||
std::move_sentinel<long> m2 = std::move_sentinel<int>(43);
|
||||
assert(m2.base() == 43L);
|
||||
}
|
||||
{
|
||||
static_assert( std::is_convertible_v<std::move_sentinel<int>, std::move_sentinel<long>>);
|
||||
static_assert( std::is_convertible_v<std::move_sentinel<int*>, std::move_sentinel<const int*>>);
|
||||
static_assert(!std::is_convertible_v<std::move_sentinel<const int*>, std::move_sentinel<int*>>);
|
||||
static_assert( std::is_convertible_v<std::move_sentinel<int>, std::move_sentinel<NonConvertible>>);
|
||||
static_assert(!std::is_convertible_v<std::move_sentinel<long>, std::move_sentinel<NonConvertible>>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// constexpr move_sentinel();
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
std::move_sentinel<int> m;
|
||||
assert(m.base() == 0);
|
||||
}
|
||||
{
|
||||
std::move_sentinel<int*> m;
|
||||
assert(m.base() == nullptr);
|
||||
}
|
||||
{
|
||||
struct S {
|
||||
explicit S() = default;
|
||||
int i = 3;
|
||||
};
|
||||
std::move_sentinel<S> m;
|
||||
assert(m.base().i == 3);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// constexpr explicit move_sentinel(S s);
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
{
|
||||
static_assert(!std::is_convertible_v<int, std::move_sentinel<int>>);
|
||||
std::move_sentinel<int> m(42);
|
||||
assert(m.base() == 42);
|
||||
}
|
||||
{
|
||||
static_assert(!std::is_convertible_v<int*, std::move_sentinel<int*>>);
|
||||
int i = 42;
|
||||
std::move_sentinel<int*> m(&i);
|
||||
assert(m.base() == &i);
|
||||
}
|
||||
{
|
||||
struct S {
|
||||
explicit S() = default;
|
||||
constexpr explicit S(int j) : i(j) {}
|
||||
int i = 3;
|
||||
};
|
||||
static_assert(!std::is_convertible_v<S, std::move_sentinel<S>>);
|
||||
std::move_sentinel<S> m(S(42));
|
||||
assert(m.base().i == 42);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
|
||||
// <iterator>
|
||||
|
||||
// move_sentinel
|
||||
|
||||
// template <class Iter, class Sent>
|
||||
// constexpr bool operator==(const move_iterator<Iter>& x, const move_sentinel<Sent>& y);
|
||||
|
||||
#include <iterator>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_macros.h"
|
||||
#include "test_iterators.h"
|
||||
|
||||
template<class T, class U> concept HasEquals = requires (T t, U u) { t == u; };
|
||||
template<class T, class U> concept HasNotEquals = requires (T t, U u) { t != u; };
|
||||
template<class T, class U> concept HasLess = requires (T t, U u) { t < u; };
|
||||
|
||||
static_assert(!HasEquals<std::move_iterator<int*>, std::move_sentinel<char*>>);
|
||||
static_assert(!HasNotEquals<std::move_iterator<int*>, std::move_sentinel<char*>>);
|
||||
static_assert(!HasLess<std::move_iterator<int*>, std::move_sentinel<char*>>);
|
||||
|
||||
static_assert( HasEquals<std::move_iterator<int*>, std::move_sentinel<const int*>>);
|
||||
static_assert( HasNotEquals<std::move_iterator<int*>, std::move_sentinel<const int*>>);
|
||||
static_assert(!HasLess<std::move_iterator<int*>, std::move_sentinel<const int*>>);
|
||||
|
||||
static_assert( HasEquals<std::move_iterator<const int*>, std::move_sentinel<int*>>);
|
||||
static_assert( HasNotEquals<std::move_iterator<const int*>, std::move_sentinel<int*>>);
|
||||
static_assert(!HasLess<std::move_iterator<const int*>, std::move_sentinel<int*>>);
|
||||
|
||||
template <class It>
|
||||
constexpr bool test_one()
|
||||
{
|
||||
{
|
||||
char s[] = "abc";
|
||||
const auto it = std::move_iterator<It>(It(s));
|
||||
const auto sent1 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s)));
|
||||
const auto sent2 = std::move_sentinel<sentinel_wrapper<It>>(sentinel_wrapper<It>(It(s + 1)));
|
||||
ASSERT_SAME_TYPE(decltype(it == sent1), bool);
|
||||
assert( (it == sent1));
|
||||
assert(!(it != sent1));
|
||||
assert(!(it == sent2));
|
||||
assert( (it != sent2));
|
||||
assert( (sent1 == it));
|
||||
assert(!(sent1 != it));
|
||||
assert(!(sent2 == it));
|
||||
assert( (sent2 != it));
|
||||
static_assert(!HasEquals<decltype(sent1), decltype(sent1)>);
|
||||
static_assert(!HasLess<decltype(sent1), decltype(sent1)>);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
constexpr bool test()
|
||||
{
|
||||
test_one<cpp17_input_iterator<char*>>();
|
||||
test_one<cpp20_input_iterator<char*>>();
|
||||
test_one<forward_iterator<char*>>();
|
||||
test_one<bidirectional_iterator<char*>>();
|
||||
test_one<random_access_iterator<char*>>();
|
||||
test_one<contiguous_iterator<char*>>();
|
||||
test_one<three_way_contiguous_iterator<char*>>();
|
||||
test_one<char*>();
|
||||
test_one<const char*>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test();
|
||||
static_assert(test());
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue