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, libcpp-has-no-incomplete-ranges
11 
12 // <algorithm>
13 //
14 // namespace ranges {
15 //   template<class InputIterator, class OutputIterator>
16 //     struct in_out_result;
17 // }
18 
19 #include <algorithm>
20 #include <cassert>
21 #include <type_traits>
22 
23 struct A {
24   A(int&);
25 };
26 static_assert(!std::is_constructible_v<std::ranges::in_out_result<A, A>, std::ranges::in_out_result<int, int>&>);
27 
28 static_assert(std::is_convertible_v<std::ranges::in_out_result<int, int>&,
29     std::ranges::in_out_result<long, long>>);
30 static_assert(!std::is_nothrow_convertible_v<std::ranges::in_out_result<int, int>&,
31     std::ranges::in_out_result<long, long>>);
32 static_assert(std::is_convertible_v<const std::ranges::in_out_result<int, int>&,
33     std::ranges::in_out_result<long, long>>);
34 static_assert(!std::is_nothrow_convertible_v<const std::ranges::in_out_result<int, int>&,
35     std::ranges::in_out_result<long, long>>);
36 static_assert(std::is_convertible_v<std::ranges::in_out_result<int, int>&&,
37     std::ranges::in_out_result<long, long>>);
38 static_assert(!std::is_nothrow_convertible_v<std::ranges::in_out_result<int, int>&&,
39     std::ranges::in_out_result<long, long>>);
40 static_assert(std::is_convertible_v<const std::ranges::in_out_result<int, int>&&,
41     std::ranges::in_out_result<long, long>>);
42 static_assert(!std::is_nothrow_convertible_v<const std::ranges::in_out_result<int, int>&&,
43     std::ranges::in_out_result<long, long>>);
44 
45 int main(int, char**) {
46   // Conversion, fundamental types.
47   {
48     std::ranges::in_out_result<int, bool> x = {2, false};
49     // FIXME(varconst): try a narrowing conversion.
50     std::ranges::in_out_result<long, char> y = x;
51     assert(y.in == 2);
52     assert(y.out == '\0');
53   }
54 
55   // Conversion, user-defined types.
56   {
57     struct From1 {
58       int value = 0;
59       From1(int v) : value(v) {}
60     };
61 
62     struct To1 {
63       int value = 0;
64       To1(int v) : value(v) {}
65 
66       To1(const From1& f) : value(f.value) {};
67     };
68 
69     struct To2 {
70       int value = 0;
71       To2(int v) : value(v) {}
72     };
73     struct From2 {
74       int value = 0;
75       From2(int v) : value(v) {}
76 
77       operator To2() const { return To2(value); }
78     };
79 
80     std::ranges::in_out_result<From1, From2> x{42, 99};
81     std::ranges::in_out_result<To1, To2> y = x;
82     assert(y.in.value == 42);
83     assert(y.out.value == 99);
84   }
85 
86   // Copy-only type.
87   {
88     struct CopyOnly {
89       int value = 0;
90       CopyOnly() = default;
91       CopyOnly(int v) : value(v) {}
92 
93       CopyOnly(const CopyOnly&) = default;
94       CopyOnly(CopyOnly&&) = delete;
95     };
96 
97     std::ranges::in_out_result<CopyOnly, CopyOnly> x;
98     x.in.value = 42;
99     x.out.value = 99;
100 
101     auto y = x;
102     assert(y.in.value == 42);
103     assert(y.out.value == 99);
104   }
105 
106   // Move-only type.
107   {
108     struct MoveOnly {
109       int value = 0;
110       MoveOnly(int v) : value(v) {}
111 
112       MoveOnly(MoveOnly&&) = default;
113       MoveOnly(const MoveOnly&) = delete;
114     };
115 
116     std::ranges::in_out_result<MoveOnly, MoveOnly> x{42, 99};
117     auto y = std::move(x);
118     assert(y.in.value == 42);
119     assert(y.out.value == 99);
120   }
121 
122   // Unsuccessful conversion.
123   {
124     struct Foo1 {};
125     struct Foo2 {};
126     struct Bar1 {};
127     struct Bar2 {};
128     static_assert(
129         !std::is_convertible_v<std::ranges::in_out_result<Foo1, Foo2>, std::ranges::in_out_result<Bar1, Bar2>>);
130   }
131 
132   return 0;
133 }
134