-
Notifications
You must be signed in to change notification settings - Fork 187
/
nest.hpp
96 lines (80 loc) · 3.35 KB
/
nest.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License Version 2.0 with LLVM Exceptions
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* https://llvm.org/LICENSE.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <unifex/config.hpp>
#include <unifex/bind_back.hpp>
#include <unifex/sender_concepts.hpp>
#include <unifex/tag_invoke.hpp>
#include <unifex/detail/prologue.hpp>
namespace unifex {
namespace _nest_cpo {
inline const struct _nest_fn final {
private:
template <typename Scope, typename Sender>
using nest_member_result_t =
decltype(UNIFEX_DECLVAL(Scope&).nest(UNIFEX_DECLVAL(Sender)));
template <typename Scope, typename Sender>
static constexpr bool is_nest_member_nothrow_v =
noexcept(UNIFEX_DECLVAL(Scope&).nest(UNIFEX_DECLVAL(Sender)));
struct deref;
public:
template(typename Sender, typename Scope) //
(requires typed_sender<Sender> AND tag_invocable<_nest_fn, Sender, Scope&>
AND typed_sender<tag_invoke_result_t<_nest_fn, Sender, Scope&>>) //
auto
operator()(Sender&& sender, Scope& scope) const
noexcept(is_nothrow_tag_invocable_v<_nest_fn, Sender, Scope&>)
-> tag_invoke_result_t<_nest_fn, Sender, Scope&> {
return tag_invoke(_nest_fn{}, static_cast<Sender&&>(sender), scope);
}
template(typename Sender, typename Scope) //
(requires typed_sender<Sender> AND(
!tag_invocable<_nest_fn, Sender, Scope&>)
AND typed_sender<nest_member_result_t<Scope, Sender>>) //
auto
operator()(Sender&& sender, Scope& scope) const
noexcept(is_nest_member_nothrow_v<Scope, Sender>)
-> nest_member_result_t<Scope, Sender> {
return scope.nest(static_cast<Sender&&>(sender));
}
template <typename Scope>
constexpr auto operator()(Scope& scope) const
noexcept(is_nothrow_callable_v<tag_t<bind_back>, deref, Scope*>)
-> bind_back_result_t<deref, Scope*>;
} nest{};
struct _nest_fn::deref final {
template <typename Sender, typename Scope>
constexpr auto operator()(Sender&& sender, Scope* scope) const
noexcept(noexcept(_nest_fn{}(static_cast<Sender&&>(sender), *scope)))
-> decltype(_nest_fn{}(static_cast<Sender&&>(sender), *scope)) {
return _nest_fn{}(static_cast<Sender&&>(sender), *scope);
}
};
template <typename Scope>
inline constexpr auto _nest_fn::operator()(Scope& scope) const
noexcept(is_nothrow_callable_v<tag_t<bind_back>, deref, Scope*>)
-> bind_back_result_t<deref, Scope*> {
// bind_back will try to store a copy of any lvalue references it's passed,
// which doesn't work for us here so we have to pass a scope pointer instead
// of a scope reference. we don't, in general, want to expose a
// `nest(Sender&&, Scope*)` function so we use `_nest_fn::deref` to do the
// indirection for us in this scenario.
return bind_back(deref{}, &scope);
}
} // namespace _nest_cpo
using _nest_cpo::nest;
} // namespace unifex
#include <unifex/detail/epilogue.hpp>