1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
10 // UNSUPPORTED: libcpp-no-concepts
11 // UNSUPPORTED: gcc-10
12 
13 // constexpr counted_iterator& operator++();
14 // decltype(auto) operator++(int);
15 // constexpr counted_iterator operator++(int)
16 //   requires forward_iterator<I>;
17 
18 #include <iterator>
19 
20 #include "test_macros.h"
21 #include "test_iterators.h"
22 
23 #ifndef TEST_HAS_NO_EXCEPTIONS
24 template <class It>
25 class ThrowsOnInc
26 {
27     It it_;
28 
29 public:
30     typedef          std::input_iterator_tag                   iterator_category;
31     typedef typename std::iterator_traits<It>::value_type      value_type;
32     typedef typename std::iterator_traits<It>::difference_type difference_type;
33     typedef It                                                 pointer;
34     typedef typename std::iterator_traits<It>::reference       reference;
35 
36     constexpr It base() const {return it_;}
37 
38     ThrowsOnInc() = default;
39     explicit constexpr ThrowsOnInc(It it) : it_(it) {}
40 
41     constexpr reference operator*() const {return *it_;}
42 
43     constexpr ThrowsOnInc& operator++() {throw 42;}
44     constexpr ThrowsOnInc operator++(int) {throw 42;}
45 };
46 #endif // TEST_HAS_NO_EXCEPTIONS
47 
48 struct InputOrOutputArchetype {
49   using difference_type = int;
50 
51   int *ptr;
52 
53   constexpr int operator*() const { return *ptr; }
54   constexpr void operator++(int) { ++ptr; }
55   constexpr InputOrOutputArchetype& operator++() { ++ptr; return *this; }
56 };
57 
58 template<class Iter>
59 concept PlusEnabled = requires(Iter& iter) {
60   iter++;
61   ++iter;
62 };
63 
64 constexpr bool test() {
65   int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
66 
67   {
68     using Counted = std::counted_iterator<forward_iterator<int*>>;
69     std::counted_iterator iter(forward_iterator<int*>{buffer}, 8);
70 
71     assert(iter++ == Counted(forward_iterator<int*>{buffer}, 8));
72     assert(++iter == Counted(forward_iterator<int*>{buffer + 2}, 6));
73 
74     ASSERT_SAME_TYPE(decltype(iter++), Counted);
75     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
76   }
77   {
78     using Counted = std::counted_iterator<random_access_iterator<int*>>;
79     std::counted_iterator iter(random_access_iterator<int*>{buffer}, 8);
80 
81     assert(iter++ == Counted(random_access_iterator<int*>{buffer}, 8));
82     assert(++iter == Counted(random_access_iterator<int*>{buffer + 2}, 6));
83 
84     ASSERT_SAME_TYPE(decltype(iter++), Counted);
85     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
86   }
87 
88   {
89     static_assert( PlusEnabled<      std::counted_iterator<random_access_iterator<int*>>>);
90     static_assert(!PlusEnabled<const std::counted_iterator<random_access_iterator<int*>>>);
91   }
92 
93   return true;
94 }
95 
96 int main(int, char**) {
97   test();
98   static_assert(test());
99 
100   int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
101 
102   {
103     using Counted = std::counted_iterator<InputOrOutputArchetype>;
104     std::counted_iterator iter(InputOrOutputArchetype{buffer}, 8);
105 
106     iter++;
107     assert((++iter).base().ptr == buffer + 2);
108 
109     ASSERT_SAME_TYPE(decltype(iter++), void);
110     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
111   }
112   {
113     using Counted = std::counted_iterator<cpp20_input_iterator<int*>>;
114     std::counted_iterator iter(cpp20_input_iterator<int*>{buffer}, 8);
115 
116     iter++;
117     assert(++iter == Counted(cpp20_input_iterator<int*>{buffer + 2}, 6));
118 
119     ASSERT_SAME_TYPE(decltype(iter++), void);
120     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
121   }
122 #ifndef TEST_HAS_NO_EXCEPTIONS
123   {
124     using Counted = std::counted_iterator<ThrowsOnInc<int*>>;
125     std::counted_iterator iter(ThrowsOnInc<int*>{buffer}, 8);
126     try {
127       (void)iter++;
128       assert(false);
129     } catch (int x) {
130       assert(x == 42);
131       assert(iter.count() == 8);
132     }
133 
134     ASSERT_SAME_TYPE(decltype(iter++), ThrowsOnInc<int*>);
135     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
136   }
137 #endif // TEST_HAS_NO_EXCEPTIONS
138 
139   return 0;
140 }
141