Skip to content

Commit 9168291

Browse files
ispetersjesswong
andauthored
Add more customizations of get_return_address (#635)
This PR adds customizations of `unifex::get_return_address` to the algorithms we plan to showcase in our CppCon talk; more algoriths to come later. * Customize get_return_address for then * Customize get_return_address for sequence * Customize get_return_address for with_query_value Co-authored-by: jesswong <[email protected]>
1 parent 6cb480c commit 9168291

File tree

4 files changed

+235
-127
lines changed

4 files changed

+235
-127
lines changed

include/unifex/schedule_with_subscheduler.hpp

+3-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ inline const struct _fn {
7070
operator()(Scheduler&& sched) const -> _result_t<Scheduler> {
7171
auto&& scheduleOp = schedule(sched);
7272
return _result_t<Scheduler>{
73-
static_cast<decltype(scheduleOp)>(scheduleOp), {(Scheduler &&) sched}};
73+
static_cast<decltype(scheduleOp)>(scheduleOp),
74+
{(Scheduler &&) sched},
75+
instruction_ptr::read_return_address()};
7476
}
7577
constexpr auto operator()() const
7678
noexcept(std::is_nothrow_invocable_v<tag_t<bind_back>, _fn>)

include/unifex/sequence.hpp

+117-72
Original file line numberDiff line numberDiff line change
@@ -297,11 +297,12 @@ struct _sndr<Predecessor, Successor>::type {
297297
constructible_from<
298298
Successor,
299299
Successor2>) //
300-
explicit type(Predecessor2&& predecessor, Successor2&& successor) noexcept(
300+
explicit type(Predecessor2&& predecessor, Successor2&& successor, instruction_ptr returnAddress) noexcept(
301301
std::is_nothrow_constructible_v<Predecessor, Predecessor2> &&
302302
std::is_nothrow_constructible_v<Successor, Successor2>)
303303
: predecessor_(static_cast<Predecessor&&>(predecessor))
304-
, successor_(static_cast<Successor&&>(successor)) {}
304+
, successor_(static_cast<Successor&&>(successor))
305+
, returnAddress_(returnAddress) {}
305306

306307
friend constexpr blocking_kind tag_invoke(tag_t<blocking>, const type& self) {
307308
blocking_kind pred = blocking(self.predecessor_);
@@ -311,6 +312,11 @@ struct _sndr<Predecessor, Successor>::type {
311312
return std::max(pred(), std::min(succ(), blocking_kind::maybe()));
312313
}
313314

315+
friend instruction_ptr
316+
tag_invoke(tag_t<get_return_address>, const type& t) noexcept {
317+
return t.returnAddress_;
318+
}
319+
314320
template(typename Receiver, typename Sender) //
315321
(requires same_as<remove_cvref_t<Sender>, type> AND
316322
constructible_from<Successor, member_t<Sender, Successor>> AND
@@ -338,84 +344,123 @@ struct _sndr<Predecessor, Successor>::type {
338344
private:
339345
UNIFEX_NO_UNIQUE_ADDRESS Predecessor predecessor_;
340346
UNIFEX_NO_UNIQUE_ADDRESS Successor successor_;
347+
instruction_ptr returnAddress_;
341348
};
342349

343350
namespace _cpo {
344351
struct _fn {
345-
// Sequencing a single sender is just the same as returning the sender
346-
// itself.
347-
template <typename First>
348-
remove_cvref_t<First> operator()(First&& first) const
349-
noexcept(std::is_nothrow_constructible_v<remove_cvref_t<First>, First>) {
350-
return static_cast<First&&>(first);
351-
}
352+
private:
353+
struct _impl_fn {
354+
// Sequencing a single sender is just the same as returning the sender
355+
// itself.
356+
template <typename First>
357+
remove_cvref_t<First> operator()(instruction_ptr, First&& first) const
358+
noexcept(
359+
std::is_nothrow_constructible_v<remove_cvref_t<First>, First>) {
360+
return static_cast<First&&>(first);
361+
}
352362

353-
template(typename First, typename Second) //
354-
(requires sender<First> AND sender<Second> AND
355-
tag_invocable<_fn, First, Second>) //
356-
auto
357-
operator()(First&& first, Second&& second) const
358-
noexcept(is_nothrow_tag_invocable_v<_fn, First, Second>)
359-
-> tag_invoke_result_t<_fn, First, Second> {
360-
return unifex::tag_invoke(
361-
_fn{}, static_cast<First&&>(first), static_cast<Second&&>(second));
362-
}
363+
template(typename First, typename Second) //
364+
(requires sender<First> AND sender<Second> AND
365+
tag_invocable<_fn, First, Second>) //
366+
auto
367+
operator()(instruction_ptr, First&& first, Second&& second) const
368+
noexcept(is_nothrow_tag_invocable_v<_fn, First, Second>)
369+
-> tag_invoke_result_t<_fn, First, Second> {
370+
return unifex::tag_invoke(
371+
_fn{}, static_cast<First&&>(first), static_cast<Second&&>(second));
372+
}
363373

364-
template(typename First, typename Second) //
365-
(requires sender<First> AND
366-
sender<Second> AND(!tag_invocable<_fn, First, Second>)) //
367-
auto
368-
operator()(First&& first, Second&& second) const
369-
noexcept(std::is_nothrow_constructible_v<
370-
_seq::_sender<First, Second>,
371-
First,
372-
Second>) -> _seq::_sender<First, Second> {
373-
return _seq::_sender<First, Second>{
374-
static_cast<First&&>(first), static_cast<Second&&>(second)};
375-
}
374+
template(typename First, typename Second) //
375+
(requires sender<First> AND
376+
sender<Second> AND(!tag_invocable<_fn, First, Second>)) //
377+
auto
378+
operator()(
379+
instruction_ptr returnAddress, First&& first, Second&& second) const
380+
noexcept(std::is_nothrow_constructible_v<
381+
_seq::_sender<First, Second>,
382+
First,
383+
Second,
384+
instruction_ptr>) -> _seq::_sender<First, Second> {
385+
return _seq::_sender<First, Second>{
386+
static_cast<First&&>(first),
387+
static_cast<Second&&>(second),
388+
returnAddress};
389+
}
376390

377-
template(
378-
typename First, typename Second, typename Third, typename... Rest) //
379-
(requires sender<First> AND sender<Second> AND
380-
sender<Third> AND(sender<Rest>&&...)
381-
AND tag_invocable<_fn, First, Second, Third, Rest...>) //
382-
auto
383-
operator()(
384-
First&& first, Second&& second, Third&& third, Rest&&... rest) const
385-
noexcept(is_nothrow_tag_invocable_v<_fn, First, Second, Third, Rest...>)
386-
-> tag_invoke_result_t<_fn, First, Second, Third, Rest...> {
387-
return unifex::tag_invoke(
388-
_fn{},
389-
static_cast<First&&>(first),
390-
static_cast<Second&&>(second),
391-
static_cast<Third&&>(third),
392-
static_cast<Rest&&>(rest)...);
393-
}
391+
template(
392+
typename First, typename Second, typename Third, typename... Rest) //
393+
(requires sender<First> AND sender<Second> AND
394+
sender<Third> AND(sender<Rest>&&...)
395+
AND tag_invocable<_fn, First, Second, Third, Rest...>) //
396+
auto
397+
operator()(
398+
instruction_ptr,
399+
First&& first,
400+
Second&& second,
401+
Third&& third,
402+
Rest&&... rest) const
403+
noexcept(is_nothrow_tag_invocable_v<_fn, First, Second, Third, Rest...>)
404+
-> tag_invoke_result_t<_fn, First, Second, Third, Rest...> {
405+
return unifex::tag_invoke(
406+
_fn{},
407+
static_cast<First&&>(first),
408+
static_cast<Second&&>(second),
409+
static_cast<Third&&>(third),
410+
static_cast<Rest&&>(rest)...);
411+
}
394412

395-
template(
396-
typename First, typename Second, typename Third, typename... Rest) //
397-
(requires sender<First> AND sender<Second> AND
398-
sender<Third> AND(sender<Rest>&&...)
399-
AND(!tag_invocable<_fn, First, Second, Third, Rest...>)) //
400-
auto
401-
operator()(First&& first, Second&& second, Third&& third, Rest&&... rest)
402-
const noexcept(
403-
std::is_nothrow_invocable_v<_fn, First, Second> &&
404-
std::is_nothrow_invocable_v<
405-
_fn,
406-
std::invoke_result_t<_fn, First, Second>,
407-
Third,
408-
Rest...>)
409-
-> std::invoke_result_t<
410-
_fn,
411-
std::invoke_result_t<_fn, First, Second>,
412-
Third,
413-
Rest...> {
414-
// Fall-back to pair-wise invocation of the sequence() CPO.
415-
return (*this)(
416-
(*this)(static_cast<First&&>(first), static_cast<Second&&>(second)),
417-
static_cast<Third&&>(third),
418-
static_cast<Rest&&>(rest)...);
413+
template(
414+
typename First, typename Second, typename Third, typename... Rest) //
415+
(requires sender<First> AND sender<Second> AND
416+
sender<Third> AND(sender<Rest>&&...)
417+
AND(!tag_invocable<_fn, First, Second, Third, Rest...>)) //
418+
auto
419+
operator()(
420+
instruction_ptr returnAddress,
421+
First&& first,
422+
Second&& second,
423+
Third&& third,
424+
Rest&&... rest) const
425+
noexcept(
426+
std::is_nothrow_invocable_v<
427+
_impl_fn,
428+
instruction_ptr,
429+
First,
430+
Second> &&
431+
std::is_nothrow_invocable_v<
432+
_impl_fn,
433+
instruction_ptr,
434+
std::invoke_result_t<_fn, First, Second>,
435+
Third,
436+
Rest...>)
437+
-> std::invoke_result_t<
438+
_impl_fn,
439+
instruction_ptr,
440+
std::invoke_result_t<_fn, First, Second>,
441+
Third,
442+
Rest...> {
443+
// Fall-back to pair-wise invocation of the sequence() CPO.
444+
return (*this)(
445+
returnAddress,
446+
(*this)(
447+
returnAddress,
448+
static_cast<First&&>(first),
449+
static_cast<Second&&>(second)),
450+
static_cast<Third&&>(third),
451+
static_cast<Rest&&>(rest)...);
452+
}
453+
};
454+
455+
public:
456+
template <typename First, typename... Rest>
457+
auto operator()(First&& first, Rest&&... rest) const noexcept(
458+
std::is_nothrow_invocable_v<_impl_fn, instruction_ptr, First, Rest...>)
459+
-> std::invoke_result_t<_impl_fn, instruction_ptr, First, Rest...> {
460+
return _impl_fn{}(
461+
instruction_ptr::read_return_address(),
462+
std::forward<First>(first),
463+
std::forward<Rest>(rest)...);
419464
}
420465
};
421466
} // namespace _cpo

0 commit comments

Comments
 (0)