xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp (revision a0662176a9b40462aafbb17cd8eb8cf6a65e940e)
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 auto begin()
12 //   requires (!(simple-view<V> &&
13 //               random_access_range<const V> && sized_range<const V>));
14 // constexpr auto begin() const
15 //   requires random_access_range<const V> && sized_range<const V>;
16 
17 #include <ranges>
18 
19 #include "test_macros.h"
20 #include "test_iterators.h"
21 #include "test_range.h"
22 #include "types.h"
23 
24 template<class T>
25 concept BeginInvocable = requires(std::ranges::drop_view<T> t) { t.begin(); };
26 
27 template <bool IsSimple>
28 struct MaybeSimpleView : std::ranges::view_base {
29   int* num_of_non_const_begin_calls;
30   int* num_of_const_begin_calls;
31 
32   constexpr int* begin() {
33     ++(*num_of_non_const_begin_calls);
34     return nullptr;
35   }
36   constexpr std::conditional_t<IsSimple, int*, const int*> begin() const {
37     ++(*num_of_const_begin_calls);
38     return nullptr;
39   }
40   constexpr int* end() const { return nullptr; }
41   constexpr std::size_t size() const { return 0; }
42 };
43 
44 using SimpleView = MaybeSimpleView<true>;
45 using NonSimpleView = MaybeSimpleView<false>;
46 
47 constexpr bool test() {
48   // random_access_range<const V> && sized_range<const V>
49   std::ranges::drop_view dropView1(MoveOnlyView(), 4);
50   assert(dropView1.begin() == globalBuff + 4);
51 
52   // !random_access_range<const V>
53   std::ranges::drop_view dropView2(ForwardView(), 4);
54   assert(base(dropView2.begin()) == globalBuff + 4);
55 
56   // !random_access_range<const V>
57   std::ranges::drop_view dropView3(InputView(), 4);
58   assert(base(dropView3.begin()) == globalBuff + 4);
59 
60   // random_access_range<const V> && sized_range<const V>
61   std::ranges::drop_view dropView4(MoveOnlyView(), 8);
62   assert(dropView4.begin() == globalBuff + 8);
63 
64   // random_access_range<const V> && sized_range<const V>
65   std::ranges::drop_view dropView5(MoveOnlyView(), 0);
66   assert(dropView5.begin() == globalBuff);
67 
68   // random_access_range<const V> && sized_range<const V>
69   const std::ranges::drop_view dropView6(MoveOnlyView(), 0);
70   assert(dropView6.begin() == globalBuff);
71 
72   // random_access_range<const V> && sized_range<const V>
73   std::ranges::drop_view dropView7(MoveOnlyView(), 10);
74   assert(dropView7.begin() == globalBuff + 8);
75 
76   IteratorOpCounts opcounts;
77   CountedView view8(&opcounts);
78   ;
79   std::ranges::drop_view dropView8(view8, 5);
80   assert(base(base(dropView8.begin())) == globalBuff + 5);
81   assert(opcounts.increments == 5);
82 
83   static_assert(!BeginInvocable<const ForwardView>);
84 
85   {
86     // non-common non-simple view,
87     // The wording of the standard is:
88     // Returns: ranges::next(ranges::begin(base_), count_, ranges::end(base_))
89     // Note that "Returns" is used here, meaning that we don't have to do it this way.
90     // In fact, this will use ranges::advance that has O(n) on non-common range.
91     // but [range.range] requires "amortized constant time" for ranges::begin and ranges::end
92     // Here, we test that begin() is indeed constant time, by creating a customized
93     // sentinel and counting how many times the sentinel eq function is called.
94     // It should be 0 times, but since this test (or any test under libcxx/test/std) is
95     // also used by other implementations, we relax the condition to that
96     // sentinel_cmp_calls is a constant number.
97     int sentinel_cmp_calls_1 = 0;
98     int sentinel_cmp_calls_2 = 0;
99     using NonCommonView      = MaybeSimpleNonCommonView<false>;
100     static_assert(std::ranges::random_access_range<NonCommonView>);
101     static_assert(std::ranges::sized_range<NonCommonView>);
102     std::ranges::drop_view dropView9_1(NonCommonView{{}, 0, &sentinel_cmp_calls_1}, 4);
103     std::ranges::drop_view dropView9_2(NonCommonView{{}, 0, &sentinel_cmp_calls_2}, 6);
104     assert(dropView9_1.begin() == globalBuff + 4);
105     assert(dropView9_2.begin() == globalBuff + 6);
106     assert(sentinel_cmp_calls_1 == sentinel_cmp_calls_2);
107   }
108 
109   {
110     // non-common simple view, same as above.
111     int sentinel_cmp_calls_1 = 0;
112     int sentinel_cmp_calls_2 = 0;
113     using NonCommonView      = MaybeSimpleNonCommonView<true>;
114     static_assert(std::ranges::random_access_range<NonCommonView>);
115     static_assert(std::ranges::sized_range<NonCommonView>);
116     std::ranges::drop_view dropView10_1(NonCommonView{{}, 0, &sentinel_cmp_calls_1}, 4);
117     std::ranges::drop_view dropView10_2(NonCommonView{{}, 0, &sentinel_cmp_calls_2}, 6);
118     assert(dropView10_1.begin() == globalBuff + 4);
119     assert(dropView10_2.begin() == globalBuff + 6);
120     assert(sentinel_cmp_calls_1 == sentinel_cmp_calls_2);
121   }
122 
123   {
124     static_assert(std::ranges::random_access_range<const SimpleView>);
125     static_assert(std::ranges::sized_range<const SimpleView>);
126     static_assert(simple_view<SimpleView>);
127     int non_const_calls = 0;
128     int const_calls = 0;
129     std::ranges::drop_view dropView(SimpleView{{}, &non_const_calls, &const_calls}, 4);
130     assert(dropView.begin() == nullptr);
131     assert(non_const_calls == 0);
132     assert(const_calls == 1);
133     assert(std::as_const(dropView).begin() == nullptr);
134     assert(non_const_calls == 0);
135     assert(const_calls == 2);
136   }
137 
138   {
139     static_assert(std::ranges::random_access_range<const NonSimpleView>);
140     static_assert(std::ranges::sized_range<const NonSimpleView>);
141     static_assert(!simple_view<NonSimpleView>);
142     int non_const_calls = 0;
143     int const_calls = 0;
144     std::ranges::drop_view dropView(NonSimpleView{{}, &non_const_calls, &const_calls}, 4);
145     assert(dropView.begin() == nullptr);
146     assert(non_const_calls == 1);
147     assert(const_calls == 0);
148     assert(std::as_const(dropView).begin() == nullptr);
149     assert(non_const_calls == 1);
150     assert(const_calls == 1);
151   }
152 
153   return true;
154 }
155 
156 int main(int, char**) {
157   test();
158   static_assert(test());
159 
160   return 0;
161 }
162