| //===----------------------------------------------------------------------===// |
| // |
| // 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, c++20 |
| |
| // Iterator traits and member typedefs in zip_view::<iterator>. |
| |
| #include <array> |
| #include <ranges> |
| #include <tuple> |
| |
| #include "test_iterators.h" |
| |
| #include "../types.h" |
| |
| template <class T> |
| struct ForwardView : std::ranges::view_base { |
| forward_iterator<T*> begin() const; |
| sentinel_wrapper<forward_iterator<T*>> end() const; |
| }; |
| |
| template <class T> |
| struct InputView : std::ranges::view_base { |
| cpp17_input_iterator<T*> begin() const; |
| sentinel_wrapper<cpp17_input_iterator<T*>> end() const; |
| }; |
| |
| template <class T> |
| concept HasIterCategory = requires { typename T::iterator_category; }; |
| |
| template <class T> |
| struct DiffTypeIter { |
| using iterator_category = std::input_iterator_tag; |
| using value_type = int; |
| using difference_type = T; |
| |
| int operator*() const; |
| DiffTypeIter& operator++(); |
| void operator++(int); |
| friend constexpr bool operator==(DiffTypeIter, DiffTypeIter) = default; |
| }; |
| |
| template <class T> |
| struct DiffTypeRange { |
| DiffTypeIter<T> begin() const; |
| DiffTypeIter<T> end() const; |
| }; |
| |
| struct Foo {}; |
| struct Bar {}; |
| |
| struct ConstVeryDifferentRange { |
| int* begin(); |
| int* end(); |
| |
| forward_iterator<double*> begin() const; |
| forward_iterator<double*> end() const; |
| }; |
| |
| void test() { |
| int buffer[] = {1, 2, 3, 4}; |
| { |
| // 2 views should have pair value_type |
| // random_access_iterator_tag |
| std::ranges::zip_view v(buffer, buffer); |
| using Iter = decltype(v.begin()); |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| #ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet |
| static_assert(std::is_same_v<Iter::value_type, std::pair<int, int>>); |
| #else |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int, int>>); |
| #endif |
| static_assert(HasIterCategory<Iter>); |
| } |
| |
| { |
| // !=2 views should have tuple value_type |
| std::ranges::zip_view v(buffer, buffer, buffer); |
| using Iter = decltype(v.begin()); |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int, int, int>>); |
| static_assert(HasIterCategory<Iter>); |
| } |
| |
| { |
| // bidirectional_iterator_tag |
| std::ranges::zip_view v(BidiCommonView{buffer}); |
| using Iter = decltype(v.begin()); |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::bidirectional_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>); |
| } |
| |
| { |
| // forward_iterator_tag |
| using Iter = std::ranges::iterator_t<std::ranges::zip_view<ForwardView<int>>>; |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::forward_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>); |
| static_assert(HasIterCategory<Iter>); |
| } |
| |
| { |
| // nested zip_view |
| std::ranges::zip_view v(buffer, buffer); |
| std::ranges::zip_view v2(buffer, v); |
| using Iter = decltype(v2.begin()); |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| #ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet |
| static_assert(std::is_same_v<Iter::value_type, std::pair<int, std::pair<int, int>>>); |
| #else |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int, std::tuple<int, int>>>); |
| #endif |
| static_assert(HasIterCategory<Iter>); |
| } |
| |
| { |
| // input_iterator_tag |
| using Iter = std::ranges::iterator_t<std::ranges::zip_view<InputView<int>>>; |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::input_iterator_tag>); |
| static_assert(!HasIterCategory<Iter>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>); |
| } |
| |
| { |
| // difference_type of single view |
| std::ranges::zip_view v{DiffTypeRange<std::intptr_t>{}}; |
| using Iter = decltype(v.begin()); |
| static_assert(std::is_same_v<Iter::difference_type, std::intptr_t>); |
| } |
| |
| { |
| // difference_type of multiple views should be the common type |
| std::ranges::zip_view v{DiffTypeRange<std::intptr_t>{}, DiffTypeRange<std::ptrdiff_t>{}}; |
| using Iter = decltype(v.begin()); |
| static_assert(std::is_same_v<Iter::difference_type, std::common_type_t<std::intptr_t, std::ptrdiff_t>>); |
| } |
| |
| const std::array foos{Foo{}}; |
| std::array bars{Bar{}, Bar{}}; |
| { |
| // value_type of single view |
| std::ranges::zip_view v{foos}; |
| using Iter = decltype(v.begin()); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<Foo>>); |
| } |
| |
| { |
| // value_type of multiple views with different value_type |
| std::ranges::zip_view v{foos, bars}; |
| using Iter = decltype(v.begin()); |
| #ifdef _LIBCPP_VERSION // libc++ doesn't implement P2165R4 yet |
| static_assert(std::is_same_v<Iter::value_type, std::pair<Foo, Bar>>); |
| #else |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<Foo, Bar>>); |
| #endif |
| } |
| |
| { |
| // const-iterator different from iterator |
| std::ranges::zip_view v{ConstVeryDifferentRange{}}; |
| using Iter = decltype(v.begin()); |
| using ConstIter = decltype(std::as_const(v).begin()); |
| |
| static_assert(std::is_same_v<Iter::iterator_concept, std::random_access_iterator_tag>); |
| static_assert(std::is_same_v<Iter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<Iter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<Iter::value_type, std::tuple<int>>); |
| |
| static_assert(std::is_same_v<ConstIter::iterator_concept, std::forward_iterator_tag>); |
| static_assert(std::is_same_v<ConstIter::iterator_category, std::input_iterator_tag>); |
| static_assert(std::is_same_v<ConstIter::difference_type, std::ptrdiff_t>); |
| static_assert(std::is_same_v<ConstIter::value_type, std::tuple<double>>); |
| } |
| |
| } |