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