139034388SChristopher Di Bella //===----------------------------------------------------------------------===//
239034388SChristopher Di Bella //
339034388SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
439034388SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
539034388SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
639034388SChristopher Di Bella //
739034388SChristopher Di Bella //===----------------------------------------------------------------------===//
839034388SChristopher Di Bella
939034388SChristopher Di Bella // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
1039034388SChristopher Di Bella
1139034388SChristopher Di Bella // template <class I, class T>
1239034388SChristopher Di Bella // struct in_value_result;
1339034388SChristopher Di Bella
1439034388SChristopher Di Bella #include <algorithm>
1539034388SChristopher Di Bella #include <cassert>
1639034388SChristopher Di Bella #include <type_traits>
1739034388SChristopher Di Bella #include <utility>
1839034388SChristopher Di Bella
1939034388SChristopher Di Bella #include "MoveOnly.h"
2039034388SChristopher Di Bella
2139034388SChristopher Di Bella struct A {
2239034388SChristopher Di Bella explicit A(int);
2339034388SChristopher Di Bella };
2439034388SChristopher Di Bella // no implicit conversion
2539034388SChristopher Di Bella static_assert(!std::is_constructible_v<std::ranges::in_value_result<A, A>, std::ranges::in_value_result<int, int>>);
2639034388SChristopher Di Bella
2739034388SChristopher Di Bella struct B {
2839034388SChristopher Di Bella B(int);
2939034388SChristopher Di Bella };
3039034388SChristopher Di Bella // implicit conversion
3139034388SChristopher Di Bella static_assert(std::is_constructible_v<std::ranges::in_value_result<B, B>, std::ranges::in_value_result<int, int>>);
3239034388SChristopher Di Bella static_assert(std::is_constructible_v<std::ranges::in_value_result<B, B>, std::ranges::in_value_result<int, int>&>);
3339034388SChristopher Di Bella static_assert(
3439034388SChristopher Di Bella std::is_constructible_v<std::ranges::in_value_result<B, B>, const std::ranges::in_value_result<int, int>>);
3539034388SChristopher Di Bella static_assert(
3639034388SChristopher Di Bella std::is_constructible_v<std::ranges::in_value_result<B, B>, const std::ranges::in_value_result<int, int>&>);
3739034388SChristopher Di Bella
3839034388SChristopher Di Bella struct C {
3939034388SChristopher Di Bella C(int&);
4039034388SChristopher Di Bella };
4139034388SChristopher Di Bella static_assert(!std::is_constructible_v<std::ranges::in_value_result<C, C>, std::ranges::in_value_result<int, int>&>);
4239034388SChristopher Di Bella
4339034388SChristopher Di Bella // has to be convertible via const&
4439034388SChristopher Di Bella static_assert(std::is_convertible_v<std::ranges::in_value_result<int, int>&, std::ranges::in_value_result<long, long>>);
4539034388SChristopher Di Bella static_assert(
4639034388SChristopher Di Bella std::is_convertible_v<const std::ranges::in_value_result<int, int>&, std::ranges::in_value_result<long, long>>);
4739034388SChristopher Di Bella static_assert(
4839034388SChristopher Di Bella std::is_convertible_v<std::ranges::in_value_result<int, int>&&, std::ranges::in_value_result<long, long>>);
4939034388SChristopher Di Bella static_assert(
5039034388SChristopher Di Bella std::is_convertible_v<const std::ranges::in_value_result<int, int>&&, std::ranges::in_value_result<long, long>>);
5139034388SChristopher Di Bella
5239034388SChristopher Di Bella // should be move constructible
5339034388SChristopher Di Bella static_assert(std::is_move_constructible_v<std::ranges::in_value_result<MoveOnly, int>>);
5439034388SChristopher Di Bella static_assert(std::is_move_constructible_v<std::ranges::in_value_result<int, MoveOnly>>);
5539034388SChristopher Di Bella
56*f0ea888eSChristopher Di Bella // should not be copy constructible with move-only type
5739034388SChristopher Di Bella static_assert(!std::is_copy_constructible_v<std::ranges::in_value_result<MoveOnly, int>>);
5839034388SChristopher Di Bella static_assert(!std::is_copy_constructible_v<std::ranges::in_value_result<int, MoveOnly>>);
5939034388SChristopher Di Bella
6039034388SChristopher Di Bella struct NotConvertible {};
6139034388SChristopher Di Bella // conversions should not work if there is no conversion
6239034388SChristopher Di Bella static_assert(
6339034388SChristopher Di Bella !std::is_convertible_v<std::ranges::in_value_result<NotConvertible, int>, std::ranges::in_value_result<int, int>>);
6439034388SChristopher Di Bella static_assert(
6539034388SChristopher Di Bella !std::is_convertible_v<std::ranges::in_value_result<int, NotConvertible>, std::ranges::in_value_result<int, int>>);
6639034388SChristopher Di Bella
6739034388SChristopher Di Bella template <class T>
6839034388SChristopher Di Bella struct ConvertibleFrom {
ConvertibleFromConvertibleFrom6939034388SChristopher Di Bella constexpr ConvertibleFrom(T c) : content{c} {}
7039034388SChristopher Di Bella T content;
7139034388SChristopher Di Bella };
7239034388SChristopher Di Bella
test()7339034388SChristopher Di Bella constexpr bool test() {
74*f0ea888eSChristopher Di Bella // Checks that conversion operations are correct.
7539034388SChristopher Di Bella {
7639034388SChristopher Di Bella std::ranges::in_value_result<int, double> res{10, 0.};
7739034388SChristopher Di Bella assert(res.in == 10);
7839034388SChristopher Di Bella assert(res.value == 0.);
7939034388SChristopher Di Bella std::ranges::in_value_result<ConvertibleFrom<int>, ConvertibleFrom<double>> res2 = res;
8039034388SChristopher Di Bella assert(res2.in.content == 10);
8139034388SChristopher Di Bella assert(res2.value.content == 0.);
8239034388SChristopher Di Bella }
83*f0ea888eSChristopher Di Bella
84*f0ea888eSChristopher Di Bella // Checks that conversions are possible when one of the types is move-only.
8539034388SChristopher Di Bella {
8639034388SChristopher Di Bella std::ranges::in_value_result<MoveOnly, int> res{MoveOnly{}, 2};
8739034388SChristopher Di Bella assert(res.in.get() == 1);
8839034388SChristopher Di Bella assert(res.value == 2);
8939034388SChristopher Di Bella auto res2 = static_cast<std::ranges::in_value_result<MoveOnly, int>>(std::move(res));
9039034388SChristopher Di Bella assert(res.in.get() == 0);
9139034388SChristopher Di Bella assert(res2.in.get() == 1);
9239034388SChristopher Di Bella assert(res2.value == 2);
9339034388SChristopher Di Bella }
94*f0ea888eSChristopher Di Bella
95*f0ea888eSChristopher Di Bella // Checks that structured bindings get the correct values.
9639034388SChristopher Di Bella {
9739034388SChristopher Di Bella auto [in, value] = std::ranges::in_value_result<int, int>{1, 2};
9839034388SChristopher Di Bella assert(in == 1);
9939034388SChristopher Di Bella assert(value == 2);
10039034388SChristopher Di Bella }
10139034388SChristopher Di Bella return true;
10239034388SChristopher Di Bella }
10339034388SChristopher Di Bella
main(int,char **)10439034388SChristopher Di Bella int main(int, char**) {
10539034388SChristopher Di Bella test();
10639034388SChristopher Di Bella static_assert(test());
10739034388SChristopher Di Bella
10839034388SChristopher Di Bella return 0;
10939034388SChristopher Di Bella }
110