Skip to content

Commit 30387e6

Browse files
committed
*: rewrite to concepts
1 parent 9e4821d commit 30387e6

File tree

3 files changed

+144
-164
lines changed

3 files changed

+144
-164
lines changed

include/async/algorithm.hpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22

33
#include <algorithm>
4+
#include <concepts>
45

56
#include <async/basic.hpp>
67
#include <async/cancellation.hpp>
@@ -141,7 +142,7 @@ template<typename Sender, typename F>
141142
struct [[nodiscard]] transform_sender;
142143

143144
template<typename Sender, typename F>
144-
requires (!std::is_same_v<typename Sender::value_type, void>)
145+
requires (!std::same_as<typename Sender::value_type, void>)
145146
struct [[nodiscard]] transform_sender<Sender, F> {
146147
using value_type = std::invoke_result_t<F, typename Sender::value_type>;
147148

@@ -160,7 +161,7 @@ struct [[nodiscard]] transform_sender<Sender, F> {
160161
};
161162

162163
template<typename Sender, typename F>
163-
requires std::is_same_v<typename Sender::value_type, void>
164+
requires std::same_as<typename Sender::value_type, void>
164165
struct [[nodiscard]] transform_sender<Sender, F> {
165166
using value_type = std::invoke_result_t<F>;
166167

include/async/basic.hpp

+27-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#pragma once
22

33
#include <atomic>
4+
#include <concepts>
5+
#include <type_traits>
46

57
#include <async/execution.hpp>
68
#include <frg/list.hpp>
@@ -140,11 +142,12 @@ struct [[nodiscard]] sender_awaiter<S, void> {
140142
template<typename T>
141143
struct any_receiver {
142144
template<typename R>
145+
requires (
146+
std::is_trivially_copyable_v<R>
147+
&& sizeof(R) <= sizeof(void *)
148+
&& alignof(R) <= alignof(void *)
149+
)
143150
any_receiver(R receiver) {
144-
static_assert(std::is_trivially_copyable_v<R>);
145-
static_assert(sizeof(R) <= sizeof(void *));
146-
static_assert(alignof(R) <= alignof(void *));
147-
148151
new (stor_) R(receiver);
149152
set_value_fptr_ = [] (void *p, T value) {
150153
auto *rp = static_cast<R *>(p);
@@ -168,8 +171,12 @@ struct any_receiver {
168171
template<>
169172
struct any_receiver<void> {
170173
template<typename R>
174+
requires (
175+
std::is_trivially_copyable_v<R>
176+
&& sizeof(R) <= sizeof(void *)
177+
&& alignof(R) <= alignof(void *)
178+
)
171179
any_receiver(R receiver) {
172-
static_assert(std::is_trivially_copyable_v<R>);
173180
new (stor_) R(receiver);
174181
set_value_fptr_ = [] (void *p) {
175182
auto *rp = static_cast<R *>(p);
@@ -211,10 +218,13 @@ struct callback<R(Args...)> {
211218
callback()
212219
: _function(nullptr) { }
213220

214-
template<typename F, typename = std::enable_if_t<
215-
sizeof(F) == sizeof(void *) && alignof(F) == alignof(void *)
216-
&& std::is_trivially_copy_constructible<F>::value
217-
&& std::is_trivially_destructible<F>::value>>
221+
template<typename F>
222+
requires (
223+
sizeof(F) <= sizeof(void*)
224+
&& alignof(F) <= alignof(void*)
225+
&& std::is_trivially_copy_constructible_v<F>
226+
&& std::is_trivially_destructible_v<F>
227+
)
218228
callback(F functor)
219229
: _function(&invoke<F>) {
220230
new (&_object) F{std::move(functor)};
@@ -307,8 +317,8 @@ void run_forever(IoService ios) {
307317
}
308318

309319
template<typename Sender>
310-
std::enable_if_t<std::is_same_v<typename Sender::value_type, void>, void>
311-
run(Sender s) {
320+
requires std::same_as<typename Sender::value_type, void>
321+
void run(Sender s) {
312322
struct receiver {
313323
void set_value_inline() { }
314324

@@ -323,9 +333,8 @@ run(Sender s) {
323333
}
324334

325335
template<typename Sender>
326-
std::enable_if_t<!std::is_same_v<typename Sender::value_type, void>,
327-
typename Sender::value_type>
328-
run(Sender s) {
336+
requires (!std::same_as<typename Sender::value_type, void>)
337+
typename Sender::value_type run(Sender s) {
329338
struct state {
330339
frg::optional<typename Sender::value_type> value;
331340
};
@@ -356,8 +365,8 @@ run(Sender s) {
356365
}
357366

358367
template<typename Sender, typename IoService>
359-
std::enable_if_t<std::is_same_v<typename Sender::value_type, void>, void>
360-
run(Sender s, IoService ios) {
368+
requires std::same_as<typename Sender::value_type, void>
369+
void run(Sender s, IoService ios) {
361370
struct state {
362371
bool done = false;
363372
};
@@ -390,9 +399,8 @@ run(Sender s, IoService ios) {
390399
}
391400

392401
template<typename Sender, typename IoService>
393-
std::enable_if_t<!std::is_same_v<typename Sender::value_type, void>,
394-
typename Sender::value_type>
395-
run(Sender s, IoService ios) {
402+
requires (!std::same_as<typename Sender::value_type, void>)
403+
typename Sender::value_type run(Sender s, IoService ios) {
396404
struct state {
397405
bool done = false;
398406
frg::optional<typename Sender::value_type> value;

include/async/execution.hpp

+114-143
Original file line numberDiff line numberDiff line change
@@ -2,154 +2,125 @@
22

33
#include <type_traits>
44
#include <utility>
5+
#include <concepts>
56

6-
namespace async {
7-
8-
// Detection pattern boilerplate.
9-
10-
template<typename... Ts>
11-
using void_t = void;
12-
13-
template<typename... Ts>
14-
constexpr bool dependent_false_t = false;
15-
16-
template <template <typename...> typename Trait, typename Void, typename... Args>
17-
struct is_detected_helper : std::false_type { };
18-
19-
template <template <typename...> typename Trait, typename... Args>
20-
struct is_detected_helper<Trait, void_t<Trait<Args...>>, Args...> : std::true_type { };
21-
22-
template <template <typename...> typename Trait, typename... Args>
23-
constexpr bool is_detected_v = is_detected_helper<Trait, void, Args...>::value;
7+
#include <frg/detection.hpp>
248

9+
namespace async {
2510
namespace cpo_types {
26-
// TODO: Rewrite this using concepts.
27-
template<typename S, typename R>
28-
using connect_member_t = decltype(std::declval<S>().connect(std::declval<R>()));
29-
30-
template<typename S, typename R>
31-
constexpr bool has_connect_member_v = is_detected_v<connect_member_t, S, R>;
32-
33-
template<typename S, typename R>
34-
using global_connect_t = decltype(connect(std::declval<S>(), std::declval<R>()));
35-
36-
template<typename S, typename R>
37-
constexpr bool has_global_connect_v = is_detected_v<global_connect_t, S, R>;
38-
39-
struct connect_cpo {
40-
template<typename Sender, typename Receiver>
41-
auto operator() (Sender &&s, Receiver &&r) const {
42-
if constexpr (has_connect_member_v<Sender, Receiver>)
43-
return s.connect(r);
44-
else if constexpr (has_global_connect_v<Sender, Receiver>)
45-
return connect(std::forward<Sender>(s), std::forward<Receiver>(r));
46-
else
47-
static_assert(dependent_false_t<Sender, Receiver>,
48-
"No connect() customization defined for sender type");
49-
}
50-
};
51-
52-
template<typename Op>
53-
using start_member_t = decltype(std::declval<Op>().start());
54-
55-
template<typename Op>
56-
constexpr bool has_start_member_v = is_detected_v<start_member_t, Op>;
57-
58-
template<typename Op>
59-
using global_start_t = decltype(start(std::declval<Op>()));
60-
61-
template<typename Op>
62-
constexpr bool has_global_start_v = is_detected_v<global_start_t, Op>;
63-
64-
struct start_inline_cpo {
65-
template<typename Operation>
66-
bool operator() (Operation &&op) const {
67-
if constexpr (requires { op.start_inline(); }) {
68-
return op.start_inline();
69-
}else if constexpr (has_start_member_v<Operation>) {
70-
op.start();
71-
return false;
72-
}else if constexpr (has_global_start_v<Operation>) {
73-
start(std::forward<Operation>(op));
74-
return false;
75-
}else{
76-
static_assert(dependent_false_t<Operation>,
77-
"No start() customization defined for operation type");
78-
}
79-
}
80-
};
81-
82-
struct set_value_cpo {
83-
template<typename Receiver, typename T>
84-
requires
85-
requires(Receiver &&r, T &&value) { r.set_value_noinline(std::forward<T>(value)); }
86-
void operator() (Receiver &&r, T &&value) {
87-
if constexpr (requires { r.set_value_noinline(std::forward<T>(value)); })
88-
r.set_value_noinline(std::forward<T>(value));
89-
else
90-
// This should have been caught by the concept.
91-
static_assert(dependent_false_t<Receiver>);
92-
}
93-
94-
template<typename Receiver>
95-
requires
96-
requires(Receiver &&r) { r.set_value_noinline(); }
97-
void operator() (Receiver &&r) {
98-
if constexpr (requires { r.set_value_noinline(); })
99-
r.set_value_noinline();
100-
else
101-
// This should have been caught by the concept.
102-
static_assert(dependent_false_t<Receiver>);
103-
}
104-
};
105-
106-
struct set_value_inline_cpo {
107-
template<typename Receiver, typename T>
108-
requires
109-
requires(Receiver &&r, T &&value) { r.set_value_inline(std::forward<T>(value)); }
110-
void operator() (Receiver &&r, T &&value) {
111-
if constexpr (requires { r.set_value_inline(std::forward<T>(value)); })
112-
r.set_value_inline(std::forward<T>(value));
113-
else
114-
// This should have been caught by the concept.
115-
static_assert(dependent_false_t<Receiver>);
116-
}
117-
118-
template<typename Receiver>
119-
requires
120-
requires(Receiver &&r) { r.set_value_inline(); }
121-
void operator() (Receiver &&r) {
122-
if constexpr (requires { r.set_value_inline(); })
123-
r.set_value_inline();
124-
else
125-
// This should have been caught by the concept.
126-
static_assert(dependent_false_t<Receiver>);
127-
}
128-
};
129-
130-
struct set_value_noinline_cpo {
131-
template<typename Receiver, typename T>
132-
requires
133-
requires(Receiver &&r, T &&value) { r.set_value_noinline(std::forward<T>(value)); }
134-
void operator() (Receiver &&r, T &&value) {
135-
if constexpr (requires { r.set_value_noinline(std::forward<T>(value)); })
136-
r.set_value_noinline(std::forward<T>(value));
137-
else
138-
// This should have been caught by the concept.
139-
static_assert(dependent_false_t<Receiver>);
11+
template<typename Sender, typename Receiver>
12+
concept member_connect = requires (Sender &&s, Receiver &&r) {
13+
std::forward<Sender>(s).connect(std::forward<Receiver>(r));
14+
};
15+
16+
template<typename Sender, typename Receiver>
17+
concept global_connect = requires (Sender &&s, Receiver &&r) {
18+
connect(std::forward<Sender>(s), std::forward<Receiver>(r));
19+
};
20+
21+
struct connect_cpo {
22+
template<typename Sender, typename Receiver>
23+
auto operator() (Sender &&s, Receiver &&r) const {
24+
if constexpr (member_connect<Sender, Receiver>) {
25+
return std::forward<Sender>(s).connect(std::forward<Receiver>(r));
26+
} else if constexpr (global_connect<Sender, Receiver>) {
27+
return connect(
28+
std::forward<Sender>(s),
29+
std::forward<Receiver>(r)
30+
);
31+
} else {
32+
static_assert(frg::dependent_false_t<Sender, Receiver>,
33+
"No connect() customization defined for S,R");
14034
}
141-
142-
template<typename Receiver>
143-
requires
144-
requires(Receiver &&r) { r.set_value_noinline(); }
145-
void operator() (Receiver &&r) {
146-
if constexpr (requires { r.set_value_noinline(); })
147-
r.set_value_noinline();
148-
else
149-
// This should have been caught by the concept.
150-
static_assert(dependent_false_t<Receiver>);
35+
}
36+
};
37+
38+
template<typename Operation>
39+
concept inline_startable_operation = requires (Operation &&op) {
40+
{ std::forward<Operation>(op).start_inline() } -> std::convertible_to<bool>;
41+
};
42+
43+
template<typename Operation>
44+
concept member_start = requires (Operation &&op) {
45+
std::forward<Operation>(op).start();
46+
};
47+
48+
template<typename Operation>
49+
concept global_start = requires (Operation &&op) {
50+
start(std::forward<Operation>(op));
51+
};
52+
53+
struct start_inline_cpo {
54+
template<typename Operation>
55+
bool operator() (Operation &&op) const {
56+
if constexpr (inline_startable_operation<Operation>) {
57+
return op.start_inline();
58+
}else if constexpr (member_start<Operation>) {
59+
std::forward<Operation>(op).start();
60+
return false;
61+
}else if constexpr (global_start<Operation>) {
62+
start(std::forward<Operation>(op));
63+
return false;
64+
}else{
65+
static_assert(frg::dependent_false_t<Operation>,
66+
"No start() customization defined for operation type");
15167
}
152-
};
68+
}
69+
};
70+
71+
struct set_value_cpo {
72+
template<typename Receiver, typename T>
73+
requires requires(Receiver &&r, T &&value) {
74+
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
75+
}
76+
void operator() (Receiver &&r, T &&value) {
77+
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
78+
}
79+
80+
template<typename Receiver>
81+
requires requires(Receiver &&r) {
82+
std::forward<Receiver>(r).set_value_noinline();
83+
}
84+
void operator() (Receiver &&r) {
85+
std::forward<Receiver>(r).set_value_noinline();
86+
}
87+
};
88+
89+
struct set_value_inline_cpo {
90+
template<typename Receiver, typename T>
91+
requires requires(Receiver &&r, T &&value) {
92+
std::forward<Receiver>(r).set_value_inline(std::forward<T>(value));
93+
}
94+
void operator() (Receiver &&r, T &&value) {
95+
std::forward<Receiver>(r).set_value_inline(std::forward<T>(value));
96+
}
97+
98+
template<typename Receiver>
99+
requires requires(Receiver &&r) {
100+
std::forward<Receiver>(r).set_value_inline();
101+
}
102+
void operator() (Receiver &&r) {
103+
std::forward<Receiver>(r).set_value_inline();
104+
}
105+
};
106+
107+
struct set_value_noinline_cpo {
108+
template<typename Receiver, typename T>
109+
requires requires(Receiver &&r, T &&value) {
110+
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
111+
}
112+
void operator() (Receiver &&r, T &&value) {
113+
std::forward<Receiver>(r).set_value_noinline(std::forward<T>(value));
114+
}
115+
116+
template<typename Receiver>
117+
requires requires(Receiver &&r) {
118+
std::forward<Receiver>(r).set_value_noinline();
119+
}
120+
void operator() (Receiver &&r) {
121+
std::forward<Receiver>(r).set_value_noinline();
122+
}
123+
};
153124
}
154125

155126
namespace execution {

0 commit comments

Comments
 (0)