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