xref: /llvm-project/libcxx/test/std/iterators/predef.iterators/counted.iterator/increment.pass.cpp (revision 2a5ba4fb895931b7dc86f4304b0e64153a1175d4)
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 // constexpr 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<InputOrOutputArchetype>;
67     std::counted_iterator iter(InputOrOutputArchetype{buffer}, 8);
68 
69     iter++;
70     assert((++iter).base().ptr == buffer + 2);
71 
72     ASSERT_SAME_TYPE(decltype(iter++), void);
73     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
74   }
75   {
76     using Counted = std::counted_iterator<cpp20_input_iterator<int*>>;
77     std::counted_iterator iter(cpp20_input_iterator<int*>{buffer}, 8);
78 
79     iter++;
80     assert(++iter == Counted(cpp20_input_iterator<int*>{buffer + 2}, 6));
81 
82     ASSERT_SAME_TYPE(decltype(iter++), void);
83     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
84   }
85   {
86     using Counted = std::counted_iterator<forward_iterator<int*>>;
87     std::counted_iterator iter(forward_iterator<int*>{buffer}, 8);
88 
89     assert(iter++ == Counted(forward_iterator<int*>{buffer}, 8));
90     assert(++iter == Counted(forward_iterator<int*>{buffer + 2}, 6));
91 
92     ASSERT_SAME_TYPE(decltype(iter++), Counted);
93     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
94   }
95   {
96     using Counted = std::counted_iterator<random_access_iterator<int*>>;
97     std::counted_iterator iter(random_access_iterator<int*>{buffer}, 8);
98 
99     assert(iter++ == Counted(random_access_iterator<int*>{buffer}, 8));
100     assert(++iter == Counted(random_access_iterator<int*>{buffer + 2}, 6));
101 
102     ASSERT_SAME_TYPE(decltype(iter++), Counted);
103     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
104   }
105 
106   {
107     static_assert( PlusEnabled<      std::counted_iterator<random_access_iterator<int*>>>);
108     static_assert(!PlusEnabled<const std::counted_iterator<random_access_iterator<int*>>>);
109   }
110 
111   return true;
112 }
113 
main(int,char **)114 int main(int, char**) {
115   test();
116   static_assert(test());
117 
118 #ifndef TEST_HAS_NO_EXCEPTIONS
119   int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
120   {
121     using Counted = std::counted_iterator<ThrowsOnInc<int*>>;
122     std::counted_iterator iter(ThrowsOnInc<int*>{buffer}, 8);
123     try {
124       (void)iter++;
125       assert(false);
126     } catch (int x) {
127       assert(x == 42);
128       assert(iter.count() == 8);
129     }
130 
131     ASSERT_SAME_TYPE(decltype(iter++), ThrowsOnInc<int*>);
132     ASSERT_SAME_TYPE(decltype(++iter), Counted&);
133   }
134 #endif // TEST_HAS_NO_EXCEPTIONS
135 
136   return 0;
137 }
138