[libcxx][ranges] Add common_iterator.

Differential Revision: https://reviews.llvm.org/D103335
This commit is contained in:
zoecarver 2021-05-27 09:23:19 -07:00
parent 4a30a5c8d9
commit 1a29403d2f
18 changed files with 1789 additions and 3 deletions

View File

@ -77,7 +77,7 @@ Section,Description,Dependencies,Assignee,Complete
[move.sentinel],,[predef.iterators],Unassigned,Not started
[common.iterator],,"| [iterator.concepts]
| [iterator.cust.swap]
| [iterator.cust.move]",Zoe Carver,In Progress
| [iterator.cust.move]",Zoe Carver,
[default.sentinels],std::default_sentinel_t.,No dependencies,Zoe Carver,✅
[counted.iterator],,"| [iterator.concepts]
| [iterator.cust.swap]

1 Section Description Dependencies Assignee Complete
77
78
79
80
81
82
83

View File

@ -133,6 +133,7 @@ set(files
__iterator/access.h
__iterator/advance.h
__iterator/back_insert_iterator.h
__iterator/common_iterator.h
__iterator/concepts.h
__iterator/data.h
__iterator/default_sentinel.h

View File

@ -0,0 +1,301 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// 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_COMMON_ITERATOR_H
#define _LIBCPP___ITERATOR_COMMON_ITERATOR_H
#include <__config>
#include <__debug>
#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/readable_traits.h>
#include <concepts>
#include <variant>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if !defined(_LIBCPP_HAS_NO_RANGES)
template<input_or_output_iterator _Iter, sentinel_for<_Iter> _Sent>
requires (!same_as<_Iter, _Sent> && copyable<_Iter>)
class common_iterator {
class __proxy {
friend common_iterator;
iter_value_t<_Iter> __value;
// We can move __x because the only caller verifies that __x is not a reference.
constexpr __proxy(iter_reference_t<_Iter>&& __x)
: __value(_VSTD::move(__x)) {}
public:
const iter_value_t<_Iter>* operator->() const {
return _VSTD::addressof(__value);
}
};
class __postfix_proxy {
friend common_iterator;
iter_value_t<_Iter> __value;
constexpr __postfix_proxy(iter_reference_t<_Iter>&& __x)
: __value(_VSTD::forward<iter_reference_t<_Iter>>(__x)) {}
public:
constexpr static bool __valid_for_iter =
constructible_from<iter_value_t<_Iter>, iter_reference_t<_Iter>> &&
move_constructible<iter_value_t<_Iter>>;
const iter_value_t<_Iter>& operator*() const {
return __value;
}
};
public:
variant<_Iter, _Sent> __hold_;
common_iterator() requires default_initializable<_Iter> = default;
constexpr common_iterator(_Iter __i) : __hold_(in_place_type<_Iter>, _VSTD::move(__i)) {}
constexpr common_iterator(_Sent __s) : __hold_(in_place_type<_Sent>, _VSTD::move(__s)) {}
template<class _I2, class _S2>
requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent>
constexpr common_iterator(const common_iterator<_I2, _S2>& __other)
: __hold_([&]() -> variant<_Iter, _Sent> {
_LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Constructed from valueless iterator.");
if (__other.__hold_.index() == 0)
return variant<_Iter, _Sent>{in_place_index<0>, _VSTD::__unchecked_get<0>(__other.__hold_)};
return variant<_Iter, _Sent>{in_place_index<1>, _VSTD::__unchecked_get<1>(__other.__hold_)};
}()) {}
template<class _I2, class _S2>
requires convertible_to<const _I2&, _Iter> && convertible_to<const _S2&, _Sent> &&
assignable_from<_Iter&, const _I2&> && assignable_from<_Sent&, const _S2&>
common_iterator& operator=(const common_iterator<_I2, _S2>& __other) {
_LIBCPP_ASSERT(!__other.__hold_.valueless_by_exception(), "Assigned from valueless iterator.");
auto __idx = __hold_.index();
auto __other_idx = __other.__hold_.index();
// If they're the same index, just assign.
if (__idx == 0 && __other_idx == 0)
_VSTD::__unchecked_get<0>(__hold_) = _VSTD::__unchecked_get<0>(__other.__hold_);
else if (__idx == 1 && __other_idx == 1)
_VSTD::__unchecked_get<1>(__hold_) = _VSTD::__unchecked_get<1>(__other.__hold_);
// Otherwise replace with the oposite element.
else if (__other_idx == 1)
__hold_.template emplace<1>(_VSTD::__unchecked_get<1>(__other.__hold_));
else if (__other_idx == 0)
__hold_.template emplace<0>(_VSTD::__unchecked_get<0>(__other.__hold_));
return *this;
}
decltype(auto) operator*()
{
_LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
"Cannot dereference sentinel. Common iterator not holding an iterator.");
return *_VSTD::__unchecked_get<_Iter>(__hold_);
}
decltype(auto) operator*() const
requires __dereferenceable<const _Iter>
{
_LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
"Cannot dereference sentinel. Common iterator not holding an iterator.");
return *_VSTD::__unchecked_get<_Iter>(__hold_);
}
template<class _I2 = _Iter>
decltype(auto) operator->() const
requires indirectly_readable<const _I2> &&
(requires(const _I2& __i) { __i.operator->(); } ||
is_reference_v<iter_reference_t<_I2>> ||
constructible_from<iter_value_t<_I2>, iter_reference_t<_I2>>)
{
_LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
"Cannot dereference sentinel. Common iterator not holding an iterator.");
if constexpr (is_pointer_v<_Iter> || requires(const _Iter& __i) { __i.operator->(); }) {
return _VSTD::__unchecked_get<_Iter>(__hold_);
} else if constexpr (is_reference_v<iter_reference_t<_Iter>>) {
auto&& __tmp = *_VSTD::__unchecked_get<_Iter>(__hold_);
return _VSTD::addressof(__tmp);
} else {
return __proxy(*_VSTD::__unchecked_get<_Iter>(__hold_));
}
}
common_iterator& operator++() {
_LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
"Cannot increment sentinel. Common iterator not holding an iterator.");
++_VSTD::__unchecked_get<_Iter>(__hold_); return *this;
}
decltype(auto) operator++(int) {
_LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_),
"Cannot increment sentinel. Common iterator not holding an iterator.");
if constexpr (forward_iterator<_Iter>) {
auto __tmp = *this;
++*this;
return __tmp;
} else if constexpr (requires (_Iter& __i) { { *__i++ } -> __referenceable; } ||
!__postfix_proxy::__valid_for_iter) {
return _VSTD::__unchecked_get<_Iter>(__hold_)++;
} else {
__postfix_proxy __p(**this);
++*this;
return __p;
}
}
template<class _I2, sentinel_for<_Iter> _S2>
requires sentinel_for<_Sent, _I2>
friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
_LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
!__y.__hold_.valueless_by_exception(),
"One or both common_iterators are valueless. (Cannot compare valueless iterators.)");
auto __x_index = __x.__hold_.index();
auto __y_index = __y.__hold_.index();
if (__x_index == __y_index)
return true;
if (__x_index == 0)
return _VSTD::__unchecked_get<_Iter>(__x.__hold_) == _VSTD::__unchecked_get<_S2>(__y.__hold_);
return _VSTD::__unchecked_get<_Sent>(__x.__hold_) == _VSTD::__unchecked_get<_I2>(__y.__hold_);
}
template<class _I2, sentinel_for<_Iter> _S2>
requires sentinel_for<_Sent, _I2> && equality_comparable_with<_Iter, _I2>
friend bool operator==(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
_LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
!__y.__hold_.valueless_by_exception(),
"One or both common_iterators are valueless. (Cannot compare valueless iterators.)");
auto __x_index = __x.__hold_.index();
auto __y_index = __y.__hold_.index();
if (__x_index == 1 && __y_index == 1)
return true;
if (__x_index == 0 && __y_index == 0)
return _VSTD::__unchecked_get<_Iter>(__x.__hold_) == _VSTD::__unchecked_get<_I2>(__y.__hold_);
if (__x_index == 0)
return _VSTD::__unchecked_get<_Iter>(__x.__hold_) == _VSTD::__unchecked_get<_S2>(__y.__hold_);
return _VSTD::__unchecked_get<_Sent>(__x.__hold_) == _VSTD::__unchecked_get<_I2>(__y.__hold_);
}
template<sized_sentinel_for<_Iter> _I2, sized_sentinel_for<_Iter> _S2>
requires sized_sentinel_for<_Sent, _I2>
friend iter_difference_t<_I2> operator-(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) {
_LIBCPP_ASSERT(!__x.__hold_.valueless_by_exception() &&
!__y.__hold_.valueless_by_exception(),
"One or both common_iterators are valueless. (Cannot subtract valueless iterators.)");
auto __x_index = __x.__hold_.index();
auto __y_index = __y.__hold_.index();
if (__x_index == 1 && __y_index == 1)
return 0;
if (__x_index == 0 && __y_index == 0)
return _VSTD::__unchecked_get<_Iter>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_);
if (__x_index == 0)
return _VSTD::__unchecked_get<_Iter>(__x.__hold_) - _VSTD::__unchecked_get<_S2>(__y.__hold_);
return _VSTD::__unchecked_get<_Sent>(__x.__hold_) - _VSTD::__unchecked_get<_I2>(__y.__hold_);
}
friend iter_rvalue_reference_t<_Iter> iter_move(const common_iterator& __i)
noexcept(noexcept(ranges::iter_move(declval<const _Iter&>())))
requires input_iterator<_Iter>
{
_LIBCPP_ASSERT(holds_alternative<_Iter>(__i.__hold_),
"Cannot iter_move a sentinel. Common iterator not holding an iterator.");
return ranges::iter_move( _VSTD::__unchecked_get<_Iter>(__i.__hold_));
}
template<indirectly_swappable<_Iter> _I2, class _S2>
friend void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y)
noexcept(noexcept(ranges::iter_swap(declval<const _Iter&>(), declval<const _I2&>())))
{
_LIBCPP_ASSERT(holds_alternative<_Iter>(__x.__hold_),
"Cannot swap __y with a sentinel. Common iterator (__x) not holding an iterator.");
_LIBCPP_ASSERT(holds_alternative<_Iter>(__y.__hold_),
"Cannot swap __x with a sentinel. Common iterator (__y) not holding an iterator.");
return ranges::iter_swap( _VSTD::__unchecked_get<_Iter>(__x.__hold_), _VSTD::__unchecked_get<_Iter>(__y.__hold_));
}
};
template<class _Iter, class _Sent>
struct incrementable_traits<common_iterator<_Iter, _Sent>> {
using difference_type = iter_difference_t<_Iter>;
};
template<class _Iter>
concept __denotes_forward_iter =
requires { typename iterator_traits<_Iter>::iterator_category; } &&
derived_from<typename iterator_traits<_Iter>::iterator_category, forward_iterator_tag>;
template<class _Iter, class _Sent>
concept __common_iter_has_ptr_op = requires(const common_iterator<_Iter, _Sent>& __a) {
__a.operator->();
};
template<class, class>
struct __arrow_type_or_void {
using type = void;
};
template<class _Iter, class _Sent>
requires __common_iter_has_ptr_op<_Iter, _Sent>
struct __arrow_type_or_void<_Iter, _Sent> {
using type = decltype(declval<const common_iterator<_Iter, _Sent>>().operator->());
};
template<class _Iter, class _Sent>
struct iterator_traits<common_iterator<_Iter, _Sent>> {
using iterator_concept = _If<forward_iterator<_Iter>,
forward_iterator_tag,
input_iterator_tag>;
using iterator_category = _If<__denotes_forward_iter<_Iter>,
forward_iterator_tag,
input_iterator_tag>;
using pointer = typename __arrow_type_or_void<_Iter, _Sent>::type;
using value_type = iter_value_t<_Iter>;
using difference_type = iter_difference_t<_Iter>;
using reference = iter_reference_t<_Iter>;
};
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___ITERATOR_COMMON_ITERATOR_H

View File

@ -136,6 +136,10 @@ template<class In, class Out>
template<class I1, class I2 = I1>
concept indirectly_swappable = see below; // since C++20
template<input_or_output_iterator I, sentinel_for<I> S>
requires (!same_as<I, S> && copyable<I>)
class common_iterator; // since C++20
template<class Category, class T, class Distance = ptrdiff_t,
class Pointer = T*, class Reference = T&>
struct iterator // deprecated in C++17
@ -564,6 +568,7 @@ template <class E> constexpr const E* data(initializer_list<E> il) noexcept;
#include <__iterator/access.h>
#include <__iterator/advance.h>
#include <__iterator/back_insert_iterator.h>
#include <__iterator/common_iterator.h>
#include <__iterator/concepts.h>
#include <__iterator/data.h>
#include <__iterator/default_sentinel.h>

View File

@ -480,6 +480,7 @@ module std [system] {
module access { private header "__iterator/access.h" }
module advance { private header "__iterator/advance.h" }
module back_insert_iterator { private header "__iterator/back_insert_iterator.h" }
module common_iterator { private header "__iterator/common_iterator.h" }
module concepts { private header "__iterator/concepts.h" }
module data { private header "__iterator/data.h" }
module default_sentinel { private header "__iterator/default_sentinel.h" }

View File

@ -201,12 +201,12 @@ namespace std {
#include <__availability>
#include <__config>
#include <__functional/hash.h>
#include <__tuple>
#include <__utility/forward.h>
#include <__variant/monostate.h>
#include <__tuple>
#include <compare>
#include <exception>
#include <functional>
#include <initializer_list>
#include <limits>
#include <new>
@ -1748,6 +1748,28 @@ struct _LIBCPP_TEMPLATE_VIS hash<
}
};
// __unchecked_get is the same as std::get, except, it is UB to use it with the wrong
// type whereas std::get will throw or returning nullptr. This makes it faster than
// std::get.
template <size_t _Ip, class _Vp>
inline _LIBCPP_INLINE_VISIBILITY
constexpr auto&& __unchecked_get(_Vp&& __v) noexcept {
using __variant_detail::__access::__variant;
return __variant::__get_alt<_Ip>(_VSTD::forward<_Vp>(__v)).__value;
}
template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY
constexpr auto&& __unchecked_get(const variant<_Types...>& __v) noexcept {
return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
}
template <class _Tp, class... _Types>
inline _LIBCPP_INLINE_VISIBILITY
constexpr auto&& __unchecked_get(variant<_Types...>& __v) noexcept {
return __unchecked_get<__find_exactly_one_t<_Tp, _Types...>::value>(__v);
}
#endif // _LIBCPP_STD_VER > 14
_LIBCPP_END_NAMESPACE_STD

View File

@ -0,0 +1,90 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// decltype(auto) operator->() const
// requires see below;
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// Case 2: http://eel.is/c++draft/iterators.common#common.iter.access-5.2
{
auto iter1 = simple_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(commonIter1.operator->() == buffer);
assert(commonIter2.operator->() == buffer);
}
// Case 3: http://eel.is/c++draft/iterators.common#common.iter.access-5.3
{
auto iter1 = value_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*commonIter1.operator->().operator->() == 1);
assert(*commonIter2.operator->().operator->() == 1);
}
// Case 3: http://eel.is/c++draft/iterators.common#common.iter.access-5.3
{
auto iter1 = void_plus_plus_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*commonIter1.operator->().operator->() == 1);
assert(*commonIter2.operator->().operator->() == 1);
}
// Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(commonIter1.operator->().base() == buffer);
assert(commonIter2.operator->().base() == buffer);
}
// Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(commonIter1.operator->().base() == buffer);
assert(commonIter2.operator->().base() == buffer);
}
// Case 1: http://eel.is/c++draft/iterators.common#common.iter.access-5.1
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(commonIter1.operator->().base() == buffer);
assert(commonIter2.operator->().base() == buffer);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,144 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// template<class I2, class S2>
// requires convertible_to<const I2&, I> && convertible_to<const S2&, S> &&
// assignable_from<I&, const I2&> && assignable_from<S&, const S2&>
// common_iterator& operator=(const common_iterator<I2, S2>& x);
#include <iterator>
#include <ranges>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(cpp17_input_iterator<int*>(buffer + 1));
assert(*commonIter1 == 1);
assert(*commonIter2 == 2);
assert(commonIter1 != commonIter2);
commonIter1 = commonIter2;
assert(*commonIter1 == 2);
assert(*commonIter2 == 2);
assert(commonIter1 == commonIter2);
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(forward_iterator<int*>(buffer + 1));
assert(*commonIter1 == 1);
assert(*commonIter2 == 2);
assert(commonIter1 != commonIter2);
commonIter1 = commonIter2;
assert(*commonIter1 == 2);
assert(*commonIter2 == 2);
assert(commonIter1 == commonIter2);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1 + 1);
auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 7});
assert(*commonIter1 == 1);
assert(*commonIter2 == 2);
assert(commonIter1 != commonIter2);
commonIter1 = commonIter2;
assert(*commonIter1 == 2);
assert(*commonIter2 == 2);
assert(commonIter1 == commonIter2);
assert(std::ranges::next(commonIter1, 6) != commonSent1);
assert(std::ranges::next(commonIter1, 6) == commonSent2);
commonSent1 = commonSent2;
assert(std::ranges::next(commonIter1, 6) == commonSent1);
assert(std::ranges::next(commonIter1, 6) == commonSent2);
}
{
auto iter1 = assignable_iterator<int*>(buffer);
auto iter2 = forward_iterator<int*>(buffer + 1);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
auto commonSent2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(sentinel_type<int*>{buffer + 7});
assert(*commonIter1 == 1);
assert(*commonIter2 == 2);
commonIter1 = commonIter2;
assert(*commonIter1 == 2);
assert(*commonIter2 == 2);
assert(commonIter1 == commonIter2);
assert(std::ranges::next(commonIter1, 6) != commonSent1);
assert(std::ranges::next(commonIter1, 6) == commonSent2);
commonSent1 = commonSent2;
assert(std::ranges::next(commonIter1, 6) == commonSent1);
assert(std::ranges::next(commonIter1, 6) == commonSent2);
commonIter1 = commonSent1;
assert(commonIter1 == commonSent2);
commonIter1 = commonSent2;
assert(commonIter1 == commonSent2);
}
#ifndef TEST_HAS_NO_EXCEPTIONS
{
auto iter1 = maybe_valueless_iterator<int*>(buffer);
auto iter2 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent2 = std::common_iterator<decltype(iter1),
sentinel_throws_on_convert<int*>>(sentinel_throws_on_convert<int*>{buffer + 8});
auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
try {
commonIter1 = commonSent2;
assert(false);
} catch (int x) {
assert(x == 42);
commonIter1 = commonIter2;
}
assert(*commonIter1 == 1);
}
#endif // TEST_HAS_NO_EXCEPTIONS
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// constexpr common_iterator() requires default_initializable<I> = default;
// constexpr common_iterator(I i);
// constexpr common_iterator(S s);
// template<class I2, class S2>
// requires convertible_to<const I2&, I> && convertible_to<const S2&, S>
// constexpr common_iterator(const common_iterator<I2, S2>& x);
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
template<class I, class S>
concept ValidCommonIterator = requires {
typename std::common_iterator<I, S>;
};
template<class I, class I2>
concept ConvCtorEnabled = requires(std::common_iterator<I2, sentinel_type<int*>> ci) {
std::common_iterator<I, sentinel_type<int*>>(ci);
};
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
static_assert( std::is_default_constructible_v<std::common_iterator<int*, sentinel_type<int*>>>);
static_assert(!std::is_default_constructible_v<std::common_iterator<non_default_constructible_iterator<int*>, sentinel_type<int*>>>);
// Not copyable:
static_assert(!ValidCommonIterator<cpp20_input_iterator<int*>, sentinel_type<int*>>);
// Same iter and sent:
static_assert(!ValidCommonIterator<cpp17_input_iterator<int*>, cpp17_input_iterator<int*>>);
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(commonIter1 != commonSent1);
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(commonIter1 != commonSent1);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(commonIter1 != commonSent1);
}
// Conversion constructor:
{
convertible_iterator<int*> conv{buffer};
auto commonIter1 = std::common_iterator<convertible_iterator<int*>, sentinel_type<int*>>(conv);
auto commonIter2 = std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>(commonIter1);
assert(*commonIter2 == 1);
static_assert( ConvCtorEnabled<forward_iterator<int*>, convertible_iterator<int*>>);
static_assert(!ConvCtorEnabled<forward_iterator<int*>, random_access_iterator<int*>>);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,147 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// decltype(auto) operator*();
// decltype(auto) operator*() const
// requires dereferenceable<const I>;
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = simple_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto iter2 = simple_iterator<int*>(buffer);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(*iter2 == 1);
assert(*commonIter2 == 1);
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
}
{
auto iter1 = value_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto iter2 = value_iterator<int*>(buffer);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(*iter2 == 1);
assert(*commonIter2 == 1);
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
}
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto iter2 = cpp17_input_iterator<int*>(buffer);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(*iter2 == 1);
assert(*commonIter2 == 1);
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto iter2 = forward_iterator<int*>(buffer);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(*iter2 == 1);
assert(*commonIter2 == 1);
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto iter2 = random_access_iterator<int*>(buffer);
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(*iter1 == 1);
assert(*commonIter1 == 1);
assert(*iter2 == 1);
assert(*commonIter2 == 1);
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,168 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// template<class I2, sentinel_for<I> S2>
// requires sentinel_for<S, I2>
// friend bool operator==(
// const common_iterator& x, const common_iterator<I2, S2>& y);
// template<class I2, sentinel_for<I> S2>
// requires sentinel_for<S, I2> && equality_comparable_with<I, I2>
// friend bool operator==(
// const common_iterator& x, const common_iterator<I2, S2>& y);
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = simple_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
}
{
auto iter1 = value_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
}
{
auto iter1 = simple_iterator<int*>(buffer);
auto iter2 = comparable_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(iter2);
const auto commonSent2 = std::common_iterator<decltype(iter2), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 == commonIter2);
assert(commonSent1 != commonIter2);
assert(commonSent1 == commonSent2);
assert(commonSent2 == commonSent1);
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
assert(commonIter1 == commonIter2);
assert(commonIter2 == commonIter1);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
// This check may *seem* incorrect (our iterators point to two completely different
// elements of buffer). However, this is actually what the Standard wants.
// See https://eel.is/c++draft/iterators.common#common.iter.cmp-2.
assert(commonIter1 == commonIter2);
}
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
const auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
const auto commonSent2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(commonIter1 != commonSent1);
assert(commonIter2 != commonSent2);
assert(commonSent1 != commonIter1);
assert(commonSent2 != commonIter2);
assert(commonSent1 == commonSent2);
assert(commonSent2 == commonSent1);
for (auto i = 1; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
assert(commonSent1 == commonIter1);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// friend iter_rvalue_reference_t<I> iter_move(const common_iterator& i)
// noexcept(noexcept(ranges::iter_move(declval<const I&>())))
// requires input_iterator<I>;
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(std::ranges::iter_move(commonIter1) == 1);
ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(std::ranges::iter_move(commonIter1) == 1);
ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
assert(std::ranges::iter_move(commonIter1) == 1);
ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,65 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// template<indirectly_swappable<I> I2, class S2>
// friend void iter_swap(const common_iterator& x, const common_iterator<I2, S2>& y)
// noexcept(noexcept(ranges::iter_swap(declval<const I&>(), declval<const I2&>())));
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
for (auto i = 0; i < 4; ++i) ++commonIter2;
assert(*commonIter2 == 5);
std::ranges::iter_swap(commonIter1, commonIter2);
assert(*commonIter1 == 5);
assert(*commonIter2 == 1);
std::ranges::iter_swap(commonIter2, commonIter1);
}
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
for (auto i = 0; i < 4; ++i) ++commonIter2;
assert(*commonIter2 == 5);
std::ranges::iter_swap(commonIter1, commonIter2);
assert(*commonIter1 == 5);
assert(*commonIter2 == 1);
std::ranges::iter_swap(commonIter2, commonIter1);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
for (auto i = 0; i < 4; ++i) ++commonIter2;
assert(*commonIter2 == 5);
std::ranges::iter_swap(commonIter1, commonIter2);
assert(*commonIter1 == 5);
assert(*commonIter2 == 1);
std::ranges::iter_swap(commonIter2, commonIter1);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,110 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// template<input_iterator I, class S>
// struct iterator_traits<common_iterator<I, S>>;
#include <iterator>
#include "test_macros.h"
#include "types.h"
void test() {
{
using Iter = simple_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
static_assert(std::same_as<IterTraits::pointer, int*>);
static_assert(std::same_as<IterTraits::reference, int&>);
}
{
using Iter = value_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
// Note: IterTraits::pointer == __proxy.
static_assert(!std::same_as<IterTraits::pointer, int*>);
static_assert(std::same_as<IterTraits::reference, int>);
}
{
using Iter = non_const_deref_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
static_assert(std::same_as<IterTraits::pointer, void>);
static_assert(std::same_as<IterTraits::reference, int&>);
}
{
using Iter = cpp17_input_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::input_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
static_assert(std::same_as<IterTraits::pointer, const Iter&>);
static_assert(std::same_as<IterTraits::reference, int&>);
}
{
using Iter = forward_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::forward_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
static_assert(std::same_as<IterTraits::pointer, const Iter&>);
static_assert(std::same_as<IterTraits::reference, int&>);
}
{
using Iter = random_access_iterator<int*>;
using CommonIter = std::common_iterator<Iter, sentinel_type<int*>>;
using IterTraits = std::iterator_traits<CommonIter>;
static_assert(std::same_as<IterTraits::iterator_concept, std::forward_iterator_tag>);
static_assert(std::same_as<IterTraits::iterator_category, std::forward_iterator_tag>);
static_assert(std::same_as<IterTraits::value_type, int>);
static_assert(std::same_as<IterTraits::difference_type, std::ptrdiff_t>);
static_assert(std::same_as<IterTraits::pointer, const Iter&>);
static_assert(std::same_as<IterTraits::reference, int&>);
}
// Testing iterator conformance.
{
static_assert(std::input_iterator<std::common_iterator<cpp17_input_iterator<int*>, sentinel_type<int*>>>);
static_assert(std::forward_iterator<std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>>);
static_assert(std::forward_iterator<std::common_iterator<random_access_iterator<int*>, sentinel_type<int*>>>);
static_assert(std::forward_iterator<std::common_iterator<contiguous_iterator<int*>, sentinel_type<int*>>>);
// Even these are only forward.
static_assert(!std::bidirectional_iterator<std::common_iterator<random_access_iterator<int*>, sentinel_type<int*>>>);
static_assert(!std::bidirectional_iterator<std::common_iterator<contiguous_iterator<int*>, sentinel_type<int*>>>);
using Iter = std::common_iterator<forward_iterator<int*>, sentinel_type<int*>>;
static_assert(std::indirectly_writable<Iter, int>);
static_assert(std::indirectly_swappable<Iter, Iter>);
}
}

View File

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// template<sized_sentinel_for<I> I2, sized_sentinel_for<I> S2>
// requires sized_sentinel_for<S, I2>
// friend iter_difference_t<I2> operator-(
// const common_iterator& x, const common_iterator<I2, S2>& y);
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(sized_sentinel_type<int*>{buffer + 8});
assert(commonIter1 - commonSent1 == -8);
assert(commonSent1 - commonIter1 == 8);
assert(commonIter1 - commonIter1 == 0);
assert(commonSent1 - commonSent1 == 0);
}
{
auto iter1 = simple_iterator<int*>(buffer);
auto iter2 = comparable_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
auto commonIter2 = std::common_iterator<decltype(iter2), sized_sentinel_type<int*>>(iter2);
assert(commonIter1 - commonIter2 == 0);
}
{
auto iter1 = random_access_iterator<int*>(buffer);
const auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
const auto commonSent1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(sized_sentinel_type<int*>{buffer + 8});
assert(commonIter1 - commonSent1 == -8);
assert(commonSent1 - commonIter1 == 8);
assert(commonIter1 - commonIter1 == 0);
assert(commonSent1 - commonSent1 == 0);
}
{
auto iter1 = simple_iterator<int*>(buffer);
auto iter2 = comparable_iterator<int*>(buffer);
const auto commonIter1 = std::common_iterator<decltype(iter1), sized_sentinel_type<int*>>(iter1);
const auto commonIter2 = std::common_iterator<decltype(iter2), sized_sentinel_type<int*>>(iter2);
assert(commonIter1 - commonIter2 == 0);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,155 @@
//===----------------------------------------------------------------------===//
//
// 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: gcc-10
// common_iterator& operator++();
// decltype(auto) operator++(int);
#include <iterator>
#include <cassert>
#include "test_macros.h"
#include "types.h"
struct Incomplete;
void test() {
int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
// Reference: http://eel.is/c++draft/iterators.common#common.iter.nav-5
// Case 2: can-reference
{
auto iter1 = simple_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
// Case 2: can-reference
{
auto iter1 = value_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
// Case 3: postfix-proxy
{
auto iter1 = void_plus_plus_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
// Case 2: where this is not referencable or move constructible
{
auto iter1 = value_type_not_move_constructible_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
commonIter1++;
// Note: postfix operator++ returns void.
// assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*commonIter1 == i);
commonIter1++;
}
assert(commonIter1 == commonSent1);
}
// Case 2: can-reference
{
auto iter1 = cpp17_input_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
// Case 1: forward_iterator
{
auto iter1 = forward_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
// Case 1: forward_iterator
{
auto iter1 = random_access_iterator<int*>(buffer);
auto commonIter1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(iter1);
auto commonSent1 = std::common_iterator<decltype(iter1), sentinel_type<int*>>(sentinel_type<int*>{buffer + 8});
assert(*(commonIter1++) == 1);
assert(*commonIter1 == 2);
assert(*(++commonIter1) == 3);
assert(*commonIter1 == 3);
for (auto i = 3; commonIter1 != commonSent1; ++i) {
assert(*(commonIter1++) == i);
}
assert(commonIter1 == commonSent1);
}
}
int main(int, char**) {
test();
return 0;
}

View File

@ -0,0 +1,316 @@
//===----------------------------------------------------------------------===//
//
// 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 TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H
#define TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H
#include "test_macros.h"
#include "test_iterators.h"
template <class>
class assignable_iterator;
template <class It>
class simple_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
simple_iterator() = default;
explicit constexpr simple_iterator(It it) : it_(it) {}
constexpr reference operator*() const {return *it_;}
constexpr simple_iterator& operator++() {++it_; return *this;}
constexpr simple_iterator operator++(int)
{simple_iterator tmp(*this); ++(*this); return tmp;}
};
template <class It>
class value_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
value_iterator() = default;
explicit constexpr value_iterator(It it) : it_(it) {}
constexpr value_type operator*() const {return std::move(*it_);}
constexpr value_iterator& operator++() {++it_; return *this;}
constexpr value_iterator operator++(int)
{value_iterator tmp(*this); ++(*this); return tmp;}
};
template <class It>
class void_plus_plus_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
void_plus_plus_iterator() = default;
explicit constexpr void_plus_plus_iterator(It it) : it_(it) {}
constexpr value_type operator*() const {return std::move(*it_);}
constexpr void_plus_plus_iterator& operator++() {++it_; return *this;}
constexpr void operator++(int) {++(*this);}
};
// Not referenceable, constructible, and not move constructible.
template <class It>
class value_type_not_move_constructible_iterator
{
It it_;
public:
template<class T>
struct hold {
T value_;
hold(T v) : value_(v) {}
hold(const hold&) = delete;
hold(hold&&) = delete;
};
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type underlying_value_type;
typedef hold<underlying_value_type> value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
value_type_not_move_constructible_iterator() = default;
explicit constexpr value_type_not_move_constructible_iterator(It it) : it_(it) {}
constexpr underlying_value_type operator*() const {return std::move(*it_);}
constexpr value_type_not_move_constructible_iterator& operator++() {++it_; return *this;}
constexpr void operator++(int) {++(*this);}
};
template <class It>
class comparable_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
comparable_iterator() = default;
explicit constexpr comparable_iterator(It it) : it_(it) {}
constexpr reference operator*() const {return *it_;}
constexpr comparable_iterator& operator++() {++it_; return *this;}
constexpr comparable_iterator operator++(int)
{comparable_iterator tmp(*this); ++(*this); return tmp;}
friend constexpr bool operator==(const comparable_iterator& lhs, const simple_iterator<It>& rhs) {
return lhs.base() == rhs.base();
}
friend constexpr bool operator==(const simple_iterator<It>& lhs, const comparable_iterator& rhs) {
return lhs.base() == rhs.base();
}
friend constexpr auto operator-(const comparable_iterator& lhs, const simple_iterator<It>& rhs) {
return lhs.base() - rhs.base();
}
friend constexpr auto operator-(const simple_iterator<It>& lhs, const comparable_iterator& rhs) {
return lhs.base() - rhs.base();
}
};
template <class It>
class convertible_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
convertible_iterator() = default;
explicit constexpr convertible_iterator(It it) : it_(it) {}
constexpr reference operator*() const {return *it_;}
constexpr convertible_iterator& operator++() {++it_; return *this;}
constexpr convertible_iterator operator++(int)
{convertible_iterator tmp(*this); ++(*this); return tmp;}
operator forward_iterator<It>() const { return forward_iterator<It>(it_); }
};
template <class It>
class non_const_deref_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
non_const_deref_iterator() = default;
explicit constexpr non_const_deref_iterator(It it) : it_(it) {}
constexpr reference operator*() {return *it_;} // Note: non-const.
constexpr non_const_deref_iterator& operator++() {++it_; return *this;}
constexpr non_const_deref_iterator operator++(int)
{non_const_deref_iterator tmp(*this); ++(*this); return tmp;}
};
template<class T>
struct sentinel_type {
T base;
template<class U>
friend constexpr bool operator==(const sentinel_type& lhs, const U& rhs) { return lhs.base == rhs.base(); }
template<class U>
friend constexpr bool operator==(const U& lhs, const sentinel_type& rhs) { return lhs.base() == rhs.base; }
};
template<class T>
struct sized_sentinel_type {
T base;
template<class U>
friend constexpr bool operator==(const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); }
template<class U>
friend constexpr bool operator==(const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; }
template<class U>
friend constexpr auto operator- (const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); }
template<class U>
friend constexpr auto operator- (const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; }
};
template <class It>
class assignable_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
assignable_iterator() = default;
explicit constexpr assignable_iterator(It it) : it_(it) {}
assignable_iterator(const forward_iterator<It>& it) : it_(it.base()) {}
assignable_iterator(const sentinel_type<It>& it) : it_(it.base) {}
constexpr reference operator*() const {return *it_;}
constexpr assignable_iterator& operator++() {++it_; return *this;}
constexpr assignable_iterator operator++(int)
{assignable_iterator tmp(*this); ++(*this); return tmp;}
assignable_iterator& operator=(const forward_iterator<It> &other) {
it_ = other.base();
return *this;
}
assignable_iterator& operator=(const sentinel_type<It> &other) {
it_ = other.base;
return *this;
}
};
#ifndef TEST_HAS_NO_EXCEPTIONS
template<class T>
struct sentinel_throws_on_convert {
T base;
template<class U>
friend constexpr bool operator==(const sentinel_throws_on_convert& lhs, const U& rhs) { return lhs.base == rhs.base(); }
template<class U>
friend constexpr bool operator==(const U& lhs, const sentinel_throws_on_convert& rhs) { return lhs.base() == rhs.base; }
operator sentinel_type<int*>() const { throw 42; }
};
template <class It>
class maybe_valueless_iterator
{
It it_;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
constexpr It base() const {return it_;}
maybe_valueless_iterator() = default;
explicit constexpr maybe_valueless_iterator(It it) : it_(it) {}
maybe_valueless_iterator(const forward_iterator<It>& it) : it_(it.base()) {}
constexpr reference operator*() const {return *it_;}
constexpr maybe_valueless_iterator& operator++() {++it_; return *this;}
constexpr maybe_valueless_iterator operator++(int)
{maybe_valueless_iterator tmp(*this); ++(*this); return tmp;}
maybe_valueless_iterator& operator=(const forward_iterator<It> &other) {
it_ = other.base();
return *this;
}
};
#endif // TEST_HAS_NO_EXCEPTIONS
#endif // TEST_STD_RANGES_ITERATORS_PREDEF_ITERATORS_ITERATORS_COMMON_TYPES_H

View File

@ -161,6 +161,59 @@ operator!=(const forward_iterator<T>& x, const forward_iterator<U>& y)
return !(x == y);
}
template <class It>
class non_default_constructible_iterator
{
It it_;
template <class U> friend class non_default_constructible_iterator;
public:
typedef std::input_iterator_tag iterator_category;
typedef typename std::iterator_traits<It>::value_type value_type;
typedef typename std::iterator_traits<It>::difference_type difference_type;
typedef It pointer;
typedef typename std::iterator_traits<It>::reference reference;
TEST_CONSTEXPR_CXX14 It base() const {return it_;}
non_default_constructible_iterator() = delete;
explicit TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(It it) : it_(it) {}
template <class U>
TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(const non_default_constructible_iterator<U>& u) :it_(u.it_) {}
TEST_CONSTEXPR_CXX14 reference operator*() const {return *it_;}
TEST_CONSTEXPR_CXX14 pointer operator->() const {return it_;}
TEST_CONSTEXPR_CXX14 non_default_constructible_iterator& operator++() {++it_; return *this;}
TEST_CONSTEXPR_CXX14 non_default_constructible_iterator operator++(int)
{non_default_constructible_iterator tmp(*this); ++(*this); return tmp;}
friend TEST_CONSTEXPR_CXX14 bool operator==(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y)
{return x.it_ == y.it_;}
friend TEST_CONSTEXPR_CXX14 bool operator!=(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y)
{return !(x == y);}
template <class T>
void operator,(T const &) DELETE_FUNCTION;
};
template <class T, class U>
inline
bool TEST_CONSTEXPR_CXX14
operator==(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y)
{
return x.base() == y.base();
}
template <class T, class U>
inline
bool TEST_CONSTEXPR_CXX14
operator!=(const non_default_constructible_iterator<T>& x, const non_default_constructible_iterator<U>& y)
{
return !(x == y);
}
template <class It>
class bidirectional_iterator
{