1717
1818#include " ../stdexec/__detail/__completion_signatures.hpp"
1919#include " ../stdexec/__detail/__concepts.hpp"
20+ #include " ../stdexec/__detail/__meta.hpp"
2021#include " ../stdexec/__detail/__read_env.hpp"
2122#include " ../stdexec/__detail/__receivers.hpp"
2223#include " ../stdexec/__detail/__sender_concepts.hpp"
24+ #include " ../stdexec/__detail/__static_vector.hpp"
2325#include " ../stdexec/__detail/__tuple.hpp"
26+ #include " ../stdexec/__detail/__typeinfo.hpp"
2427#include " ../stdexec/__detail/__utility.hpp"
2528#include " ../stdexec/functional.hpp"
2629
@@ -287,10 +290,10 @@ namespace experimental::execution
287290 };
288291
289292 template <class Sigs >
290- struct _canonical_t ;
293+ struct _canonical_fn ;
291294
292295 template <class ... Sigs>
293- struct _canonical_t <completion_signatures<Sigs...>>
296+ struct _canonical_fn <completion_signatures<Sigs...>>
294297 {
295298 consteval auto operator ()() const noexcept
296299 {
@@ -303,18 +306,59 @@ namespace experimental::execution
303306 }
304307 };
305308
309+ template <class ... Queries>
310+ struct _canonical_fn <queries<Queries...>>
311+ {
312+ private:
313+ // sort and unique the function types in Queries... into an array of __mtypeids
314+ static consteval auto get_sigs () noexcept
315+ {
316+ using sig_array_t = __static_vector<__type_index, sizeof ...(Queries)>;
317+ auto sigs = sig_array_t {__mtypeid<Queries>...};
318+
319+ std::ranges::sort (sigs);
320+
321+ auto const end = std::ranges::unique (sigs).begin ();
322+ sigs.erase (end, sigs.end ());
323+
324+ return sigs;
325+ }
326+
327+ public:
328+ consteval auto operator ()() const noexcept
329+ {
330+ constexpr auto sigs = get_sigs ();
331+
332+ constexpr auto fn = [=]<std::size_t ... Is>(__indices<Is...>)
333+ {
334+ return queries<__msplice<sigs[Is]>...>();
335+ };
336+
337+ return fn (__make_indices<sigs.size ()>());
338+ }
339+ };
340+
341+ template <>
342+ struct _canonical_fn <queries<>>
343+ {
344+ consteval auto operator ()() const noexcept
345+ {
346+ return queries<>();
347+ }
348+ };
349+
306350 template <class Sigs >
307- inline constexpr _canonical_t <Sigs> _canonical{};
351+ inline constexpr _canonical_fn <Sigs> _canonical{};
308352
309353 template <class Sigs >
310- using _canonical_sigs_t = decltype (_canonical<Sigs>());
354+ using _canonical_t = decltype (_canonical<Sigs>());
311355
312356 // Given a return type and a bool indicating whether the function is noexcept,
313357 // compute the appropriate completion_signatures. The result is a set_value
314358 // overload taking either Return&& or no args when Return is void, set_stopped,
315359 // and, when the function type is not noexcept, set_error(std::exception_ptr)
316360 template <class Return , bool NoExcept>
317- using _sigs_from_t = _canonical_sigs_t <STDEXEC ::__concat_completion_signatures_t <
361+ using _sigs_from_t = _canonical_t <STDEXEC ::__concat_completion_signatures_t <
318362 STDEXEC ::completion_signatures<STDEXEC ::__single_value_sig_t <Return>,
319363 STDEXEC::set_stopped_t ()>,
320364 STDEXEC ::__eptr_completion_unless_t <STDEXEC ::__mbool<NoExcept>>>>;
@@ -416,10 +460,10 @@ namespace experimental::execution
416460 template <class ... Args, class Sigs >
417461 requires STDEXEC ::__is_instance_of<Sigs, STDEXEC ::completion_signatures>
418462 struct function <STDEXEC ::sender_tag(Args...), Sigs>
419- : _func::_func_impl<STDEXEC ::sender_tag(Args...), _func::_canonical_sigs_t <Sigs>, queries<>>
463+ : _func::_func_impl<STDEXEC ::sender_tag(Args...), _func::_canonical_t <Sigs>, queries<>>
420464 {
421465 using base =
422- _func::_func_impl<STDEXEC ::sender_tag(Args...), _func::_canonical_sigs_t <Sigs>, queries<>>;
466+ _func::_func_impl<STDEXEC ::sender_tag(Args...), _func::_canonical_t <Sigs>, queries<>>;
423467
424468 using base::base;
425469
@@ -449,11 +493,11 @@ namespace experimental::execution
449493 struct function <Return(Args...), queries<Queries...>>
450494 : _func::_func_impl<STDEXEC ::sender_tag(Args...),
451495 _func::_sigs_from_t <Return, false >,
452- queries<Queries...>>
496+ _func:: _canonical_t < queries<Queries...> >>
453497 {
454498 using base = _func::_func_impl<STDEXEC ::sender_tag(Args...),
455499 _func::_sigs_from_t <Return, false >,
456- queries<Queries...>>;
500+ _func:: _canonical_t < queries<Queries...> >>;
457501
458502 using base::base;
459503
@@ -483,11 +527,11 @@ namespace experimental::execution
483527 struct function <Return(Args...) noexcept , queries<Queries...>>
484528 : _func::_func_impl<STDEXEC ::sender_tag(Args...),
485529 _func::_sigs_from_t <Return, true >,
486- queries<Queries...>>
530+ _func:: _canonical_t < queries<Queries...> >>
487531 {
488532 using base = _func::_func_impl<STDEXEC ::sender_tag(Args...),
489533 _func::_sigs_from_t <Return, true >,
490- queries<Queries...>>;
534+ _func:: _canonical_t < queries<Queries...> >>;
491535
492536 using base::base;
493537
@@ -518,13 +562,12 @@ namespace experimental::execution
518562 STDEXEC ::completion_signatures<Sigs...>,
519563 queries<Queries...>>
520564 : _func::_func_impl<STDEXEC ::sender_tag(Args...),
521- _func::_canonical_sigs_t <STDEXEC ::completion_signatures<Sigs...>>,
522- queries<Queries...>>
565+ _func::_canonical_t <STDEXEC ::completion_signatures<Sigs...>>,
566+ _func:: _canonical_t < queries<Queries...> >>
523567 {
524- using base =
525- _func::_func_impl<STDEXEC ::sender_tag(Args...),
526- _func::_canonical_sigs_t <STDEXEC ::completion_signatures<Sigs...>>,
527- queries<Queries...>>;
568+ using base = _func::_func_impl<STDEXEC ::sender_tag(Args...),
569+ _func::_canonical_t <STDEXEC ::completion_signatures<Sigs...>>,
570+ _func::_canonical_t <queries<Queries...>>>;
528571
529572 using base::base;
530573
0 commit comments