diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -77,7 +77,7 @@ [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 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -133,6 +133,7 @@ __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 --- /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 +#include + +#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 _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>(__x)) {} + + public: + constexpr static bool __valid_for_iter = + constructible_from, iter_reference_t<_Iter>> && + move_constructible>; + + 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 + requires convertible_to && convertible_to + 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 + requires convertible_to && convertible_to && + 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 + { + _LIBCPP_ASSERT(holds_alternative<_Iter>(__hold_), + "Cannot dereference sentinel. Common iterator not holding an iterator."); + return *_VSTD::__unchecked_get<_Iter>(__hold_); + } + + template + decltype(auto) operator->() const + requires indirectly_readable && + (requires(const _I2& __i) { __i.operator->(); } || + is_reference_v> || + constructible_from, 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>) { + 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 _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 _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 _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()))) + 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 _I2, class _S2> + friend void iter_swap(const common_iterator& __x, const common_iterator<_I2, _S2>& __y) + noexcept(noexcept(ranges::iter_swap(declval(), declval()))) + { + _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 +struct incrementable_traits> { + using difference_type = iter_difference_t<_Iter>; +}; + +template +concept __denotes_forward_iter = + requires { typename iterator_traits<_Iter>::iterator_category; } && + derived_from::iterator_category, forward_iterator_tag>; + +template +concept __common_iter_has_ptr_op = requires(const common_iterator<_Iter, _Sent>& __a) { + __a.operator->(); +}; + +template +struct __arrow_type_or_void { + using type = void; +}; + +template + requires __common_iter_has_ptr_op<_Iter, _Sent> +struct __arrow_type_or_void<_Iter, _Sent> { + using type = decltype(declval>().operator->()); +}; + +template +struct iterator_traits> { + using iterator_concept = _If, + 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 diff --git a/libcxx/include/iterator b/libcxx/include/iterator --- a/libcxx/include/iterator +++ b/libcxx/include/iterator @@ -136,6 +136,10 @@ template concept indirectly_swappable = see below; // since C++20 +template S> + requires (!same_as && copyable) +class common_iterator; // since C++20 + template struct iterator // deprecated in C++17 @@ -564,6 +568,7 @@ #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 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -480,6 +480,7 @@ 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 --- a/libcxx/include/variant +++ b/libcxx/include/variant @@ -201,12 +201,12 @@ #include <__availability> #include <__config> +#include <__functional/hash.h> +#include <__tuple> #include <__utility/forward.h> #include <__variant/monostate.h> -#include <__tuple> #include #include -#include #include #include #include @@ -1748,6 +1748,28 @@ } }; +// __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 +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 +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 +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 --- /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 +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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 --- /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 +// requires convertible_to && convertible_to && +// assignable_from && assignable_from +// common_iterator& operator=(const common_iterator& x); + +#include +#include +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(cpp17_input_iterator(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(forward_iterator(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + auto commonIter2 = std::common_iterator>(iter1 + 1); + auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto iter2 = forward_iterator(buffer + 1); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + auto commonIter2 = std::common_iterator>(iter2); + auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto iter2 = forward_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent2 = std::common_iterator>(sentinel_throws_on_convert{buffer + 8}); + auto commonIter2 = std::common_iterator>(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 --- /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 = default; +// constexpr common_iterator(I i); +// constexpr common_iterator(S s); +// template +// requires convertible_to && convertible_to +// constexpr common_iterator(const common_iterator& x); + +#include +#include + +#include "test_macros.h" +#include "types.h" + +template +concept ValidCommonIterator = requires { + typename std::common_iterator; +}; + +template +concept ConvCtorEnabled = requires(std::common_iterator> ci) { + std::common_iterator>(ci); +}; + +void test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + static_assert( std::is_default_constructible_v>>); + static_assert(!std::is_default_constructible_v, sentinel_type>>); + + // Not copyable: + static_assert(!ValidCommonIterator, sentinel_type>); + // Same iter and sent: + static_assert(!ValidCommonIterator, cpp17_input_iterator>); + + { + auto iter1 = cpp17_input_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + assert(*iter1 == 1); + assert(*commonIter1 == 1); + assert(commonIter1 != commonSent1); + } + { + auto iter1 = forward_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + assert(*iter1 == 1); + assert(*commonIter1 == 1); + assert(commonIter1 != commonSent1); + } + { + auto iter1 = random_access_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + assert(*iter1 == 1); + assert(*commonIter1 == 1); + assert(commonIter1 != commonSent1); + } + + // Conversion constructor: + { + convertible_iterator conv{buffer}; + auto commonIter1 = std::common_iterator, sentinel_type>(conv); + auto commonIter2 = std::common_iterator, sentinel_type>(commonIter1); + assert(*commonIter2 == 1); + + static_assert( ConvCtorEnabled, convertible_iterator>); + static_assert(!ConvCtorEnabled, random_access_iterator>); + } +} + +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 --- /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; + +#include +#include + +#include "test_macros.h" +#include "types.h" + +void test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + auto iter1 = simple_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto iter2 = simple_iterator(buffer); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto iter2 = value_iterator(buffer); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto iter2 = cpp17_input_iterator(buffer); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto iter2 = forward_iterator(buffer); + const auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto iter2 = random_access_iterator(buffer); + const auto commonIter2 = std::common_iterator>(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 --- /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 S2> +// requires sentinel_for +// friend bool operator==( +// const common_iterator& x, const common_iterator& y); +// template S2> +// requires sentinel_for && equality_comparable_with +// friend bool operator==( +// const common_iterator& x, const common_iterator& y); + +#include +#include + +#include "test_macros.h" +#include "types.h" + +void test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + auto iter1 = simple_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter1); + const auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter1); + const auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto iter2 = comparable_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter2); + const auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter1); + const auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter1); + const auto commonSent2 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{buffer + 8}); + + const auto commonIter2 = std::common_iterator>(iter1); + const auto commonSent2 = std::common_iterator>(sentinel_type{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 --- /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 iter_move(const common_iterator& i) +// noexcept(noexcept(ranges::iter_move(declval()))) +// requires input_iterator; + +#include +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + assert(std::ranges::iter_move(commonIter1) == 1); + ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&); + } + { + auto iter1 = forward_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + assert(std::ranges::iter_move(commonIter1) == 1); + ASSERT_SAME_TYPE(decltype(std::ranges::iter_move(commonIter1)), int&&); + } + { + auto iter1 = random_access_iterator(buffer); + auto commonIter1 = std::common_iterator>(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 --- /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 I2, class S2> +// friend void iter_swap(const common_iterator& x, const common_iterator& y) +// noexcept(noexcept(ranges::iter_swap(declval(), declval()))); + +#include +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(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 --- /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 +// struct iterator_traits>; + +#include + +#include "test_macros.h" +#include "types.h" + +void test() { + { + using Iter = simple_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + using Iter = value_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + // Note: IterTraits::pointer == __proxy. + static_assert(!std::same_as); + static_assert(std::same_as); + } + { + using Iter = non_const_deref_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + using Iter = cpp17_input_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + using Iter = forward_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + { + using Iter = random_access_iterator; + using CommonIter = std::common_iterator>; + using IterTraits = std::iterator_traits; + + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + static_assert(std::same_as); + } + + // Testing iterator conformance. + { + static_assert(std::input_iterator, sentinel_type>>); + static_assert(std::forward_iterator, sentinel_type>>); + static_assert(std::forward_iterator, sentinel_type>>); + static_assert(std::forward_iterator, sentinel_type>>); + // Even these are only forward. + static_assert(!std::bidirectional_iterator, sentinel_type>>); + static_assert(!std::bidirectional_iterator, sentinel_type>>); + + using Iter = std::common_iterator, sentinel_type>; + static_assert(std::indirectly_writable); + static_assert(std::indirectly_swappable); + } +} 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 --- /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 I2, sized_sentinel_for S2> +// requires sized_sentinel_for +// friend iter_difference_t operator-( +// const common_iterator& x, const common_iterator& y); + +#include +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sized_sentinel_type{buffer + 8}); + assert(commonIter1 - commonSent1 == -8); + assert(commonSent1 - commonIter1 == 8); + assert(commonIter1 - commonIter1 == 0); + assert(commonSent1 - commonSent1 == 0); + } + { + auto iter1 = simple_iterator(buffer); + auto iter2 = comparable_iterator(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonIter2 = std::common_iterator>(iter2); + + assert(commonIter1 - commonIter2 == 0); + } + { + auto iter1 = random_access_iterator(buffer); + const auto commonIter1 = std::common_iterator>(iter1); + const auto commonSent1 = std::common_iterator>(sized_sentinel_type{buffer + 8}); + assert(commonIter1 - commonSent1 == -8); + assert(commonSent1 - commonIter1 == 8); + assert(commonIter1 - commonIter1 == 0); + assert(commonSent1 - commonSent1 == 0); + } + { + auto iter1 = simple_iterator(buffer); + auto iter2 = comparable_iterator(buffer); + const auto commonIter1 = std::common_iterator>(iter1); + const auto commonIter2 = std::common_iterator>(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 --- /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 +#include + +#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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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(buffer); + auto commonIter1 = std::common_iterator>(iter1); + auto commonSent1 = std::common_iterator>(sentinel_type{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 --- /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 assignable_iterator; + +template +class simple_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 value_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 void_plus_plus_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 value_type_not_move_constructible_iterator +{ + It it_; + +public: + template + 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::value_type underlying_value_type; + typedef hold value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 comparable_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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& rhs) { + return lhs.base() == rhs.base(); + } + friend constexpr bool operator==(const simple_iterator& lhs, const comparable_iterator& rhs) { + return lhs.base() == rhs.base(); + } + + friend constexpr auto operator-(const comparable_iterator& lhs, const simple_iterator& rhs) { + return lhs.base() - rhs.base(); + } + friend constexpr auto operator-(const simple_iterator& lhs, const comparable_iterator& rhs) { + return lhs.base() - rhs.base(); + } +}; + +template +class convertible_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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() const { return forward_iterator(it_); } +}; + +template +class non_const_deref_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 +struct sentinel_type { + T base; + + template + friend constexpr bool operator==(const sentinel_type& lhs, const U& rhs) { return lhs.base == rhs.base(); } + template + friend constexpr bool operator==(const U& lhs, const sentinel_type& rhs) { return lhs.base() == rhs.base; } +}; + +template +struct sized_sentinel_type { + T base; + + template + friend constexpr bool operator==(const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); } + template + friend constexpr bool operator==(const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; } + template + friend constexpr auto operator- (const sized_sentinel_type& lhs, const U& rhs) { return lhs.base - rhs.base(); } + template + friend constexpr auto operator- (const U& lhs, const sized_sentinel_type& rhs) { return lhs.base() - rhs.base; } +}; + +template +class assignable_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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.base()) {} + assignable_iterator(const sentinel_type& 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 &other) { + it_ = other.base(); + return *this; + } + + assignable_iterator& operator=(const sentinel_type &other) { + it_ = other.base; + return *this; + } +}; + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +struct sentinel_throws_on_convert { + T base; + + template + friend constexpr bool operator==(const sentinel_throws_on_convert& lhs, const U& rhs) { return lhs.base == rhs.base(); } + template + friend constexpr bool operator==(const U& lhs, const sentinel_throws_on_convert& rhs) { return lhs.base() == rhs.base; } + + operator sentinel_type() const { throw 42; } +}; + +template +class maybe_valueless_iterator +{ + It it_; + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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.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 &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 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -161,6 +161,59 @@ return !(x == y); } +template +class non_default_constructible_iterator +{ + It it_; + + template friend class non_default_constructible_iterator; +public: + typedef std::input_iterator_tag iterator_category; + typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef It pointer; + typedef typename std::iterator_traits::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 + TEST_CONSTEXPR_CXX14 non_default_constructible_iterator(const non_default_constructible_iterator& 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 + void operator,(T const &) DELETE_FUNCTION; +}; + +template +inline +bool TEST_CONSTEXPR_CXX14 +operator==(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) +{ + return x.base() == y.base(); +} + +template +inline +bool TEST_CONSTEXPR_CXX14 +operator!=(const non_default_constructible_iterator& x, const non_default_constructible_iterator& y) +{ + return !(x == y); +} + template class bidirectional_iterator {