[libcxx-commits] [libcxx] 1a29403 - [libcxx][ranges] Add common_iterator.
via libcxx-commits
libcxx-commits at lists.llvm.org
Tue Jul 20 08:13:22 PDT 2021
Author: zoecarver
Date: 2021-07-20T08:12:44-07:00
New Revision: 1a29403d2f8a0d74effcee6ab3d29d361fe97276
URL: https://github.com/llvm/llvm-project/commit/1a29403d2f8a0d74effcee6ab3d29d361fe97276
DIFF: https://github.com/llvm/llvm-project/commit/1a29403d2f8a0d74effcee6ab3d29d361fe97276.diff
LOG: [libcxx][ranges] Add common_iterator.
Differential Revision: https://reviews.llvm.org/D103335
Added:
libcxx/include/__iterator/common_iterator.h
libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
Modified:
libcxx/docs/Status/RangesPaper.csv
libcxx/include/CMakeLists.txt
libcxx/include/iterator
libcxx/include/module.modulemap
libcxx/include/variant
libcxx/test/support/test_iterators.h
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 4ee8d0d74b1d1..3fadfc3f15fad 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -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]
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 57304baeba31b..fd86cf114822c 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -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
diff --git a/libcxx/include/__iterator/common_iterator.h b/libcxx/include/__iterator/common_iterator.h
new file mode 100644
index 0000000000000..fb01d8bd4b955
--- /dev/null
+++ b/libcxx/include/__iterator/common_iterator.h
@@ -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_
diff erence_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
diff erence_type = iter_
diff erence_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
diff erence_type = iter_
diff erence_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
diff --git a/libcxx/include/iterator b/libcxx/include/iterator
index 52b04e4cc779c..80f3827b72034 100644
--- a/libcxx/include/iterator
+++ b/libcxx/include/iterator
@@ -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 = ptr
diff _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>
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 1d22f866dea79..ecd853c8536b3 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -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" }
diff --git a/libcxx/include/variant b/libcxx/include/variant
index 7e8b683953d42..700e6f3f11514 100644
--- a/libcxx/include/variant
+++ b/libcxx/include/variant
@@ -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
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
new file mode 100644
index 0000000000000..f3b741d1c4c95
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/arrow.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
new file mode 100644
index 0000000000000..baa759f78462c
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/assign.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
new file mode 100644
index 0000000000000..d8226a142b111
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/ctor.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
new file mode 100644
index 0000000000000..533a4a48b0065
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/deref.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
new file mode 100644
index 0000000000000..7d7513b369cc0
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/eq.pass.cpp
@@ -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
diff erent
+ // 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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
new file mode 100644
index 0000000000000..b79f0590e7cdd
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_move.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
new file mode 100644
index 0000000000000..348c9fab21547
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iter_swap.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
new file mode 100644
index 0000000000000..8309ab7f732da
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/iterator_traits.compile.pass.cpp
@@ -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::
diff erence_type, std::ptr
diff _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::
diff erence_type, std::ptr
diff _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::
diff erence_type, std::ptr
diff _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::
diff erence_type, std::ptr
diff _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::
diff erence_type, std::ptr
diff _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::
diff erence_type, std::ptr
diff _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>);
+ }
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
new file mode 100644
index 0000000000000..41f8c77268c93
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/minus.pass.cpp
@@ -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_
diff erence_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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
new file mode 100644
index 0000000000000..4d8ef3984cb00
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/plus_plus.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
new file mode 100644
index 0000000000000..d5068b3cf013f
--- /dev/null
+++ b/libcxx/test/std/iterators/predef.iterators/iterators.common/types.h
@@ -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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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>::
diff erence_type
diff erence_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
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h
index bb1671b909352..7e094428b72f4 100644
--- a/libcxx/test/support/test_iterators.h
+++ b/libcxx/test/support/test_iterators.h
@@ -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>::
diff erence_type
diff erence_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
{
More information about the libcxx-commits
mailing list