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