Skip to content

Commit 1e77b39

Browse files
committed
[libc++] Add ranges::in_fun_result
Add `ranges::in_fun_result` Reviewed By: Quuxplusone, #libc, var-const Spies: CaseyCarter, var-const, libcxx-commits, mgorny Differential Revision: https://reviews.llvm.org/D116974
1 parent 2bd62e0 commit 1e77b39

File tree

7 files changed

+178
-7
lines changed

7 files changed

+178
-7
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ set(files
2626
__algorithm/generate.h
2727
__algorithm/generate_n.h
2828
__algorithm/half_positive.h
29+
__algorithm/in_fun_result.h
2930
__algorithm/in_in_out_result.h
3031
__algorithm/in_in_result.h
3132
__algorithm/in_out_out_result.h
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___ALGORITHM_IN_FUN_RESULT_H
11+
#define _LIBCPP___ALGORITHM_IN_FUN_RESULT_H
12+
13+
#include <__concepts/convertible_to.h>
14+
#include <__config>
15+
#include <__utility/move.h>
16+
17+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
18+
# pragma GCC system_header
19+
#endif
20+
21+
_LIBCPP_BEGIN_NAMESPACE_STD
22+
23+
#ifndef _LIBCPP_HAS_NO_CONCEPTS
24+
25+
namespace ranges {
26+
template <class _Ip, class _Fp>
27+
struct in_fun_result {
28+
[[no_unique_address]] _Ip in;
29+
[[no_unique_address]] _Fp fun;
30+
31+
template <class _I2, class _F2>
32+
requires convertible_to<const _Ip&, _I2> && convertible_to<const _Fp&, _F2>
33+
_LIBCPP_HIDE_FROM_ABI constexpr operator in_fun_result<_I2, _F2>() const & {
34+
return {in, fun};
35+
}
36+
37+
template <class _I2, class _F2>
38+
requires convertible_to<_Ip, _I2> && convertible_to<_Fp, _F2>
39+
_LIBCPP_HIDE_FROM_ABI constexpr operator in_fun_result<_I2, _F2>() && {
40+
return {std::move(in), std::move(fun)};
41+
}
42+
};
43+
} // namespace ranges
44+
45+
#endif // _LIBCPP_HAS_NO_RANGES
46+
47+
_LIBCPP_END_NAMESPACE_STD
48+
49+
#endif // _LIBCPP___ALGORITHM_IN_FUN_RESULT_H

libcxx/include/algorithm

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ namespace std
1919
{
2020
2121
namespace ranges {
22+
template <class I, class F>
23+
struct in_fun_result; // since C++20
24+
2225
template <class I1, class I2>
2326
struct in_in_result; // since C++20
2427
@@ -27,6 +30,9 @@ namespace ranges {
2730
2831
template <class I, class O1, class O2>
2932
struct in_out_out_result; // since C++20
33+
34+
template<class I, class O>
35+
struct in_out_result; // since C++20
3036
}
3137
3238
template <class InputIterator, class Predicate>
@@ -661,13 +667,6 @@ template <class BidirectionalIterator>
661667
template <class BidirectionalIterator, class Compare>
662668
constexpr bool // constexpr in C++20
663669
prev_permutation(BidirectionalIterator first, BidirectionalIterator last, Compare comp);
664-
665-
namespace ranges {
666-
// [algorithms.results], algorithm result types
667-
template<class InputIterator, class OutputIterator>
668-
struct in_out_result;
669-
}
670-
671670
} // std
672671
673672
*/
@@ -712,6 +711,7 @@ template<class InputIterator, class OutputIterator>
712711
#include <__algorithm/generate.h>
713712
#include <__algorithm/generate_n.h>
714713
#include <__algorithm/half_positive.h>
714+
#include <__algorithm/in_fun_result.h>
715715
#include <__algorithm/in_in_out_result.h>
716716
#include <__algorithm/in_in_result.h>
717717
#include <__algorithm/in_out_out_result.h>

libcxx/include/module.modulemap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ module std [system] {
247247
module generate { private header "__algorithm/generate.h" }
248248
module generate_n { private header "__algorithm/generate_n.h" }
249249
module half_positive { private header "__algorithm/half_positive.h" }
250+
module in_fun_result { private header "__algorithm/in_fun_result.h" }
250251
module in_in_out_result { private header "__algorithm/in_in_out_result.h" }
251252
module in_in_result { private header "__algorithm/in_in_result.h" }
252253
module in_out_out_result { private header "__algorithm/in_out_out_result.h" }
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
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+
// REQUIRES: modules-build
10+
11+
// WARNING: This test was generated by 'generate_private_header_tests.py'
12+
// and should not be edited manually.
13+
14+
// expected-error@*:* {{use of private header from outside its module: '__algorithm/in_fun_result.h'}}
15+
#include <__algorithm/in_fun_result.h>
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
// template <class I1, class I2>
14+
// struct in_fun_result;
15+
16+
#include <algorithm>
17+
#include <cassert>
18+
#include <type_traits>
19+
#include <utility>
20+
21+
#include "MoveOnly.h"
22+
23+
struct A {
24+
explicit A(int);
25+
};
26+
// no implicit conversion
27+
static_assert(!std::is_constructible_v<std::ranges::in_fun_result<A, A>, std::ranges::in_fun_result<int, int>>);
28+
29+
struct B {
30+
B(int);
31+
};
32+
// implicit conversion
33+
static_assert(std::is_constructible_v<std::ranges::in_fun_result<B, B>, std::ranges::in_fun_result<int, int>>);
34+
static_assert(std::is_constructible_v<std::ranges::in_fun_result<B, B>, std::ranges::in_fun_result<int, int>&>);
35+
static_assert(std::is_constructible_v<std::ranges::in_fun_result<B, B>, const std::ranges::in_fun_result<int, int>>);
36+
static_assert(std::is_constructible_v<std::ranges::in_fun_result<B, B>, const std::ranges::in_fun_result<int, int>&>);
37+
38+
struct C {
39+
C(int&);
40+
};
41+
// has to be convertible via const&
42+
static_assert(!std::is_constructible_v<std::ranges::in_fun_result<C, C>, std::ranges::in_fun_result<int, int>&>);
43+
44+
static_assert(std::is_convertible_v<std::ranges::in_fun_result<int, int>&, std::ranges::in_fun_result<long, long>>);
45+
static_assert(std::is_convertible_v<const std::ranges::in_fun_result<int, int>&, std::ranges::in_fun_result<long, long>>);
46+
static_assert(std::is_convertible_v<std::ranges::in_fun_result<int, int>&&, std::ranges::in_fun_result<long, long>>);
47+
static_assert(std::is_convertible_v<const std::ranges::in_fun_result<int, int>&&, std::ranges::in_fun_result<long, long>>);
48+
49+
// should be move constructible
50+
static_assert(std::is_move_constructible_v<std::ranges::in_fun_result<MoveOnly, int>>);
51+
static_assert(std::is_move_constructible_v<std::ranges::in_fun_result<int, MoveOnly>>);
52+
53+
// should not copy constructible with move-only type
54+
static_assert(!std::is_copy_constructible_v<std::ranges::in_fun_result<MoveOnly, int>>);
55+
static_assert(!std::is_copy_constructible_v<std::ranges::in_fun_result<int, MoveOnly>>);
56+
57+
struct NotConvertible {};
58+
// conversions should not work if there is no conversion
59+
static_assert(!std::is_convertible_v<std::ranges::in_fun_result<NotConvertible, int>,
60+
std::ranges::in_fun_result<int, int>>);
61+
static_assert(!std::is_convertible_v<std::ranges::in_fun_result<int, NotConvertible>,
62+
std::ranges::in_fun_result<int, int>>);
63+
64+
template <class T>
65+
struct ConvertibleFrom {
66+
constexpr ConvertibleFrom(T c) : content{c} {}
67+
T content;
68+
};
69+
70+
constexpr bool test() {
71+
{
72+
std::ranges::in_fun_result<int, double> res{10, 0.};
73+
assert(res.in == 10);
74+
assert(res.fun == 0.);
75+
std::ranges::in_fun_result<ConvertibleFrom<int>, ConvertibleFrom<double>> res2 = res;
76+
assert(res2.in.content == 10);
77+
assert(res2.fun.content == 0.);
78+
}
79+
{
80+
std::ranges::in_fun_result<MoveOnly, int> res{MoveOnly{}, 2};
81+
assert(res.in.get() == 1);
82+
assert(res.fun == 2);
83+
auto res2 = static_cast<std::ranges::in_fun_result<MoveOnly, int>>(std::move(res));
84+
assert(res.in.get() == 0);
85+
assert(res2.in.get() == 1);
86+
assert(res2.fun == 2);
87+
}
88+
{
89+
auto [in, fun] = std::ranges::in_fun_result<int, int>{1, 2};
90+
assert(in == 1);
91+
assert(fun == 2);
92+
}
93+
return true;
94+
}
95+
96+
int main(int, char**) {
97+
test();
98+
static_assert(test());
99+
100+
return 0;
101+
}

libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ static_assert(sizeof(std::ranges::in_out_out_result<Empty, char, Empty>) == 2);
4444
static_assert(sizeof(std::ranges::in_out_out_result<Empty, Empty, char>) == 2);
4545
static_assert(sizeof(std::ranges::in_out_out_result<int, Empty, Empty2>) == sizeof(int));
4646
static_assert(sizeof(std::ranges::in_out_out_result<Empty, Empty, Empty>) == 3);
47+
48+
static_assert(sizeof(std::ranges::in_fun_result<Empty, int>) == sizeof(int));
49+
static_assert(sizeof(std::ranges::in_fun_result<int, Empty>) == sizeof(int));
50+
static_assert(sizeof(std::ranges::in_fun_result<Empty, Empty>) == 2);

0 commit comments

Comments
 (0)