Implement move_sentinel and C++20 move_iterator.

Differential Revision: https://reviews.llvm.org/D117656
This commit is contained in:
Arthur O'Dwyer 2022-01-19 06:26:52 -05:00 committed by Louis Dionne
parent 7d70b1a405
commit 2fb026ee4d
25 changed files with 1294 additions and 219 deletions

View file

@ -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.

View file

@ -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

View file

@ -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

View 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

View file

@ -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>

View file

@ -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 {

View file

@ -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>

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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>);
}
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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>>);
}
}

View file

@ -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>);

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}