xref: /llvm-project/libcxx/test/std/numerics/numeric.ops/partial.sum/partial_sum_op.pass.cpp (revision ae5f792002d8885c091e3e2de6fcebf9b26085f8)
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 // <numeric>
10 // UNSUPPORTED: clang-8
11 // UNSUPPORTED: gcc-9
12 
13 // Became constexpr in C++20
14 // template<InputIterator InIter,
15 //          OutputIterator<auto, const InIter::value_type&> OutIter,
16 //          Callable<auto, const InIter::value_type&, InIter::reference> BinaryOperation>
17 //   requires HasAssign<InIter::value_type, BinaryOperation::result_type>
18 //         && Constructible<InIter::value_type, InIter::reference>
19 //         && CopyConstructible<BinaryOperation>
20 //   OutIter
21 //   partial_sum(InIter first, InIter last, OutIter result, BinaryOperation binary_op);
22 
23 #include <numeric>
24 #include <functional>
25 #include <string>
26 #include <cassert>
27 
28 #include "test_macros.h"
29 #include "test_iterators.h"
30 
31 #if TEST_STD_VER > 17
32 struct rvalue_addable
33 {
34     bool correctOperatorUsed = false;
35 
36     // make sure the predicate is passed an rvalue and an lvalue (so check that the first argument was moved)
37     constexpr rvalue_addable operator()(rvalue_addable&& r, rvalue_addable const&) {
38         r.correctOperatorUsed = true;
39         return std::move(r);
40     }
41 };
42 
43 constexpr rvalue_addable operator+(rvalue_addable& lhs, rvalue_addable const&)
44 {
45     lhs.correctOperatorUsed = false;
46     return lhs;
47 }
48 
49 constexpr rvalue_addable operator+(rvalue_addable&& lhs, rvalue_addable const&)
50 {
51     lhs.correctOperatorUsed = true;
52     return std::move(lhs);
53 }
54 
55 constexpr void
56 test_use_move()
57 {
58     const std::size_t size = 100;
59     rvalue_addable arr[size];
60     rvalue_addable res1[size];
61     rvalue_addable res2[size];
62     std::partial_sum(arr, arr + size, res1);
63     std::partial_sum(arr, arr + size, res2, /*predicate=*/rvalue_addable());
64     // start at 1 because the first element is not moved
65     for (unsigned i = 1; i < size; ++i) assert(res1[i].correctOperatorUsed);
66     for (unsigned i = 1; i < size; ++i) assert(res2[i].correctOperatorUsed);
67 }
68 #endif // TEST_STD_VER > 17
69 
70 // C++20 can use string in constexpr evaluation, but both libc++ and MSVC
71 // don't have the support yet. In these cases omit the constexpr test.
72 // FIXME Remove constexpr string workaround introduced in D90569
73 #if TEST_STD_VER > 17 && \
74 	(!defined(__cpp_lib_constexpr_string) || __cpp_lib_constexpr_string < 201907L)
75 void
76 #else
77 TEST_CONSTEXPR_CXX20 void
78 #endif
79 test_string()
80 {
81     std::string sa[] = {"a", "b", "c"};
82     std::string sr[] = {"a", "ba", "cb"};
83     std::string output[3];
84     std::adjacent_difference(sa, sa + 3, output, std::plus<std::string>());
85     for (unsigned i = 0; i < 3; ++i) assert(output[i] == sr[i]);
86 }
87 
88 template <class InIter, class OutIter>
89 TEST_CONSTEXPR_CXX20 void
90 test()
91 {
92     int ia[] = {1, 2, 3, 4, 5};
93     int ir[] = {1, -1, -4, -8, -13};
94     const unsigned s = sizeof(ia) / sizeof(ia[0]);
95     int ib[s] = {0};
96     OutIter r = std::partial_sum(InIter(ia), InIter(ia+s), OutIter(ib), std::minus<int>());
97     assert(base(r) == ib + s);
98     for (unsigned i = 0; i < s; ++i)
99         assert(ib[i] == ir[i]);
100 }
101 
102 TEST_CONSTEXPR_CXX20 bool
103 test()
104 {
105     test<input_iterator<const int*>, output_iterator<int*> >();
106     test<input_iterator<const int*>, forward_iterator<int*> >();
107     test<input_iterator<const int*>, bidirectional_iterator<int*> >();
108     test<input_iterator<const int*>, random_access_iterator<int*> >();
109     test<input_iterator<const int*>, int*>();
110 
111     test<forward_iterator<const int*>, output_iterator<int*> >();
112     test<forward_iterator<const int*>, forward_iterator<int*> >();
113     test<forward_iterator<const int*>, bidirectional_iterator<int*> >();
114     test<forward_iterator<const int*>, random_access_iterator<int*> >();
115     test<forward_iterator<const int*>, int*>();
116 
117     test<bidirectional_iterator<const int*>, output_iterator<int*> >();
118     test<bidirectional_iterator<const int*>, forward_iterator<int*> >();
119     test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
120     test<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
121     test<bidirectional_iterator<const int*>, int*>();
122 
123     test<random_access_iterator<const int*>, output_iterator<int*> >();
124     test<random_access_iterator<const int*>, forward_iterator<int*> >();
125     test<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
126     test<random_access_iterator<const int*>, random_access_iterator<int*> >();
127     test<random_access_iterator<const int*>, int*>();
128 
129     test<const int*, output_iterator<int*> >();
130     test<const int*, forward_iterator<int*> >();
131     test<const int*, bidirectional_iterator<int*> >();
132     test<const int*, random_access_iterator<int*> >();
133     test<const int*, int*>();
134 
135 #if TEST_STD_VER > 17
136     test_use_move();
137 #endif // TEST_STD_VER > 17
138     // C++20 can use string in constexpr evaluation, but both libc++ and MSVC
139     // don't have the support yet. In these cases omit the constexpr test.
140     // FIXME Remove constexpr string workaround introduced in D90569
141 #if TEST_STD_VER > 17 && \
142 	(!defined(__cpp_lib_constexpr_string) || __cpp_lib_constexpr_string < 201907L)
143 	if (!std::is_constant_evaluated())
144 #endif
145     test_string();
146 
147     return true;
148 }
149 
150 int main(int, char**)
151 {
152     test();
153 #if TEST_STD_VER > 17
154     static_assert(test());
155 #endif
156 
157     return 0;
158 }
159