Repository: NVIDIA/cccl
Pull request #4657: replace the simplistic eager customization mechanism with proper apply/transform_sender
Author: login: ericniebler
Created: 2025-05-07T19:20:15Z | Merged: 2025-05-09T02:47:55Z

## Description

currently ustdex has a rather simplistic dispatch mechanism for finding algorithm customizations that does not handle _late_ customization (at `connect` time). that support will be needed to implement the `schedule_from` algorithm, since `continues_on` lowers to `schedule_from` by default using a late customization hook. and `schedule_from` is needed to properly handle transitions to and from the GPU in the stream and graph schedulers (coming!).

## Checklist
<!-- TODO: - [ ] I am familiar with the [Contributing Guidelines](). -->
- [x] New or existing tests cover these changes.
- [x] The documentation is up to date with these changes.



Diff:
diff --git a/cudax/include/cuda/experimental/__execution/apply_sender.cuh b/cudax/include/cuda/experimental/__execution/apply_sender.cuh
new file mode 100644
index 00000000000..b9939bc0644
--- /dev/null
+++ b/cudax/include/cuda/experimental/__execution/apply_sender.cuh
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of CUDA Experimental in CUDA C++ Core Libraries,
+// under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CUDAX_EXECUTION_APPLY_SENDER
+#define __CUDAX_EXECUTION_APPLY_SENDER
+
+#include <cuda/std/detail/__config>
+
+#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
+#  pragma GCC system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
+#  pragma clang system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
+#  pragma system_header
+#endif // no system header
+
+#include <cuda/std/__type_traits/conditional.h>
+#include <cuda/std/__type_traits/is_valid_expansion.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/domain.cuh>
+
+#include <cuda/experimental/__execution/prologue.cuh>
+
+namespace cuda::experimental::execution
+{
+//! A callable object that implements the `std::execution::apply_sender` functionality.
+//! This is used to apply a sender to a domain, tag, and arguments, as specified in the
+//! C++ standard draft. The implementation ensures compatibility with CUDA C++ Core
+//! Libraries.
+//! @see https://eel.is/c++draft/exec.snd.apply
+struct _CCCL_TYPE_VISIBILITY_DEFAULT apply_sender_t
+{
+private:
+  //! A type alias that determines the domain to apply the sender to. If the expansion of
+  //! `__apply_sender_result_t` is valid for the given domain and arguments, the domain is
+  //! used; otherwise, the `default_domain` is used.
+  //! @tparam _Domain The domain to check.
+  //! @tparam _Args The arguments to validate against the domain.
+  template <class _Domain, class... _Args>
+  using __apply_domain_t _CCCL_NODEBUG_ALIAS = _CUDA_VSTD::
+    _If<_CUDA_VSTD::_IsValidExpansion<__apply_sender_result_t, _Domain, _Args...>::value, _Domain, default_domain>;
+
+public:
+  //! Applies a sender to a domain, tag, and arguments.
+  //! @tparam _Domain The domain used to select the algorithm implementation.
+  //! @tparam _Tag The tag associated with the algorithm.
+  //! @tparam _Sndr The sender to be applied.
+  //! @tparam _Args The arguments to pass to the algorithm.
+  //! @param __sndr The sender object.
+  //! @param __args The arguments to pass to the algorithm.
+  //! @return `DOM().apply_sender(_Tag(), __sndr, __args...)`, where `DOM` is the first of
+  //! [`_Domain`, `default_domain`] to make the expression well-formed.
+  //! @note This function is `constexpr` and `noexcept` if the underlying domain's
+  //! `apply_sender` is `noexcept`.
+  //! @throws Any exception thrown by the underlying domain's `apply_sender`.
+  template <class _Domain, class _Tag, class _Sndr, class... _Args>
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Domain, _Tag, _Sndr&& __sndr, _Args&&... __args) const
+    noexcept(noexcept(__apply_domain_t<_Domain, _Tag, _Sndr, _Args...>{}.apply_sender(
+      _Tag{}, static_cast<_Sndr&&>(__sndr), static_cast<_Args&&>(__args)...)))
+      -> __apply_sender_result_t<__apply_domain_t<_Domain, _Tag, _Sndr, _Args...>, _Tag, _Sndr, _Args...>
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS = __apply_domain_t<_Domain, _Tag, _Sndr, _Args...>;
+    //! Calls the algorithm specified by _Tag using the determined domain.
+    return __dom_t{}.apply_sender(_Tag{}, static_cast<_Sndr&&>(__sndr), static_cast<_Args&&>(__args)...);
+  }
+};
+
+//! A global constant instance of `apply_sender_t`.
+//! This can be used directly to invoke the `apply_sender` functionality.
+_CCCL_GLOBAL_CONSTANT apply_sender_t apply_sender{};
+
+} // namespace cuda::experimental::execution
+
+#include <cuda/experimental/__execution/epilogue.cuh>
+
+#endif // __CUDAX_EXECUTION_APPLY_SENDER
diff --git a/cudax/include/cuda/experimental/__execution/completion_signatures.cuh b/cudax/include/cuda/experimental/__execution/completion_signatures.cuh
index 32a928f3f57..7b888da0dd0 100644
--- a/cudax/include/cuda/experimental/__execution/completion_signatures.cuh
+++ b/cudax/include/cuda/experimental/__execution/completion_signatures.cuh
@@ -34,11 +34,10 @@
 #include <cuda/experimental/__detail/utility.cuh>
 #include <cuda/experimental/__execution/cpos.cuh>
 #include <cuda/experimental/__execution/exception.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/type_traits.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 
-#include <nv/target>
-
 // include this last:
 #include <cuda/experimental/__execution/prologue.cuh>
 
@@ -446,12 +445,15 @@ _CCCL_TRIVIAL_API _CCCL_CONSTEVAL auto get_completion_signatures()
   {
     return __get_completion_signatures_helper<_Sndr>();
   }
+  else if constexpr (!__has_sender_transform<_Sndr, _Env...>)
+  {
+    return __get_completion_signatures_helper<_Sndr, _Env...>();
+  }
   else
   {
-    // BUGBUG TODO:
     // Apply a lazy sender transform if one exists before computing the completion signatures:
-    // using _NewSndr _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__late_domain_of_t<_Sndr, _Env>, _Sndr, _Env>;
-    using _NewSndr _CCCL_NODEBUG_ALIAS = _Sndr;
+    using _NewSndr _CCCL_NODEBUG_ALIAS =
+      _CUDA_VSTD::__call_result_t<transform_sender_t, domain_for_t<_Sndr, _Env...>, _Sndr, _Env...>;
     return __get_completion_signatures_helper<_NewSndr, _Env...>();
   }
 }
diff --git a/cudax/include/cuda/experimental/__execution/conditional.cuh b/cudax/include/cuda/experimental/__execution/conditional.cuh
index fd25844db61..009193dfc65 100644
--- a/cudax/include/cuda/experimental/__execution/conditional.cuh
+++ b/cudax/include/cuda/experimental/__execution/conditional.cuh
@@ -32,6 +32,7 @@
 #include <cuda/experimental/__execution/just_from.cuh>
 #include <cuda/experimental/__execution/meta.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/type_traits.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/variant.cuh>
@@ -178,21 +179,10 @@ private:
     __next_ops_variant_t __ops_;
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Params, class _Sndr>
-    _CCCL_API constexpr auto operator()(_Params __params, _Sndr __sndr) const;
-  };
-
 public:
   template <class _Pred, class _Then, class _Else>
   using params _CCCL_NODEBUG_ALIAS = __closure<_Pred, _Then, _Else>;
 
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Params, class _Sndr>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -242,18 +232,6 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __cond_t::__sndr_t<__cond_t::__closure<_Pre
   }
 };
 
-template <class _Params, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto __cond_t::__fn::operator()(_Params __params, _Sndr __sndr) const
-{
-  if constexpr (!dependent_sender<_Sndr>)
-  {
-    using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<_Params, _Sndr>>;
-    static_assert(__valid_completion_signatures<__completions>);
-  }
-
-  return __sndr_t<_Params, _Sndr>{{}, static_cast<_Params&&>(__params), static_cast<_Sndr&&>(__sndr)};
-}
-
 template <class _Pred, class _Then, class _Else>
 struct _CCCL_TYPE_VISIBILITY_DEFAULT __cond_t::__closure
 {
@@ -264,13 +242,16 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __cond_t::__closure
   template <class _Sndr>
   _CCCL_TRIVIAL_API auto __mk_sender(_Sndr&& __sndr) -> __sndr_t<__closure, _Sndr>
   {
+    using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr>;
+
     if constexpr (!dependent_sender<_Sndr>)
     {
       using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<__closure, _Sndr>>;
       static_assert(__valid_completion_signatures<__completions>);
     }
 
-    return __sndr_t<__closure, _Sndr>{{}, static_cast<__closure&&>(*this), static_cast<_Sndr&&>(__sndr)};
+    return transform_sender(
+      __dom_t{}, __sndr_t<__closure, _Sndr>{{}, static_cast<__closure&&>(*this), static_cast<_Sndr&&>(__sndr)});
   }
 
   template <class _Sndr>
@@ -289,10 +270,10 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __cond_t::__closure
 template <class _Sndr, class _Pred, class _Then, class _Else>
 _CCCL_TRIVIAL_API constexpr auto __cond_t::operator()(_Sndr __sndr, _Pred __pred, _Then __then, _Else __else) const
 {
-  using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-  __closure<_Pred, _Then, _Else> __params{
-    static_cast<_Pred&&>(__pred), static_cast<_Then&&>(__then), static_cast<_Else&&>(__else)};
-  return __dom_t::__apply(*this)(static_cast<__closure<_Pred, _Then, _Else>&&>(__params), static_cast<_Sndr&&>(__sndr));
+  using __dom_t _CCCL_NODEBUG_ALIAS    = domain_for_t<_Sndr>;
+  using __params_t _CCCL_NODEBUG_ALIAS = __closure<_Pred, _Then, _Else>;
+  __params_t __params{static_cast<_Pred&&>(__pred), static_cast<_Then&&>(__then), static_cast<_Else&&>(__else)};
+  return static_cast<__params_t&&>(__params).__mk_sender(static_cast<_Sndr&&>(__sndr));
 }
 
 template <class _Pred, class _Then, class _Else>
diff --git a/cudax/include/cuda/experimental/__execution/continues_on.cuh b/cudax/include/cuda/experimental/__execution/continues_on.cuh
index 77c794e341b..4668569477c 100644
--- a/cudax/include/cuda/experimental/__execution/continues_on.cuh
+++ b/cudax/include/cuda/experimental/__execution/continues_on.cuh
@@ -32,6 +32,7 @@
 #include <cuda/experimental/__execution/meta.cuh>
 #include <cuda/experimental/__execution/queries.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/variant.cuh>
 #include <cuda/experimental/__execution/visit.cuh>
@@ -169,18 +170,7 @@ private:
     connect_result_t<schedule_result_t<_Sch>, __rcvr_ref<__rcvr_t<_Rcvr, __result_t>>> __opstate2_;
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Sch, class _Sndr>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Sch __sch, _Sndr __sndr) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Sndr, class _Sch>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -291,17 +281,11 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT continues_on_t::__sndr_t
   }
 };
 
-template <class _Sch, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto continues_on_t::__fn::operator()(_Sch __sch, _Sndr __sndr) const
-{
-  return __sndr_t<_Sndr, _Sch>{{}, __sch, static_cast<_Sndr&&>(__sndr)};
-}
-
 template <class _Sndr, class _Sch>
 _CCCL_TRIVIAL_API constexpr auto continues_on_t::operator()(_Sndr __sndr, _Sch __sch) const
 {
-  using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-  return __dom_t::__apply(*this)(static_cast<_Sch&&>(__sch), static_cast<_Sndr&&>(__sndr));
+  using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr>;
+  return transform_sender(__dom_t{}, __sndr_t<_Sndr, _Sch>{{}, __sch, static_cast<_Sndr&&>(__sndr)});
 }
 
 template <class _Sch>
diff --git a/cudax/include/cuda/experimental/__execution/cpos.cuh b/cudax/include/cuda/experimental/__execution/cpos.cuh
index feb52464999..58e5a4a4bd7 100644
--- a/cudax/include/cuda/experimental/__execution/cpos.cuh
+++ b/cudax/include/cuda/experimental/__execution/cpos.cuh
@@ -23,7 +23,9 @@
 
 #include <cuda/std/__type_traits/is_same.h>
 
+#include <cuda/experimental/__execution/env.cuh>
 #include <cuda/experimental/__execution/fwd.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 
 #include <cuda/experimental/__execution/prologue.cuh>
 
@@ -100,19 +102,34 @@ struct start_t
 // connect
 struct connect_t
 {
-  template <class _Sndr, class _Rcvr>
-  _CCCL_TRIVIAL_API auto operator()(_Sndr&& __sndr, _Rcvr&& __rcvr) const
-    noexcept(noexcept(static_cast<_Sndr&&>(__sndr).connect(static_cast<_Rcvr&&>(__rcvr))))
-      -> decltype(static_cast<_Sndr&&>(__sndr).connect(static_cast<_Rcvr&&>(__rcvr)))
+  template <class _Sndr, class _Rcvr, class _Domain = domain_for_t<_Sndr, env_of_t<_Rcvr>>>
+  _CCCL_TRIVIAL_API static constexpr auto __do_transform(_Sndr&& __sndr, _Rcvr __rcvr) noexcept(
+    noexcept(transform_sender(_Domain{}, declval<_Sndr>(), get_env(__rcvr)))) -> decltype(auto)
+  {
+    return transform_sender(_Domain{}, static_cast<_Sndr&&>(__sndr), get_env(__rcvr));
+  }
+
+  _CCCL_TEMPLATE(class _Sndr, class _Rcvr)
+  _CCCL_REQUIRES((!__has_sender_transform<_Sndr, env_of_t<_Rcvr>>) )
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Sndr&& __sndr, _Rcvr __rcvr) const
+    noexcept(noexcept(declval<_Sndr>().connect(declval<_Rcvr>()))) -> decltype(auto)
   {
     return static_cast<_Sndr&&>(__sndr).connect(static_cast<_Rcvr&&>(__rcvr));
   }
+
+  _CCCL_TEMPLATE(class _Sndr, class _Rcvr)
+  _CCCL_REQUIRES(__has_sender_transform<_Sndr, env_of_t<_Rcvr>>)
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Sndr&& __sndr, _Rcvr __rcvr) const
+    noexcept(noexcept(__do_transform(declval<_Sndr>(), __rcvr).connect(declval<_Rcvr>()))) -> decltype(auto)
+  {
+    return __do_transform(static_cast<_Sndr&&>(__sndr), __rcvr).connect(static_cast<_Rcvr&&>(__rcvr));
+  }
 };
 
 struct schedule_t
 {
   template <class _Sch>
-  _CCCL_TRIVIAL_API auto operator()(_Sch&& __sch) const noexcept -> decltype(static_cast<_Sch&&>(__sch).schedule())
+  _CCCL_TRIVIAL_API auto operator()(_Sch&& __sch) const noexcept -> decltype(declval<_Sch>().schedule())
   {
     static_assert(noexcept(static_cast<_Sch&&>(__sch).schedule()));
     return static_cast<_Sch&&>(__sch).schedule();
diff --git a/cudax/include/cuda/experimental/__execution/domain.cuh b/cudax/include/cuda/experimental/__execution/domain.cuh
index ddb95b85b6c..e31feb8dea5 100644
--- a/cudax/include/cuda/experimental/__execution/domain.cuh
+++ b/cudax/include/cuda/experimental/__execution/domain.cuh
@@ -21,17 +21,123 @@
 #  pragma system_header
 #endif // no system header
 
+#include <cuda/std/__execution/env.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
 #include <cuda/experimental/__execution/fwd.cuh>
 
 #include <cuda/experimental/__execution/prologue.cuh>
 
 namespace cuda::experimental::execution
 {
-template <class _Tag>
-_CCCL_API constexpr auto default_domain::__apply(_Tag) noexcept
+using _CUDA_STD_EXEC::__query_result_t;
+using _CUDA_STD_EXEC::__queryable_with;
+using _CUDA_STD_EXEC::env_of_t;
+
+template <class _DomainOrTag, class... _Args>
+using __apply_sender_result_t _CCCL_NODEBUG_ALIAS = decltype(_DomainOrTag{}.apply_sender(declval<_Args>()...));
+
+template <class _DomainOrTag, class _Sndr, class... _Env>
+using __transform_sender_result_t =
+  decltype(_DomainOrTag{}.transform_sender(declval<_Sndr>(), declval<const _Env&>()...));
+
+//! @brief A structure that selects the default set of algorithm implementations for
+//! senders.
+//!
+//! This structure defines static member functions to handle operations on senders, such
+//! as applying and transforming them. It is designed to work with CUDA's experimental
+//! execution framework.
+//! @see https://eel.is/c++draft/exec.domain.default
+struct _CCCL_TYPE_VISIBILITY_DEFAULT default_domain
+{
+  //! @brief Applies a sender operation using the specified tag and arguments.
+  //!
+  //! @tparam _Tag The tag type that defines the operation to be applied.
+  //! @tparam _Sndr The type of the sender.
+  //! @tparam _Args Variadic template for additional arguments.
+  //! @param _Tag The tag instance specifying the operation.
+  //! @param __sndr The sender to which the operation is applied.
+  //! @param __args Additional arguments for the operation.
+  //! @return The result of applying the sender operation.
+  template <class _Tag, class _Sndr, class... _Args>
+  _CCCL_TRIVIAL_API static constexpr auto apply_sender(_Tag, _Sndr&& __sndr, _Args&&... __args) noexcept(noexcept(
+    _Tag{}.apply_sender(declval<_Sndr>(), declval<_Args>()...))) -> __apply_sender_result_t<_Tag, _Sndr, _Args...>
+  {
+    return _Tag{}.apply_sender(static_cast<_Sndr&&>(__sndr), static_cast<_Args&&>(__args)...);
+  }
+
+  //! @brief Transforms a sender with an optional environment.
+  //!
+  //! @tparam _Sndr The type of the sender.
+  //! @tparam _Env The type of the environment.
+  //! @param __sndr The sender to be transformed.
+  //! @param __env The environment used for the transformation.
+  //! @return The result of transforming the sender with the given environment.
+  template <class _Sndr, class _Env>
+  _CCCL_TRIVIAL_API static constexpr auto transform_sender(_Sndr&& __sndr, const _Env& __env) noexcept(
+    noexcept(tag_of_t<_Sndr>{}.transform_sender(static_cast<_Sndr&&>(__sndr), __env)))
+    -> __transform_sender_result_t<tag_of_t<_Sndr>, _Sndr, _Env>
+  {
+    return tag_of_t<_Sndr>{}.transform_sender(static_cast<_Sndr&&>(__sndr), __env);
+  }
+
+  //! @overload
+  template <class _Sndr>
+  _CCCL_TRIVIAL_API static constexpr auto transform_sender(_Sndr&& __sndr) noexcept -> _Sndr&&
+  {
+    // FUTURE TODO: add a transform for the split sender once we have a split sender
+    return static_cast<_Sndr&&>(__sndr);
+  }
+
+  //! @overload
+  template <class _Sndr>
+  _CCCL_TRIVIAL_API static constexpr auto transform_sender(_Sndr&& __sndr, _CUDA_VSTD::__ignore_t) noexcept -> _Sndr&&
+  {
+    return static_cast<_Sndr&&>(__sndr);
+  }
+};
+
+namespace __detail
+{
+// This function is used to determine the domain associated with a sender and
+// (optionally), an environment. It uses clues from the sender and environment to deduce
+// where the sender will execute (on what scheduler), and what the domain of that
+// scheduler is. It proceeds as follows:
+// 1. If the sender attributes has a domain, return it.
+// 2. Otherwise, if the sender has a completion scheduler, return its domain if any.
+// 3. Otherwise, if an environment is provided:
+//   - If the environment has a domain, return it.
+//   - If the environment has a scheduler, return its domain if any.
+// 4. Otherwise, return the default domain.
+template <class _GetScheduler, class _Env1, class _Env2 = _CUDA_STD_EXEC::prop<get_domain_t, default_domain>>
+_CCCL_TRIVIAL_API constexpr auto __domain_for() noexcept
 {
-  return _Tag::__apply();
+  if constexpr (__queryable_with<_Env1, get_domain_t>)
+  {
+    return __query_result_t<_Env1, get_domain_t>{};
+  }
+  else if constexpr (__queryable_with<_Env1, _GetScheduler>)
+  {
+    if constexpr (__queryable_with<__query_result_t<_Env1, _GetScheduler>, get_domain_t>)
+    {
+      return __query_result_t<__query_result_t<_Env1, _GetScheduler>, get_domain_t>{};
+    }
+    else
+    {
+      return __domain_for<get_scheduler_t, _Env2>();
+    }
+  }
+  else
+  {
+    return __domain_for<get_scheduler_t, _Env2>();
+  }
 }
+} // namespace __detail
+
+template <class _Sndr, class... _Env>
+using domain_for_t _CCCL_NODEBUG_ALIAS =
+  decltype(__detail::__domain_for<get_completion_scheduler_t<set_value_t>, env_of_t<_Sndr>, _Env...>());
+
 } // namespace cuda::experimental::execution
 
 #include <cuda/experimental/__execution/epilogue.cuh>
diff --git a/cudax/include/cuda/experimental/__execution/env.cuh b/cudax/include/cuda/experimental/__execution/env.cuh
index 24f76b5eb72..013506f4839 100644
--- a/cudax/include/cuda/experimental/__execution/env.cuh
+++ b/cudax/include/cuda/experimental/__execution/env.cuh
@@ -26,7 +26,6 @@
 #include <cuda/std/__type_traits/is_same.h>
 #include <cuda/std/__utility/move.h>
 
-#include <cuda/experimental/__execution/cpos.cuh>
 #include <cuda/experimental/__execution/policy.cuh>
 #include <cuda/experimental/__execution/queries.cuh>
 #include <cuda/experimental/__memory_resource/any_resource.cuh>
@@ -49,34 +48,6 @@ using _CUDA_STD_EXEC::prop;
 using _CUDA_STD_EXEC::__nothrow_queryable_with;
 using _CUDA_STD_EXEC::__query_result_t;
 using _CUDA_STD_EXEC::__queryable_with;
-
-struct __not_a_scheduler
-{
-  using scheduler_concept _CCCL_NODEBUG_ALIAS = scheduler_t;
-};
-
-using __no_completion_scheduler_t _CCCL_NODEBUG_ALIAS =
-  prop<get_completion_scheduler_t<set_value_t>, __not_a_scheduler>;
-using __no_scheduler_t = prop<get_scheduler_t, __not_a_scheduler>;
-
-// First look in the sender's environment for a domain. If none is found, look
-// in the sender's (value) completion scheduler, if any.
-template <class _Sndr>
-using __early_domain_env _CCCL_NODEBUG_ALIAS =
-  env<env_of_t<_Sndr>, __completion_scheduler_of_t<env<env_of_t<_Sndr>, __no_completion_scheduler_t>>>;
-
-template <class _Sndr>
-using early_domain_of_t _CCCL_NODEBUG_ALIAS = __domain_of_t<__early_domain_env<_Sndr>>;
-
-// First look in the sender's environment for a domain. If none is found, look
-// in the sender's (value) completion scheduler, if any. Then look in _Env for a
-// domain. If none is found, look in the environment's scheduler, if any.
-template <class _Sndr, class _Env>
-using __late_domain_env _CCCL_NODEBUG_ALIAS =
-  env<__early_domain_env<_Sndr>, env<_Env, __scheduler_of_t<env<_Env, __no_scheduler_t>>>>;
-
-template <class _Sndr, class _Env>
-using late_domain_of_t _CCCL_NODEBUG_ALIAS = __domain_of_t<__late_domain_env<_Sndr, _Env>>;
 } // namespace execution
 
 template <class... _Properties>
diff --git a/cudax/include/cuda/experimental/__execution/fwd.cuh b/cudax/include/cuda/experimental/__execution/fwd.cuh
index f8d45a20492..418c0a52c40 100644
--- a/cudax/include/cuda/experimental/__execution/fwd.cuh
+++ b/cudax/include/cuda/experimental/__execution/fwd.cuh
@@ -21,10 +21,13 @@
 #  pragma system_header
 #endif // no system header
 
+#include <cuda/std/__tuple_dir/ignore.h>
 #include <cuda/std/__type_traits/remove_reference.h>
 #include <cuda/std/__type_traits/type_list.h>
 
+#include <cuda/experimental/__detail/utility.cuh>
 #include <cuda/experimental/__execution/meta.cuh>
+#include <cuda/experimental/__execution/visit.cuh>
 
 #include <cuda/experimental/__execution/prologue.cuh>
 
@@ -63,11 +66,7 @@ inline constexpr bool __is_scheduler = __type_valid_v<__scheduler_concept_t, _Ty
 struct stream_domain;
 struct dependent_sender_error;
 
-struct default_domain
-{
-  template <class _Tag>
-  _CCCL_API static constexpr auto __apply(_Tag) noexcept;
-};
+struct default_domain;
 
 template <class... _Sigs>
 struct completion_signatures;
@@ -92,8 +91,34 @@ struct set_stopped_t;
 struct start_t;
 struct connect_t;
 struct schedule_t;
-struct get_env_t;
 struct sync_wait_t;
+struct start_detached_t;
+
+struct get_allocator_t;
+struct get_stop_token_t;
+struct get_scheduler_t;
+struct get_delegation_scheduler_t;
+template <class _Tag>
+struct get_completion_scheduler_t;
+struct get_forward_progress_guarantee_t;
+struct get_domain_t;
+
+namespace __detail
+{
+struct __get_tag
+{
+  template <class _Tag, class... _Child>
+  _CCCL_TRIVIAL_API constexpr auto operator()(_CUDA_VSTD::__ignore_t, _Tag, _CUDA_VSTD::__ignore_t, _Child&&...) const
+    -> _Tag
+  {
+    return _Tag{};
+  }
+};
+} // namespace __detail
+
+template <class _Sndr>
+using tag_of_t _CCCL_NODEBUG_ALIAS =
+  decltype(visit(declval<__detail::__get_tag&>(), declval<_Sndr>(), declval<int&>()));
 
 namespace __detail
 {
diff --git a/cudax/include/cuda/experimental/__execution/let_value.cuh b/cudax/include/cuda/experimental/__execution/let_value.cuh
index 897d5ae8da8..e639d810a56 100644
--- a/cudax/include/cuda/experimental/__execution/let_value.cuh
+++ b/cudax/include/cuda/experimental/__execution/let_value.cuh
@@ -32,6 +32,7 @@
 #include <cuda/experimental/__execution/env.cuh>
 #include <cuda/experimental/__execution/exception.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/type_traits.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/variant.cuh>
@@ -222,18 +223,7 @@ private:
     }
   };
 
-  struct __fn
-  {
-    template <class _Fn, class _Sndr>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Fn __fn, _Sndr __sndr) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   /// @brief The `let_(value|error|stopped)` sender.
   /// @tparam _Sndr The predecessor sender.
   /// @tparam _Fn The function to be called when the predecessor sender
@@ -327,9 +317,10 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __let_t<_Disposition>::__closure_t
 };
 
 template <__disposition_t _Disposition>
-template <class _Fn, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto __let_t<_Disposition>::__fn::operator()(_Fn __fn, _Sndr __sndr) const
+template <class _Sndr, class _Fn>
+_CCCL_TRIVIAL_API constexpr auto __let_t<_Disposition>::operator()(_Sndr __sndr, _Fn __fn) const
 {
+  using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr>;
   // If the incoming sender is non-dependent, we can check the completion
   // signatures of the composed sender immediately.
   if constexpr (!dependent_sender<_Sndr>)
@@ -337,15 +328,7 @@ _CCCL_TRIVIAL_API constexpr auto __let_t<_Disposition>::__fn::operator()(_Fn __f
     using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<_Sndr, _Fn>>;
     static_assert(__valid_completion_signatures<__completions>);
   }
-  return __sndr_t<_Sndr, _Fn>{{}, static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr)};
-}
-
-template <__disposition_t _Disposition>
-template <class _Sndr, class _Fn>
-_CCCL_TRIVIAL_API constexpr auto __let_t<_Disposition>::operator()(_Sndr __sndr, _Fn __fn) const
-{
-  using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-  return __dom_t::__apply(*this)(static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr));
+  return transform_sender(__dom_t{}, __sndr_t<_Sndr, _Fn>{{}, static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr)});
 }
 
 template <__disposition_t _Disposition>
diff --git a/cudax/include/cuda/experimental/__execution/rcvr_with_env.cuh b/cudax/include/cuda/experimental/__execution/rcvr_with_env.cuh
index 647268d630d..01f12edd4e9 100644
--- a/cudax/include/cuda/experimental/__execution/rcvr_with_env.cuh
+++ b/cudax/include/cuda/experimental/__execution/rcvr_with_env.cuh
@@ -54,7 +54,7 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __rcvr_with_env_t : _Rcvr
       noexcept(__nothrow_queryable_with<__1st_env_t<_Query>, _Query>) //
       -> __query_result_t<__1st_env_t<_Query>, _Query>
     {
-      return __env_t::__get_1st<_Query>(*this);
+      return __env_t::__get_1st<_Query>(*this).query(_Query{});
     }
 
     __rcvr_with_env_t const* __rcvr_;
diff --git a/cudax/include/cuda/experimental/__execution/sequence.cuh b/cudax/include/cuda/experimental/__execution/sequence.cuh
index 7e3384c8f60..d98df1662c8 100644
--- a/cudax/include/cuda/experimental/__execution/sequence.cuh
+++ b/cudax/include/cuda/experimental/__execution/sequence.cuh
@@ -29,6 +29,7 @@
 #include <cuda/experimental/__execution/exception.cuh>
 #include <cuda/experimental/__execution/lazy.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/variant.cuh>
 #include <cuda/experimental/__execution/visit.cuh>
@@ -99,18 +100,7 @@ private:
     connect_result_t<__sndr2_t, __rcvr_ref<__rcvr_t>> __opstate2_;
   };
 
-  struct __fn
-  {
-    template <class _Sndr1, class _Sndr2>
-    _CCCL_TRIVIAL_API constexpr auto operator()(__ignore, _Sndr1 __sndr1, _Sndr2 __sndr2) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Sndr1, class _Sndr2>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -165,18 +155,12 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __seq_t::__sndr_t
   __sndr2_t __sndr2_;
 };
 
-template <class _Sndr1, class _Sndr2>
-_CCCL_TRIVIAL_API constexpr auto __seq_t::__fn::operator()(__ignore, _Sndr1 __sndr1, _Sndr2 __sndr2) const
-{
-  using __sndr_t _CCCL_NODEBUG_ALIAS = __seq_t::__sndr_t<_Sndr1, _Sndr2>;
-  return __sndr_t{{}, {}, static_cast<_Sndr1&&>(__sndr1), static_cast<_Sndr2&&>(__sndr2)};
-}
-
 template <class _Sndr1, class _Sndr2>
 _CCCL_TRIVIAL_API constexpr auto __seq_t::operator()(_Sndr1 __sndr1, _Sndr2 __sndr2) const
 {
-  using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr1>;
-  return __dom_t::__apply(*this)(__ignore{}, static_cast<_Sndr1&&>(__sndr1), static_cast<_Sndr2&&>(__sndr2));
+  using __dom_t _CCCL_NODEBUG_ALIAS  = domain_for_t<_Sndr1>;
+  using __sndr_t _CCCL_NODEBUG_ALIAS = __seq_t::__sndr_t<_Sndr1, _Sndr2>;
+  return transform_sender(__dom_t{}, __sndr_t{{}, {}, static_cast<_Sndr1&&>(__sndr1), static_cast<_Sndr2&&>(__sndr2)});
 }
 
 template <class _Sndr1, class _Sndr2>
diff --git a/cudax/include/cuda/experimental/__execution/start_detached.cuh b/cudax/include/cuda/experimental/__execution/start_detached.cuh
index 75493d6144f..cc556c12b12 100644
--- a/cudax/include/cuda/experimental/__execution/start_detached.cuh
+++ b/cudax/include/cuda/experimental/__execution/start_detached.cuh
@@ -24,6 +24,7 @@
 #include <cuda/std/__exception/terminate.h>
 
 #include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/apply_sender.cuh>
 #include <cuda/experimental/__execution/cpos.cuh>
 #include <cuda/experimental/__execution/env.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
@@ -86,27 +87,19 @@ private:
     }
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Sndr>
-    _CCCL_API auto operator()(_Sndr __sndr) const
-    {
-      execution::start(*new __opstate_t<_Sndr>{static_cast<_Sndr&&>(__sndr)});
-    }
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
+  template <class _Sndr>
+  _CCCL_API static auto apply_sender(_Sndr __sndr)
   {
-    return __fn{};
+    execution::start(*new __opstate_t<_Sndr>{static_cast<_Sndr&&>(__sndr)});
   }
 
   /// run detached.
   template <class _Sndr>
   _CCCL_TRIVIAL_API void operator()(_Sndr __sndr) const
   {
-    using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-    __dom_t::__apply (*this)(static_cast<_Sndr&&>(__sndr));
+    using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr>;
+    execution::apply_sender(__dom_t{}, *this, static_cast<_Sndr&&>(__sndr));
   }
 };
 
diff --git a/cudax/include/cuda/experimental/__execution/starts_on.cuh b/cudax/include/cuda/experimental/__execution/starts_on.cuh
index 0f43ec855a5..2002eb27221 100644
--- a/cudax/include/cuda/experimental/__execution/starts_on.cuh
+++ b/cudax/include/cuda/experimental/__execution/starts_on.cuh
@@ -85,18 +85,7 @@ private:
     connect_result_t<_CvSndr, __rcvr_ref<__rcvr_with_sch_t>> __opstate2_;
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Sch, class _Sndr>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Sch __sch, _Sndr __sndr) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Sch, class _Sndr>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -151,17 +140,12 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT starts_on_t::__sndr_t
   }
 };
 
-template <class _Sch, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto starts_on_t::__fn::operator()(_Sch __sch, _Sndr __sndr) const
-{
-  return __sndr_t<_Sch, _Sndr>{{}, __sch, __sndr};
-}
-
 template <class _Sch, class _Sndr>
 _CCCL_TRIVIAL_API constexpr auto starts_on_t::operator()(_Sch __sch, _Sndr __sndr) const
 {
-  using __dom_t _CCCL_NODEBUG_ALIAS = __domain_of_t<_Sch>; // see [exec.starts.on]
-  return __dom_t::__apply(*this)(static_cast<_Sch&&>(__sch), static_cast<_Sndr&&>(__sndr));
+  using __dom_t _CCCL_NODEBUG_ALIAS  = __domain_of_t<_Sch>; // see [exec.starts.on]
+  using __sndr_t _CCCL_NODEBUG_ALIAS = starts_on_t::__sndr_t<_Sch, _Sndr>;
+  return transform_sender(__dom_t{}, __sndr_t{{}, static_cast<_Sch&&>(__sch), static_cast<_Sndr&&>(__sndr)});
 }
 
 template <class _Sch, class _Sndr>
diff --git a/cudax/include/cuda/experimental/__execution/sync_wait.cuh b/cudax/include/cuda/experimental/__execution/sync_wait.cuh
index e6eecbc5ac6..94b2673f9d3 100644
--- a/cudax/include/cuda/experimental/__execution/sync_wait.cuh
+++ b/cudax/include/cuda/experimental/__execution/sync_wait.cuh
@@ -27,6 +27,7 @@
 #include <cuda/std/optional>
 #include <cuda/std/tuple>
 
+#include <cuda/experimental/__execution/apply_sender.cuh>
 #include <cuda/experimental/__execution/env.cuh>
 #include <cuda/experimental/__execution/exception.cuh>
 #include <cuda/experimental/__execution/meta.cuh>
@@ -130,53 +131,45 @@ private:
     int i{}; // so that structured bindings kinda work
   };
 
+public:
   // This is the actual default sync_wait implementation.
-  struct __fn
+  template <class _Sndr>
+  _CCCL_HOST_API static auto apply_sender(_Sndr&& __sndr)
   {
-    template <class _Sndr>
-    _CCCL_HOST_API auto operator()(_Sndr&& __sndr) const
-    {
-      using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<_Sndr, __env_t>;
-
-      if constexpr (!__valid_completion_signatures<__completions>)
-      {
-        return __bad_sync_wait<__completions>::__result();
-      }
-      else
-      {
-        using __values _CCCL_NODEBUG_ALIAS = __value_types<__completions, _CUDA_VSTD::tuple, _CUDA_VSTD::__type_self_t>;
-        _CUDA_VSTD::optional<__values> __result{};
-        __state_t<__values> __state{&__result, {}, {}};
+    using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<_Sndr, __env_t>;
 
-        // Launch the sender with a continuation that will fill in a variant
-        using __rcvr   = typename __state_t<__values>::__rcvr_t;
-        auto __opstate = execution::connect(static_cast<_Sndr&&>(__sndr), __rcvr{&__state});
-        execution::start(__opstate);
+    if constexpr (!__valid_completion_signatures<__completions>)
+    {
+      return __bad_sync_wait<__completions>::__result();
+    }
+    else
+    {
+      using __values _CCCL_NODEBUG_ALIAS = __value_types<__completions, _CUDA_VSTD::tuple, _CUDA_VSTD::__type_self_t>;
+      _CUDA_VSTD::optional<__values> __result{};
+      __state_t<__values> __state{&__result, {}, {}};
 
-        // Wait for the variant to be filled in, and process any work that
-        // may be delegated to this thread.
-        __state.__loop_.run();
+      // Launch the sender with a continuation that will fill in a variant
+      using __rcvr   = typename __state_t<__values>::__rcvr_t;
+      auto __opstate = execution::connect(static_cast<_Sndr&&>(__sndr), __rcvr{&__state});
+      execution::start(__opstate);
 
-        if (__state.__eptr_)
-        {
-          ::std::rethrow_exception(__state.__eptr_);
-        }
+      // Wait for the variant to be filled in, and process any work that
+      // may be delegated to this thread.
+      __state.__loop_.run();
 
-        return __result; // uses NRVO to "return" the result
+      if (__state.__eptr_)
+      {
+        ::std::rethrow_exception(__state.__eptr_);
       }
-    }
 
-    template <class _Sndr, class _Env>
-    _CCCL_HOST_API auto operator()(_Sndr&& __sndr, _Env&& __env) const
-    {
-      return (*this)(execution::write_env(static_cast<_Sndr&&>(__sndr), static_cast<_Env&&>(__env)));
+      return __result; // uses NRVO to "return" the result
     }
-  };
+  }
 
-public:
-  _CCCL_HOST_API static constexpr auto __apply() noexcept
+  template <class _Sndr, class _Env>
+  _CCCL_HOST_API static auto apply_sender(_Sndr&& __sndr, _Env&& __env)
   {
-    return __fn{};
+    return apply_sender(execution::write_env(static_cast<_Sndr&&>(__sndr), static_cast<_Env&&>(__env)));
   }
 
   // clang-format off
@@ -206,18 +199,11 @@ public:
   ///         `cudaError_t`.
   /// @throws error otherwise
   // clang-format on
-  template <class _Sndr>
-  _CCCL_HOST_API auto operator()(_Sndr&& __sndr) const
-  {
-    using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-    return __dom_t::__apply(*this)(static_cast<_Sndr&&>(__sndr));
-  }
-
-  template <class _Sndr, class _Env>
-  _CCCL_HOST_API auto operator()(_Sndr&& __sndr, _Env&& __env) const
+  template <class _Sndr, class... _Env>
+  _CCCL_HOST_API auto operator()(_Sndr&& __sndr, _Env&&... __env) const
   {
-    using __dom_t _CCCL_NODEBUG_ALIAS = late_domain_of_t<_Sndr, _Env>;
-    return __dom_t::__apply(*this)(static_cast<_Sndr&&>(__sndr), static_cast<_Env&&>(__env));
+    using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr, _Env...>;
+    return execution::apply_sender(__dom_t{}, *this, static_cast<_Sndr&&>(__sndr), static_cast<_Env&&>(__env)...);
   }
 };
 
diff --git a/cudax/include/cuda/experimental/__execution/then.cuh b/cudax/include/cuda/experimental/__execution/then.cuh
index cb6159c62f6..3e53e2a939f 100644
--- a/cudax/include/cuda/experimental/__execution/then.cuh
+++ b/cudax/include/cuda/experimental/__execution/then.cuh
@@ -34,6 +34,7 @@
 #include <cuda/experimental/__execution/exception.cuh>
 #include <cuda/experimental/__execution/meta.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/visit.cuh>
 
@@ -212,18 +213,7 @@ private:
     }
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Fn, class _Sndr>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Fn __fn, _Sndr __sndr) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Fn, class _Sndr>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -316,9 +306,10 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT __upon_t<_Disposition>::__closure_t
 };
 
 template <__disposition_t _Disposition>
-template <class _Fn, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto __upon_t<_Disposition>::__fn::operator()(_Fn __fn, _Sndr __sndr) const
+template <class _Sndr, class _Fn>
+_CCCL_TRIVIAL_API constexpr auto __upon_t<_Disposition>::operator()(_Sndr __sndr, _Fn __fn) const
 {
+  using __dom_t _CCCL_NODEBUG_ALIAS = domain_for_t<_Sndr>;
   // If the incoming sender is non-dependent, we can check the completion
   // signatures of the composed sender immediately.
   if constexpr (!dependent_sender<_Sndr>)
@@ -326,15 +317,7 @@ _CCCL_TRIVIAL_API constexpr auto __upon_t<_Disposition>::__fn::operator()(_Fn __
     using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<_Fn, _Sndr>>;
     static_assert(__valid_completion_signatures<__completions>);
   }
-  return __sndr_t<_Fn, _Sndr>{{}, static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr)};
-}
-
-template <__disposition_t _Disposition>
-template <class _Sndr, class _Fn>
-_CCCL_TRIVIAL_API constexpr auto __upon_t<_Disposition>::operator()(_Sndr __sndr, _Fn __fn) const
-{
-  using __dom_t _CCCL_NODEBUG_ALIAS = early_domain_of_t<_Sndr>;
-  return __dom_t::__apply(*this)(static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr));
+  return transform_sender(__dom_t{}, __sndr_t<_Fn, _Sndr>{{}, static_cast<_Fn&&>(__fn), static_cast<_Sndr&&>(__sndr)});
 }
 
 template <__disposition_t _Disposition>
diff --git a/cudax/include/cuda/experimental/__execution/transform_sender.cuh b/cudax/include/cuda/experimental/__execution/transform_sender.cuh
new file mode 100644
index 00000000000..3d57572c459
--- /dev/null
+++ b/cudax/include/cuda/experimental/__execution/transform_sender.cuh
@@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of CUDA Experimental in CUDA C++ Core Libraries,
+// under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CUDAX_EXECUTION_TRANSFORM_SENDER
+#define __CUDAX_EXECUTION_TRANSFORM_SENDER
+
+#include <cuda/std/detail/__config>
+
+#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
+#  pragma GCC system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
+#  pragma clang system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
+#  pragma system_header
+#endif // no system header
+
+#include <cuda/std/__type_traits/conditional.h>
+#include <cuda/std/__type_traits/is_valid_expansion.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/domain.cuh>
+#include <cuda/experimental/__execution/env.cuh>
+
+#include <cuda/experimental/__execution/prologue.cuh>
+
+namespace cuda::experimental::execution
+{
+struct _CCCL_TYPE_VISIBILITY_DEFAULT transform_sender_t
+{
+  template <class _Domain, class _Sndr, class... _Env>
+  using __transform_domain_t =
+    _CUDA_VSTD::_If<_CUDA_VSTD::_IsValidExpansion<__transform_sender_result_t, _Domain, _Sndr, _Env...>::value,
+                    _Domain,
+                    default_domain>;
+
+  enum class __strategy
+  {
+    __passthru,
+    __transform,
+    __transform_recurse
+  };
+
+  struct __transform_strategy_t
+  {
+    bool __nothrow_;
+    __strategy __strategy_;
+  };
+
+  template <class _Self, class _Domain, class _Sndr, class... _Env>
+  _CCCL_TRIVIAL_API static constexpr auto __get_transform_strategy() noexcept -> __transform_strategy_t
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    using __result_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom_t, _Sndr, _Env...>;
+
+    if constexpr (_CUDA_VSTD::_IsSame<__result_t&&, _Sndr&&>::value)
+    {
+      return __transform_strategy_t{true, __strategy::__passthru};
+    }
+    else
+    {
+      using __dom2_t _CCCL_NODEBUG_ALIAS = __transform_domain_t<domain_for_t<__result_t, _Env...>, __result_t, _Env...>;
+      using __result2_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom2_t, _Sndr, _Env...>;
+
+      if constexpr (_CUDA_VSTD::_IsSame<__result2_t&&, __result_t&&>::value)
+      {
+        constexpr bool __nothrow_ = noexcept(__dom_t{}.transform_sender(declval<_Sndr>(), declval<const _Env&>()...));
+        return __transform_strategy_t{__nothrow_, __strategy::__transform};
+      }
+      else
+      {
+        constexpr bool __nothrow_ = noexcept(
+          _Self{}(__dom2_t{},
+                  __dom_t{}.transform_sender(declval<_Sndr>(), declval<const _Env&>()...),
+                  declval<const _Env&>()...));
+        return __transform_strategy_t{__nothrow_, __strategy::__transform_recurse};
+      }
+    }
+  }
+
+  _CCCL_TEMPLATE(class _Self = transform_sender_t, class _Domain, class _Sndr, class... _Env)
+  _CCCL_REQUIRES((__get_transform_strategy<_Self, _Domain, _Sndr, _Env...>().__strategy_ == __strategy::__passthru))
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Domain, _Sndr&& __sndr, const _Env&...) const noexcept -> _Sndr&&
+  {
+    return static_cast<_Sndr&&>(__sndr);
+  }
+
+  _CCCL_TEMPLATE(class _Self = transform_sender_t, class _Domain, class _Sndr, class... _Env)
+  _CCCL_REQUIRES((__get_transform_strategy<_Self, _Domain, _Sndr, _Env...>().__strategy_ == __strategy::__transform))
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Domain, _Sndr&& __sndr, const _Env&... __env) const
+    noexcept(__get_transform_strategy<_Self, _Domain, _Sndr, _Env...>().__nothrow_) -> decltype(auto)
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    return __dom_t{}.transform_sender(static_cast<_Sndr&&>(__sndr), __env...);
+  }
+
+  _CCCL_TEMPLATE(class _Self = transform_sender_t, class _Domain, class _Sndr, class... _Env)
+  _CCCL_REQUIRES((__get_transform_strategy<_Self, _Domain, _Sndr, _Env...>().__strategy_
+                  == __strategy::__transform_recurse))
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Domain, _Sndr&& __sndr, const _Env&... __env) const
+    noexcept(__get_transform_strategy<_Self, _Domain, _Sndr, _Env...>().__nothrow_) -> decltype(auto)
+  {
+    using __dom1_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    using __result1_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom1_t, _Sndr, _Env...>;
+    using __dom2_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<domain_for_t<__result1_t>, __result1_t, _Env...>;
+    return (*this)(__dom2_t{}, __dom1_t{}.transform_sender(static_cast<_Sndr&&>(__sndr), __env...), __env...);
+  }
+};
+
+_CCCL_GLOBAL_CONSTANT transform_sender_t transform_sender{};
+
+template <class _Sndr, class... _Env>
+_CCCL_CONCEPT __has_sender_transform =
+  transform_sender_t::__get_transform_strategy<transform_sender_t, domain_for_t<_Sndr, _Env...>, _Sndr, _Env...>()
+    .__strategy_
+  != transform_sender_t::__strategy::__passthru;
+
+} // namespace cuda::experimental::execution
+
+#include <cuda/experimental/__execution/epilogue.cuh>
+
+#endif // __CUDAX_EXECUTION_TRANSFORM_SENDER
diff --git a/cudax/include/cuda/experimental/__execution/visit.cuh b/cudax/include/cuda/experimental/__execution/visit.cuh
index 7ffaee57fc9..180d3c6aa55 100644
--- a/cudax/include/cuda/experimental/__execution/visit.cuh
+++ b/cudax/include/cuda/experimental/__execution/visit.cuh
@@ -27,32 +27,66 @@
 
 #include <cuda/experimental/__execution/prologue.cuh>
 
+#define _CCCL_BIND_CHILD(_Ord) , _CCCL_PP_CAT(__child, _Ord)
+#define _CCCL_FWD_CHILD(_Ord)  , _CCCL_FWD_LIKE(_Sndr, _CCCL_PP_CAT(__child, _Ord))
+#define _CCCL_FWD_LIKE(_X, _Y) static_cast<_CUDA_VSTD::__copy_cvref_t<_X&&, decltype(_Y)>>(_Y)
+
 namespace cuda::experimental::execution
 {
+#if _CCCL_HAS_BUILTIN(__builtin_structured_binding_size)
+
+template <class _Sndr>
+inline constexpr size_t structured_binding_size = __builtin_structured_binding_size(_Sndr);
+
+#else // ^^^ _CCCL_HAS_BUILTIN(__builtin_structured_binding_size) ^^^ /
+      // vvv !_CCCL_HAS_BUILTIN(__builtin_structured_binding_size) vvv
 
 // Specialize this for each sender type that can be used to initialize a structured binding.
 template <class _Sndr>
 inline constexpr size_t structured_binding_size = static_cast<size_t>(-1);
 
+#endif // _CCCL_HAS_BUILTIN(__builtin_structured_binding_size)
+
+template <class _Sndr>
+inline constexpr size_t structured_binding_size<_Sndr&> = structured_binding_size<_Sndr>;
+
+template <class _Sndr>
+inline constexpr size_t structured_binding_size<_Sndr const&> = structured_binding_size<_Sndr>;
+
+// If structured bindings can be used to introduce a pack, then `visit` has a very simple
+// implementation. Otherwise, we need an `__unpack` function template specialized for
+#if __cpp_structured_bindings >= 202411L
+
+// C++26, structured binding can introduce a pack.
+struct _CCCL_TYPE_VISIBILITY_DEFAULT visit_t
+{
+  template <class _Visitor, class _CvSndr, class _Context>
+    requires(static_cast<int>(structured_binding_size<_CvSndr>) >= 2)
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Visitor& __visitor, _CvSndr&& __sndr, _Context& __context) const
+    -> decltype(auto)
+  {
+    auto&& [__tag, __data, ... __children] = static_cast<_CvSndr&&>(__sndr);
+    return __visitor(__context, __tag, _CCCL_FWD_LIKE(_CvSndr, __data), _CCCL_FWD_LIKE(_CvSndr, __children)...);
+  }
+};
+
+#else // ^^^ __cpp_structured_bindings >= 202411L / !__cpp_structured_bindings >= 202411L vvv
+
 template <size_t _Arity>
 struct __sender_type_cannot_be_used_to_initialize_a_structured_binding;
 
 template <size_t _Arity>
 extern __sender_type_cannot_be_used_to_initialize_a_structured_binding<_Arity> __unpack;
 
-#define _CCCL_BIND_CHILD(_Ord) , _CCCL_PP_CAT(__child, _Ord)
-#define _CCCL_FWD_CHILD(_Ord)  , _CCCL_FWD_LIKE(_Sndr, _CCCL_PP_CAT(__child, _Ord))
-#define _CCCL_FWD_LIKE(_X, _Y) static_cast<_CUDA_VSTD::__copy_cvref_t<_X&&, decltype(_Y)>>(_Y)
-
-#define _CCCL_UNPACK_SENDER(_Arity)                                                                             \
-  template <>                                                                                                   \
-  [[maybe_unused]]                                                                                              \
-  _CCCL_GLOBAL_CONSTANT auto __unpack<2 + _Arity> =                                                             \
-    [](auto& __visitor, auto&& __sndr, auto& __context) -> decltype(auto) {                                     \
-    using _Sndr _CCCL_NODEBUG_ALIAS                                  = decltype(__sndr);                        \
-    auto&& [__tag, __data _CCCL_PP_REPEAT(_Arity, _CCCL_BIND_CHILD)] = static_cast<_Sndr&&>(__sndr);            \
-    return __visitor(__context, __tag, _CCCL_FWD_LIKE(_Sndr, __data) _CCCL_PP_REPEAT(_Arity, _CCCL_FWD_CHILD)); \
-  }
+#  define _CCCL_UNPACK_SENDER(_Arity)                                                                             \
+    template <>                                                                                                   \
+    [[maybe_unused]]                                                                                              \
+    _CCCL_GLOBAL_CONSTANT auto __unpack<2 + _Arity> =                                                             \
+      [](auto& __visitor, auto&& __sndr, auto& __context) -> decltype(auto) {                                     \
+      using _Sndr _CCCL_NODEBUG_ALIAS                                  = decltype(__sndr);                        \
+      auto&& [__tag, __data _CCCL_PP_REPEAT(_Arity, _CCCL_BIND_CHILD)] = static_cast<_Sndr&&>(__sndr);            \
+      return __visitor(__context, __tag, _CCCL_FWD_LIKE(_Sndr, __data) _CCCL_PP_REPEAT(_Arity, _CCCL_FWD_CHILD)); \
+    }
 
 _CCCL_UNPACK_SENDER(0);
 _CCCL_UNPACK_SENDER(1);
@@ -63,18 +97,35 @@ _CCCL_UNPACK_SENDER(5);
 _CCCL_UNPACK_SENDER(6);
 _CCCL_UNPACK_SENDER(7);
 
-#undef _CCCL_FWD_LIKE
-#undef _CCCL_FWD_CHILD
-#undef _CCCL_BIND_CHILD
+struct _CCCL_TYPE_VISIBILITY_DEFAULT visit_t
+{
+  _CCCL_TEMPLATE(class _Visitor, class _Sndr, class _Context)
+  _CCCL_REQUIRES((static_cast<int>(structured_binding_size<_Sndr>) >= 2))
+  _CCCL_TRIVIAL_API constexpr auto operator()(_Visitor& __visitor, _Sndr&& __sndr, _Context& __context) const
+    -> decltype(auto)
+  {
+    // This `if constexpr` shouldn't be needed given the `requires` clause above. It is
+    // here because nvcc 12.0 have a bug where the full signature of the function template
+    // -- including the return type -- is instantiated before the `requires` clause is
+    // checked.
+    if constexpr (static_cast<int>(structured_binding_size<_Sndr>) >= 2)
+    {
+      return __unpack<structured_binding_size<_Sndr>>(__visitor, static_cast<_Sndr&&>(__sndr), __context);
+    }
+  }
+};
+
+#endif // ^^^ __cpp_structured_bindings < 202411L
 
 [[maybe_unused]]
-_CCCL_GLOBAL_CONSTANT auto visit = [](auto& __visitor, auto&& sndr, auto& __context) -> decltype(auto) {
-  using _Sndr _CCCL_NODEBUG_ALIAS = __decay_t<decltype(sndr)>;
-  return __unpack<structured_binding_size<_Sndr>>(__visitor, static_cast<decltype(sndr)&&>(sndr), __context);
-};
+_CCCL_GLOBAL_CONSTANT visit_t visit{};
 
 } // namespace cuda::experimental::execution
 
+#undef _CCCL_FWD_LIKE
+#undef _CCCL_FWD_CHILD
+#undef _CCCL_BIND_CHILD
+
 #include <cuda/experimental/__execution/epilogue.cuh>
 
 #endif // __CUDAX_ASYNC_DETAIL_VISIT
diff --git a/cudax/include/cuda/experimental/__execution/when_all.cuh b/cudax/include/cuda/experimental/__execution/when_all.cuh
index 85c25943135..fc182582d2d 100644
--- a/cudax/include/cuda/experimental/__execution/when_all.cuh
+++ b/cudax/include/cuda/experimental/__execution/when_all.cuh
@@ -42,6 +42,7 @@
 #include <cuda/experimental/__execution/meta.cuh>
 #include <cuda/experimental/__execution/queries.cuh>
 #include <cuda/experimental/__execution/stop_token.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/type_traits.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/variant.cuh>
@@ -380,18 +381,7 @@ private:
   template <class... _Ts>
   using __decay_all _CCCL_NODEBUG_ALIAS = _CUDA_VSTD::__type_list<_CUDA_VSTD::decay_t<_Ts>...>;
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class... _Sndrs>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Sndrs... __sndrs) const;
-  };
-
 public:
-  _CCCL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class... _Sndrs>
   _CCCL_TRIVIAL_API constexpr auto operator()(_Sndrs... __sndrs) const;
 };
@@ -494,19 +484,6 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT when_all_t::__sndr_t : _CUDA_VSTD::__tuple<
   }
 };
 
-template <class... _Sndrs>
-_CCCL_TRIVIAL_API constexpr auto when_all_t::__fn::operator()(_Sndrs... __sndrs) const
-{
-  // If the incoming senders are non-dependent, we can check the completion
-  // signatures of the composed sender immediately.
-  if constexpr (((!dependent_sender<_Sndrs>) && ...))
-  {
-    using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<_Sndrs...>>;
-    static_assert(__valid_completion_signatures<__completions>);
-  }
-  return __sndr_t<_Sndrs...>{{{}, {}, static_cast<_Sndrs&&>(__sndrs)...}};
-}
-
 template <class... _Sndrs>
 _CCCL_TRIVIAL_API constexpr auto when_all_t::operator()(_Sndrs... __sndrs) const
 {
@@ -514,15 +491,22 @@ _CCCL_TRIVIAL_API constexpr auto when_all_t::operator()(_Sndrs... __sndrs) const
   {
     return __sndr_t{};
   }
-  else if constexpr (!__type_valid_v<_CUDA_VSTD::common_type_t, early_domain_of_t<_Sndrs>...>)
+  else if constexpr (!__type_valid_v<_CUDA_VSTD::common_type_t, domain_for_t<_Sndrs>...>)
   {
-    static_assert(__type_valid_v<_CUDA_VSTD::common_type_t, early_domain_of_t<_Sndrs>...>,
+    static_assert(__type_valid_v<_CUDA_VSTD::common_type_t, domain_for_t<_Sndrs>...>,
                   "when_all: all child senders must have the same domain");
   }
   else
   {
-    using __dom_t _CCCL_NODEBUG_ALIAS = _CUDA_VSTD::common_type_t<early_domain_of_t<_Sndrs>...>;
-    return __dom_t::__apply(*this)(static_cast<_Sndrs&&>(__sndrs)...);
+    using __dom_t _CCCL_NODEBUG_ALIAS = _CUDA_VSTD::common_type_t<domain_for_t<_Sndrs>...>;
+    // If the incoming senders are non-dependent, we can check the completion
+    // signatures of the composed sender immediately.
+    if constexpr (((!dependent_sender<_Sndrs>) && ...))
+    {
+      using __completions _CCCL_NODEBUG_ALIAS = completion_signatures_of_t<__sndr_t<_Sndrs...>>;
+      static_assert(__valid_completion_signatures<__completions>);
+    }
+    return transform_sender(__dom_t{}, __sndr_t<_Sndrs...>{{{}, {}, static_cast<_Sndrs&&>(__sndrs)...}});
   }
 }
 
diff --git a/cudax/include/cuda/experimental/__execution/write_env.cuh b/cudax/include/cuda/experimental/__execution/write_env.cuh
index 8cbe1f586b1..fdedfec5b3a 100644
--- a/cudax/include/cuda/experimental/__execution/write_env.cuh
+++ b/cudax/include/cuda/experimental/__execution/write_env.cuh
@@ -28,6 +28,7 @@
 #include <cuda/experimental/__execution/queries.cuh>
 #include <cuda/experimental/__execution/rcvr_ref.cuh>
 #include <cuda/experimental/__execution/rcvr_with_env.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/utility.cuh>
 #include <cuda/experimental/__execution/visit.cuh>
 
@@ -59,18 +60,7 @@ private:
     connect_result_t<_Sndr, __rcvr_ref<__rcvr_with_env_t<_Rcvr, _Env>>> __opstate_;
   };
 
-  struct _CCCL_TYPE_VISIBILITY_DEFAULT __fn
-  {
-    template <class _Env, class _Sndr>
-    _CCCL_TRIVIAL_API constexpr auto operator()(_Env __env, _Sndr __sndr) const;
-  };
-
 public:
-  _CCCL_TRIVIAL_API static constexpr auto __apply() noexcept
-  {
-    return __fn{};
-  }
-
   template <class _Sndr, class _Env>
   struct _CCCL_TYPE_VISIBILITY_DEFAULT __sndr_t;
 
@@ -115,17 +105,12 @@ struct _CCCL_TYPE_VISIBILITY_DEFAULT write_env_t::__sndr_t
   _Sndr __sndr_;
 };
 
-template <class _Env, class _Sndr>
-_CCCL_TRIVIAL_API constexpr auto write_env_t::__fn::operator()(_Env __env, _Sndr __sndr) const
-{
-  return __sndr_t<_Sndr, _Env>{{}, static_cast<_Env&&>(__env), static_cast<_Sndr&&>(__sndr)};
-}
-
 template <class _Sndr, class _Env>
 _CCCL_TRIVIAL_API constexpr auto write_env_t::operator()(_Sndr __sndr, _Env __env) const
 {
-  using __dom_t _CCCL_NODEBUG_ALIAS = __domain_of_t<_Env>;
-  return __dom_t::__apply(*this)(static_cast<_Env&&>(__env), static_cast<_Sndr&&>(__sndr));
+  using __dom_t _CCCL_NODEBUG_ALIAS  = __domain_of_t<_Env>;
+  using __sndr_t _CCCL_NODEBUG_ALIAS = write_env_t::__sndr_t<_Sndr, _Env>;
+  return transform_sender(__dom_t{}, __sndr_t{{}, static_cast<_Env&&>(__env), static_cast<_Sndr&&>(__sndr)});
 }
 
 template <class _Sndr, class _Env>
diff --git a/cudax/include/cuda/experimental/execution.cuh b/cudax/include/cuda/experimental/execution.cuh
index 846bb700765..f048f50a17d 100644
--- a/cudax/include/cuda/experimental/execution.cuh
+++ b/cudax/include/cuda/experimental/execution.cuh
@@ -12,6 +12,7 @@
 #define __CUDAX_EXECUTION__
 
 // IWYU pragma: begin_exports
+#include <cuda/experimental/__execution/apply_sender.cuh>
 #include <cuda/experimental/__execution/conditional.cuh>
 #include <cuda/experimental/__execution/continues_on.cuh>
 #include <cuda/experimental/__execution/cpos.cuh>
@@ -31,6 +32,7 @@
 #include <cuda/experimental/__execution/sync_wait.cuh>
 #include <cuda/experimental/__execution/then.cuh>
 #include <cuda/experimental/__execution/thread_context.cuh>
+#include <cuda/experimental/__execution/transform_sender.cuh>
 #include <cuda/experimental/__execution/visit.cuh>
 #include <cuda/experimental/__execution/when_all.cuh>
 #include <cuda/experimental/__execution/write_env.cuh>
diff --git a/cudax/test/execution/common/error_scheduler.cuh b/cudax/test/execution/common/error_scheduler.cuh
index 6c0a8810da9..73326edaa14 100755
--- a/cudax/test/execution/common/error_scheduler.cuh
+++ b/cudax/test/execution/common/error_scheduler.cuh
@@ -91,6 +91,8 @@ private:
 public:
   using scheduler_concept = cudax_async::scheduler_t;
 
+  _CCCL_HIDE_FROM_ABI error_scheduler() = default;
+
   _CCCL_HOST_DEVICE explicit error_scheduler(Error err)
       : _err(static_cast<Error&&>(err))
   {}


Reviews:
user: login: miscco
body: I love this. Its makes a ton of code easier*

 * "easier"
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T06:08:41Z
user: login: miscco
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T06:08:53Z
user: login: ericniebler
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T06:33:35Z
user: login: miscco
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-08T08:00:08Z

Review comments:
diff_hunk: @@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of CUDA Experimental in CUDA C++ Core Libraries,
+// under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CUDAX_EXECUTION_TRANSFORM_SENDER
+#define __CUDAX_EXECUTION_TRANSFORM_SENDER
+
+#include <cuda/std/detail/__config>
+
+#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
+#  pragma GCC system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
+#  pragma clang system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
+#  pragma system_header
+#endif // no system header
+
+#include <cuda/std/__type_traits/conditional.h>
+#include <cuda/std/__type_traits/is_valid_expansion.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/domain.cuh>
+#include <cuda/experimental/__execution/env.cuh>
+
+#include <cuda/experimental/__execution/prologue.cuh>
+
+namespace cuda::experimental::execution
+{
+struct _CCCL_TYPE_VISIBILITY_DEFAULT transform_sender_t
+{
+  template <class _Domain, class _Sndr, class... _Env>
+  using __transform_domain_t =
+    _CUDA_VSTD::_If<_CUDA_VSTD::_IsValidExpansion<__transform_sender_result_t, _Domain, _Sndr, _Env...>::value,
+                    _Domain,
+                    default_domain>;
+
+  enum class __strategy
+  {
+    __passthru,
+    __transform,
+    __transform_recurse
+  };
+
+  struct __transform_strategy_t
+  {
+    bool __nothrow_;
+    __strategy __strategy_;
+  };
+
+  template <class _Self, class _Domain, class _Sndr, class... _Env>
+  _CCCL_TRIVIAL_API static constexpr auto __get_transform_strategy() noexcept -> __transform_strategy_t
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    using __result_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom_t, _Sndr, _Env...>;
+
+    if constexpr (_CUDA_VSTD::_IsSame<__result_t&&, _Sndr&&>::value)
path: cudax/include/cuda/experimental/__execution/transform_sender.cuh
user: login: miscco
body: Are the && here necessary?
created_at: 2025-05-08T06:06:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of CUDA Experimental in CUDA C++ Core Libraries,
+// under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CUDAX_EXECUTION_TRANSFORM_SENDER
+#define __CUDAX_EXECUTION_TRANSFORM_SENDER
+
+#include <cuda/std/detail/__config>
+
+#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
+#  pragma GCC system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
+#  pragma clang system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
+#  pragma system_header
+#endif // no system header
+
+#include <cuda/std/__type_traits/conditional.h>
+#include <cuda/std/__type_traits/is_valid_expansion.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/domain.cuh>
+#include <cuda/experimental/__execution/env.cuh>
+
+#include <cuda/experimental/__execution/prologue.cuh>
+
+namespace cuda::experimental::execution
+{
+struct _CCCL_TYPE_VISIBILITY_DEFAULT transform_sender_t
+{
+  template <class _Domain, class _Sndr, class... _Env>
+  using __transform_domain_t =
+    _CUDA_VSTD::_If<_CUDA_VSTD::_IsValidExpansion<__transform_sender_result_t, _Domain, _Sndr, _Env...>::value,
+                    _Domain,
+                    default_domain>;
+
+  enum class __strategy
+  {
+    __passthru,
+    __transform,
+    __transform_recurse
+  };
+
+  struct __transform_strategy_t
+  {
+    bool __nothrow_;
+    __strategy __strategy_;
+  };
+
+  template <class _Self, class _Domain, class _Sndr, class... _Env>
+  _CCCL_TRIVIAL_API static constexpr auto __get_transform_strategy() noexcept -> __transform_strategy_t
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    using __result_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom_t, _Sndr, _Env...>;
+
+    if constexpr (_CUDA_VSTD::_IsSame<__result_t&&, _Sndr&&>::value)
path: cudax/include/cuda/experimental/__execution/transform_sender.cuh
user: login: ericniebler
body: I want them to compare equal if one is a T and the other is a T&&
created_at: 2025-05-08T06:33:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,128 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of CUDA Experimental in CUDA C++ Core Libraries,
+// under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __CUDAX_EXECUTION_TRANSFORM_SENDER
+#define __CUDAX_EXECUTION_TRANSFORM_SENDER
+
+#include <cuda/std/detail/__config>
+
+#if defined(_CCCL_IMPLICIT_SYSTEM_HEADER_GCC)
+#  pragma GCC system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_CLANG)
+#  pragma clang system_header
+#elif defined(_CCCL_IMPLICIT_SYSTEM_HEADER_MSVC)
+#  pragma system_header
+#endif // no system header
+
+#include <cuda/std/__type_traits/conditional.h>
+#include <cuda/std/__type_traits/is_valid_expansion.h>
+
+#include <cuda/experimental/__detail/utility.cuh>
+#include <cuda/experimental/__execution/domain.cuh>
+#include <cuda/experimental/__execution/env.cuh>
+
+#include <cuda/experimental/__execution/prologue.cuh>
+
+namespace cuda::experimental::execution
+{
+struct _CCCL_TYPE_VISIBILITY_DEFAULT transform_sender_t
+{
+  template <class _Domain, class _Sndr, class... _Env>
+  using __transform_domain_t =
+    _CUDA_VSTD::_If<_CUDA_VSTD::_IsValidExpansion<__transform_sender_result_t, _Domain, _Sndr, _Env...>::value,
+                    _Domain,
+                    default_domain>;
+
+  enum class __strategy
+  {
+    __passthru,
+    __transform,
+    __transform_recurse
+  };
+
+  struct __transform_strategy_t
+  {
+    bool __nothrow_;
+    __strategy __strategy_;
+  };
+
+  template <class _Self, class _Domain, class _Sndr, class... _Env>
+  _CCCL_TRIVIAL_API static constexpr auto __get_transform_strategy() noexcept -> __transform_strategy_t
+  {
+    using __dom_t _CCCL_NODEBUG_ALIAS    = __transform_domain_t<_Domain, _Sndr, _Env...>;
+    using __result_t _CCCL_NODEBUG_ALIAS = __transform_sender_result_t<__dom_t, _Sndr, _Env...>;
+
+    if constexpr (_CUDA_VSTD::_IsSame<__result_t&&, _Sndr&&>::value)
path: cudax/include/cuda/experimental/__execution/transform_sender.cuh
user: login: miscco
body: So is it explicitly the `T` and `T&&` because commonly we use `remove_reference_t` or `remove_cvref_t` for that
created_at: 2025-05-08T08:00:05Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-07T19:36:29Z
body: <details><summary>🟥 CI finished in 14m 10s: Pass:   0%/26  | Total:  1h 29m | Avg:  3m 25s | Max: 11m 42s</summary>

<ul>
<li>
<details><summary><h3>🟥 cudax: Pass:   0%/26  | Total:  1h 29m | Avg:  3m 25s | Max: 11m 42s</h3></summary>

```
🟥 cudacxx_family
  🟥 nvcc               Pass:   0%/26  | Total:  1h 29m | Avg:  3m 25s | Max: 11m 42s
🟥 cpu
  🟥 amd64              Pass:   0%/22  | Total:  1h 18m | Avg:  3m 34s | Max: 11m 42s
  🟥 arm64              Pass:   0%/4   | Total: 10m 24s | Avg:  2m 36s | Max:  2m 47s
🟥 ctk
  🟥 12.0               Pass:   0%/3   | Total: 15m 43s | Avg:  5m 14s | Max: 10m 29s
  🟥 12.8               Pass:   0%/23  | Total:  1h 13m | Avg:  3m 11s | Max: 11m 42s
🟥 cudacxx
  🟥 nvcc12.0           Pass:   0%/3   | Total: 15m 43s | Avg:  5m 14s | Max: 10m 29s
  🟥 nvcc12.8           Pass:   0%/23  | Total:  1h 13m | Avg:  3m 11s | Max: 11m 42s
🟥 cxx
  🟥 Clang14            Pass:   0%/2   | Total:  5m 24s | Avg:  2m 42s | Max:  2m 48s
  🟥 Clang15            Pass:   0%/1   | Total:  2m 45s | Avg:  2m 45s | Max:  2m 45s
  🟥 Clang16            Pass:   0%/1   | Total:  3m 03s | Avg:  3m 03s | Max:  3m 03s
  🟥 Clang17            Pass:   0%/1   | Total:  2m 53s | Avg:  2m 53s | Max:  2m 53s
  🟥 Clang18            Pass:   0%/1   | Total:  3m 01s | Avg:  3m 01s | Max:  3m 01s
  🟥 Clang19            Pass:   0%/4   | Total:  8m 14s | Avg:  2m 03s | Max:  3m 03s
  🟥 GCC10              Pass:   0%/2   | Total:  5m 17s | Avg:  2m 38s | Max:  2m 39s
  🟥 GCC11              Pass:   0%/1   | Total:  2m 51s | Avg:  2m 51s | Max:  2m 51s
  🟥 GCC12              Pass:   0%/1   | Total:  2m 51s | Avg:  2m 51s | Max:  2m 51s
  🟥 GCC13              Pass:   0%/8   | Total: 17m 22s | Avg:  2m 10s | Max:  3m 16s
  🟥 MSVC14.39          Pass:   0%/1   | Total: 10m 29s | Avg: 10m 29s | Max: 10m 29s
  🟥 MSVC14.42          Pass:   0%/1   | Total: 11m 42s | Avg: 11m 42s | Max: 11m 42s
  🟥 NVHPC25.3          Pass:   0%/2   | Total: 13m 18s | Avg:  6m 39s | Max:  7m 15s
🟥 cxx_family
  🟥 Clang              Pass:   0%/10  | Total: 25m 20s | Avg:  2m 32s | Max:  3m 03s
  🟥 GCC                Pass:   0%/12  | Total: 28m 21s | Avg:  2m 21s | Max:  3m 16s
  🟥 MSVC               Pass:   0%/2   | Total: 22m 11s | Avg: 11m 05s | Max: 11m 42s
  🟥 NVHPC              Pass:   0%/2   | Total: 13m 18s | Avg:  6m 39s | Max:  7m 15s
🟥 gpu
  🟥 h100               Pass:   0%/2   | Total:  3m 16s | Avg:  1m 38s | Max:  3m 16s
  🟥 rtx2080            Pass:   0%/24  | Total:  1h 25m | Avg:  3m 34s | Max: 11m 42s
🟥 jobs
  🟥 Build              Pass:   0%/23  | Total:  1h 29m | Avg:  3m 52s | Max: 11m 42s
  🟥 Test               Pass:   0%/3  
🟥 sm
  🟥 90                 Pass:   0%/3   | Total:  6m 15s | Avg:  2m 05s | Max:  3m 16s
  🟥 90a                Pass:   0%/1   | Total:  2m 51s | Avg:  2m 51s | Max:  2m 51s
🟥 std
  🟥 17                 Pass:   0%/4   | Total: 15m 47s | Avg:  3m 56s | Max:  7m 15s
  🟥 20                 Pass:   0%/22  | Total:  1h 13m | Avg:  3m 20s | Max: 11m 42s
```

</details>

</ul>

<details><summary><h3>👃 Inspect Changes</h3></summary>

### Modifications in project?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper

### Modifications in project or dependencies?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper
</details>


<details><summary><h2>🏃‍ Runner counts (total jobs: 26)</h2></summary>

|  #   | Runner
|------|------
|   17 | `linux-amd64-cpu16`
|    4 | `linux-arm64-cpu16`
|    2 | `windows-amd64-cpu16`
|    2 | `linux-amd64-gpu-rtx2080-latest-1`
|    1 | `linux-amd64-gpu-h100-latest-1`


</details>

</details>

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-07T20:50:21Z
body: <details><summary>🟨 CI finished in 13m 37s: Pass:  15%/26  | Total:  1h 38m | Avg:  3m 47s | Max: 11m 57s | Hits:  89%/2338</summary>

<ul>
<li>
<details><summary><h3>🟨 cudax: Pass:  15%/26  | Total:  1h 38m | Avg:  3m 47s | Max: 11m 57s | Hits:  89%/2338  </h3></summary>

```
🚨 std: 20 🚨
  🟩 17                 Pass: 100%/4   | Total: 21m 36s | Avg:  5m 24s | Max:  9m 25s | Hits:  89%/2338  
  🔥 20                 Pass:   0%/22  | Total:  1h 17m | Avg:  3m 30s | Max: 11m 57s
🟨 cudacxx_family
  🟨 nvcc               Pass:  15%/26  | Total:  1h 38m | Avg:  3m 47s | Max: 11m 57s | Hits:  89%/2338  
🟨 cpu
  🟨 amd64              Pass:   9%/22  | Total:  1h 24m | Avg:  3m 51s | Max: 11m 57s | Hits:  89%/1168  
  🟨 arm64              Pass:  50%/4   | Total: 13m 43s | Avg:  3m 25s | Max:  4m 21s | Hits:  90%/1170  
🟨 ctk
  🟥 12.0               Pass:   0%/3   | Total: 17m 20s | Avg:  5m 46s | Max: 11m 57s
  🟨 12.8               Pass:  17%/23  | Total:  1h 21m | Avg:  3m 32s | Max: 11m 13s | Hits:  89%/2338  
🟨 cudacxx
  🟥 nvcc12.0           Pass:   0%/3   | Total: 17m 20s | Avg:  5m 46s | Max: 11m 57s
  🟨 nvcc12.8           Pass:  17%/23  | Total:  1h 21m | Avg:  3m 32s | Max: 11m 13s | Hits:  89%/2338  
🟨 cxx
  🟥 Clang14            Pass:   0%/2   | Total:  5m 48s | Avg:  2m 54s | Max:  3m 07s
  🟥 Clang15            Pass:   0%/1   | Total:  3m 01s | Avg:  3m 01s | Max:  3m 01s
  🟥 Clang16            Pass:   0%/1   | Total:  3m 08s | Avg:  3m 08s | Max:  3m 08s
  🟥 Clang17            Pass:   0%/1   | Total:  3m 10s | Avg:  3m 10s | Max:  3m 10s
  🟥 Clang18            Pass:   0%/1   | Total:  3m 12s | Avg:  3m 12s | Max:  3m 12s
  🟨 Clang19            Pass:  25%/4   | Total:  9m 59s | Avg:  2m 29s | Max:  4m 07s | Hits:  90%/585   
  🟥 GCC10              Pass:   0%/2   | Total:  5m 42s | Avg:  2m 51s | Max:  3m 00s
  🟥 GCC11              Pass:   0%/1   | Total:  2m 49s | Avg:  2m 49s | Max:  2m 49s
  🟥 GCC12              Pass:   0%/1   | Total:  3m 02s | Avg:  3m 02s | Max:  3m 02s
  🟨 GCC13              Pass:  25%/8   | Total: 19m 30s | Avg:  2m 26s | Max:  4m 21s | Hits:  90%/1170  
  🟥 MSVC14.39          Pass:   0%/1   | Total: 11m 57s | Avg: 11m 57s | Max: 11m 57s
  🟥 MSVC14.42          Pass:   0%/1   | Total: 11m 13s | Avg: 11m 13s | Max: 11m 13s
  🟨 NVHPC25.3          Pass:  50%/2   | Total: 16m 08s | Avg:  8m 04s | Max:  9m 25s | Hits:  88%/583   
🟨 cxx_family
  🟨 Clang              Pass:  10%/10  | Total: 28m 18s | Avg:  2m 49s | Max:  4m 07s | Hits:  90%/585   
  🟨 GCC                Pass:  16%/12  | Total: 31m 03s | Avg:  2m 35s | Max:  4m 21s | Hits:  90%/1170  
  🟥 MSVC               Pass:   0%/2   | Total: 23m 10s | Avg: 11m 35s | Max: 11m 57s
  🟨 NVHPC              Pass:  50%/2   | Total: 16m 08s | Avg:  8m 04s | Max:  9m 25s | Hits:  88%/583   
🟨 gpu
  🟥 h100               Pass:   0%/2   | Total:  2m 52s | Avg:  1m 26s | Max:  2m 52s
  🟨 rtx2080            Pass:  16%/24  | Total:  1h 35m | Avg:  3m 59s | Max: 11m 57s | Hits:  89%/2338  
🟨 jobs
  🟨 Build              Pass:  17%/23  | Total:  1h 38m | Avg:  4m 17s | Max: 11m 57s | Hits:  89%/2338  
  🟥 Test               Pass:   0%/3  
🟨 sm
  🟨 90                 Pass:  33%/3   | Total:  6m 35s | Avg:  2m 11s | Max:  3m 43s | Hits:  90%/585   
  🟥 90a                Pass:   0%/1   | Total:  2m 44s | Avg:  2m 44s | Max:  2m 44s
```

</details>

</ul>

<details><summary><h3>👃 Inspect Changes</h3></summary>

### Modifications in project?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper

### Modifications in project or dependencies?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper
</details>


<details><summary><h2>🏃‍ Runner counts (total jobs: 26)</h2></summary>

|  #   | Runner
|------|------
|   17 | `linux-amd64-cpu16`
|    4 | `linux-arm64-cpu16`
|    2 | `windows-amd64-cpu16`
|    2 | `linux-amd64-gpu-rtx2080-latest-1`
|    1 | `linux-amd64-gpu-h100-latest-1`


</details>

</details>

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-07T21:43:47Z
body: <details><summary>🟨 CI finished in 17m 44s: Pass:  92%/26  | Total:  2h 29m | Avg:  5m 44s | Max: 11m 43s | Hits:  91%/14044</summary>

<ul>
<li>
<details><summary><h3>🟨 cudax: Pass:  92%/26  | Total:  2h 29m | Avg:  5m 44s | Max: 11m 43s | Hits:  91%/14044 </h3></summary>

```
🔍 cpu: amd64 🔍
  🔍 amd64              Pass:  90%/22  | Total:  2h 12m | Avg:  6m 00s | Max: 11m 43s | Hits:  91%/11704 
  🟩 arm64              Pass: 100%/4   | Total: 17m 04s | Avg:  4m 16s | Max:  4m 30s | Hits:  90%/2340  
🚨 cxx_family: MSVC 🚨
  🟩 Clang              Pass: 100%/10  | Total: 47m 04s | Avg:  4m 42s | Max:  7m 37s | Hits:  91%/5854  
  🟩 GCC                Pass: 100%/12  | Total:  1h 01m | Avg:  5m 08s | Max:  9m 04s | Hits:  91%/7024  
  🔥 MSVC               Pass:   0%/2   | Total: 22m 15s | Avg: 11m 07s | Max: 11m 43s
  🟩 NVHPC              Pass: 100%/2   | Total: 18m 24s | Avg:  9m 12s | Max:  9m 46s | Hits:  88%/1166  
🔍 gpu: rtx2080 🔍
  🟩 h100               Pass: 100%/2   | Total: 12m 14s | Avg:  6m 07s | Max:  8m 16s | Hits:  95%/1170  
  🔍 rtx2080            Pass:  91%/24  | Total:  2h 17m | Avg:  5m 42s | Max: 11m 43s | Hits:  91%/12874 
🔍 jobs: Build 🔍
  🔍 Build              Pass:  91%/23  | Total:  2h 04m | Avg:  5m 24s | Max: 11m 43s | Hits:  90%/12289 
  🟩 Test               Pass: 100%/3   | Total: 24m 57s | Avg:  8m 19s | Max:  9m 04s | Hits:  99%/1755  
🔍 std: 20 🔍
  🟩 17                 Pass: 100%/4   | Total: 22m 09s | Avg:  5m 32s | Max:  9m 46s | Hits:  89%/2338  
  🔍 20                 Pass:  90%/22  | Total:  2h 07m | Avg:  5m 46s | Max: 11m 43s | Hits:  91%/11706 
🟨 cxx
  🟩 Clang14            Pass: 100%/2   | Total:  8m 10s | Avg:  4m 05s | Max:  4m 17s | Hits:  90%/1174  
  🟩 Clang15            Pass: 100%/1   | Total:  4m 30s | Avg:  4m 30s | Max:  4m 30s | Hits:  90%/585   
  🟩 Clang16            Pass: 100%/1   | Total:  4m 34s | Avg:  4m 34s | Max:  4m 34s | Hits:  90%/585   
  🟩 Clang17            Pass: 100%/1   | Total:  4m 33s | Avg:  4m 33s | Max:  4m 33s | Hits:  90%/585   
  🟩 Clang18            Pass: 100%/1   | Total:  4m 48s | Avg:  4m 48s | Max:  4m 48s | Hits:  90%/585   
  🟩 Clang19            Pass: 100%/4   | Total: 20m 29s | Avg:  5m 07s | Max:  7m 37s | Hits:  93%/2340  
  🟩 GCC10              Pass: 100%/2   | Total:  8m 47s | Avg:  4m 23s | Max:  4m 30s | Hits:  90%/1174  
  🟩 GCC11              Pass: 100%/1   | Total:  4m 40s | Avg:  4m 40s | Max:  4m 40s | Hits:  90%/585   
  🟩 GCC12              Pass: 100%/1   | Total:  4m 53s | Avg:  4m 53s | Max:  4m 53s | Hits:  90%/585   
  🟩 GCC13              Pass: 100%/8   | Total: 43m 16s | Avg:  5m 24s | Max:  9m 04s | Hits:  92%/4680  
  🟥 MSVC14.39          Pass:   0%/1   | Total: 10m 32s | Avg: 10m 32s | Max: 10m 32s
  🟥 MSVC14.42          Pass:   0%/1   | Total: 11m 43s | Avg: 11m 43s | Max: 11m 43s
  🟩 NVHPC25.3          Pass: 100%/2   | Total: 18m 24s | Avg:  9m 12s | Max:  9m 46s | Hits:  88%/1166  
🟨 cudacxx_family
  🟨 nvcc               Pass:  92%/26  | Total:  2h 29m | Avg:  5m 44s | Max: 11m 43s | Hits:  91%/14044 
🟨 ctk
  🟨 12.0               Pass:  66%/3   | Total: 18m 42s | Avg:  6m 14s | Max: 10m 32s | Hits:  90%/1174  
  🟨 12.8               Pass:  95%/23  | Total:  2h 10m | Avg:  5m 40s | Max: 11m 43s | Hits:  91%/12870 
🟨 cudacxx
  🟨 nvcc12.0           Pass:  66%/3   | Total: 18m 42s | Avg:  6m 14s | Max: 10m 32s | Hits:  90%/1174  
  🟨 nvcc12.8           Pass:  95%/23  | Total:  2h 10m | Avg:  5m 40s | Max: 11m 43s | Hits:  91%/12870 
🟩 sm
  🟩 90                 Pass: 100%/3   | Total: 16m 07s | Avg:  5m 22s | Max:  8m 16s | Hits:  93%/1755  
  🟩 90a                Pass: 100%/1   | Total:  3m 52s | Avg:  3m 52s | Max:  3m 52s | Hits:  90%/585   
```

</details>

</ul>

<details><summary><h3>👃 Inspect Changes</h3></summary>

### Modifications in project?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper

### Modifications in project or dependencies?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper
</details>


<details><summary><h2>🏃‍ Runner counts (total jobs: 26)</h2></summary>

|  #   | Runner
|------|------
|   17 | `linux-amd64-cpu16`
|    4 | `linux-arm64-cpu16`
|    2 | `windows-amd64-cpu16`
|    2 | `linux-amd64-gpu-rtx2080-latest-1`
|    1 | `linux-amd64-gpu-h100-latest-1`


</details>

</details>

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-07T23:09:16Z
body: <details><summary>🟨 CI finished in 27m 00s: Pass:  92%/26  | Total:  2h 23m | Avg:  5m 30s | Max: 10m 42s | Hits:  93%/14044</summary>

<ul>
<li>
<details><summary><h3>🟨 cudax: Pass:  92%/26  | Total:  2h 23m | Avg:  5m 30s | Max: 10m 42s | Hits:  93%/14044 </h3></summary>

```
🔍 cpu: amd64 🔍
  🔍 amd64              Pass:  90%/22  | Total:  2h 07m | Avg:  5m 48s | Max: 10m 42s | Hits:  93%/11704 
  🟩 arm64              Pass: 100%/4   | Total: 15m 42s | Avg:  3m 55s | Max:  4m 07s | Hits:  92%/2340  
🚨 cxx_family: MSVC 🚨
  🟩 Clang              Pass: 100%/10  | Total: 44m 42s | Avg:  4m 28s | Max:  7m 35s | Hits:  94%/5854  
  🟩 GCC                Pass: 100%/12  | Total: 58m 51s | Avg:  4m 54s | Max:  9m 53s | Hits:  93%/7024  
  🔥 MSVC               Pass:   0%/2   | Total: 20m 14s | Avg: 10m 07s | Max: 10m 42s
  🟩 NVHPC              Pass: 100%/2   | Total: 19m 37s | Avg:  9m 48s | Max:  9m 59s | Hits:  90%/1166  
🔍 gpu: rtx2080 🔍
  🟩 h100               Pass: 100%/2   | Total: 11m 34s | Avg:  5m 47s | Max:  7m 28s | Hits:  96%/1170  
  🔍 rtx2080            Pass:  91%/24  | Total:  2h 11m | Avg:  5m 29s | Max: 10m 42s | Hits:  93%/12874 
🔍 jobs: Build 🔍
  🔍 Build              Pass:  91%/23  | Total:  1h 58m | Avg:  5m 09s | Max: 10m 42s | Hits:  92%/12289 
  🟩 Test               Pass: 100%/3   | Total: 24m 56s | Avg:  8m 18s | Max:  9m 53s | Hits:  99%/1755  
🔍 std: 20 🔍
  🟩 17                 Pass: 100%/4   | Total: 20m 55s | Avg:  5m 13s | Max:  9m 38s | Hits:  92%/2338  
  🔍 20                 Pass:  90%/22  | Total:  2h 02m | Avg:  5m 34s | Max: 10m 42s | Hits:  93%/11706 
🟨 cxx
  🟩 Clang14            Pass: 100%/2   | Total:  7m 44s | Avg:  3m 52s | Max:  4m 04s | Hits:  93%/1174  
  🟩 Clang15            Pass: 100%/1   | Total:  4m 19s | Avg:  4m 19s | Max:  4m 19s | Hits:  93%/585   
  🟩 Clang16            Pass: 100%/1   | Total:  4m 20s | Avg:  4m 20s | Max:  4m 20s | Hits:  93%/585   
  🟩 Clang17            Pass: 100%/1   | Total:  4m 21s | Avg:  4m 21s | Max:  4m 21s | Hits:  93%/585   
  🟩 Clang18            Pass: 100%/1   | Total:  4m 16s | Avg:  4m 16s | Max:  4m 16s | Hits:  93%/585   
  🟩 Clang19            Pass: 100%/4   | Total: 19m 42s | Avg:  4m 55s | Max:  7m 35s | Hits:  95%/2340  
  🟩 GCC10              Pass: 100%/2   | Total:  8m 06s | Avg:  4m 03s | Max:  4m 21s | Hits:  92%/1174  
  🟩 GCC11              Pass: 100%/1   | Total:  4m 25s | Avg:  4m 25s | Max:  4m 25s | Hits:  92%/585   
  🟩 GCC12              Pass: 100%/1   | Total:  4m 44s | Avg:  4m 44s | Max:  4m 44s | Hits:  92%/585   
  🟩 GCC13              Pass: 100%/8   | Total: 41m 36s | Avg:  5m 12s | Max:  9m 53s | Hits:  94%/4680  
  🟥 MSVC14.39          Pass:   0%/1   | Total:  9m 32s | Avg:  9m 32s | Max:  9m 32s
  🟥 MSVC14.42          Pass:   0%/1   | Total: 10m 42s | Avg: 10m 42s | Max: 10m 42s
  🟩 NVHPC25.3          Pass: 100%/2   | Total: 19m 37s | Avg:  9m 48s | Max:  9m 59s | Hits:  90%/1166  
🟨 cudacxx_family
  🟨 nvcc               Pass:  92%/26  | Total:  2h 23m | Avg:  5m 30s | Max: 10m 42s | Hits:  93%/14044 
🟨 ctk
  🟨 12.0               Pass:  66%/3   | Total: 16m 57s | Avg:  5m 39s | Max:  9m 32s | Hits:  93%/1174  
  🟨 12.8               Pass:  95%/23  | Total:  2h 06m | Avg:  5m 29s | Max: 10m 42s | Hits:  93%/12870 
🟨 cudacxx
  🟨 nvcc12.0           Pass:  66%/3   | Total: 16m 57s | Avg:  5m 39s | Max:  9m 32s | Hits:  93%/1174  
  🟨 nvcc12.8           Pass:  95%/23  | Total:  2h 06m | Avg:  5m 29s | Max: 10m 42s | Hits:  93%/12870 
🟩 sm
  🟩 90                 Pass: 100%/3   | Total: 15m 05s | Avg:  5m 01s | Max:  7m 28s | Hits:  95%/1755  
  🟩 90a                Pass: 100%/1   | Total:  3m 39s | Avg:  3m 39s | Max:  3m 39s | Hits:  92%/585   
```

</details>

</ul>

<details><summary><h3>👃 Inspect Changes</h3></summary>

### Modifications in project?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper

### Modifications in project or dependencies?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper
</details>


<details><summary><h2>🏃‍ Runner counts (total jobs: 26)</h2></summary>

|  #   | Runner
|------|------
|   17 | `linux-amd64-cpu16`
|    4 | `linux-arm64-cpu16`
|    2 | `windows-amd64-cpu16`
|    2 | `linux-amd64-gpu-rtx2080-latest-1`
|    1 | `linux-amd64-gpu-h100-latest-1`


</details>

</details>

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-08T00:33:16Z
body: <details><summary>🟩 CI finished in 51m 41s: Pass: 100%/26  | Total:  2h 27m | Avg:  5m 39s | Max: 12m 18s | Hits:  93%/14616</summary>

<ul>
<li>
<details><summary><h3>🟩 cudax: Pass: 100%/26  | Total:  2h 27m | Avg:  5m 39s | Max: 12m 18s | Hits:  93%/14616 </h3></summary>

```
🟩 cpu
  🟩 amd64              Pass: 100%/22  | Total:  2h 11m | Avg:  5m 59s | Max: 12m 18s | Hits:  93%/12276 
  🟩 arm64              Pass: 100%/4   | Total: 15m 36s | Avg:  3m 54s | Max:  4m 05s | Hits:  92%/2340  
🟩 ctk
  🟩 12.0               Pass: 100%/3   | Total: 19m 13s | Avg:  6m 24s | Max: 11m 37s | Hits:  90%/1460  
  🟩 12.8               Pass: 100%/23  | Total:  2h 08m | Avg:  5m 34s | Max: 12m 18s | Hits:  93%/13156 
🟩 cudacxx
  🟩 nvcc12.0           Pass: 100%/3   | Total: 19m 13s | Avg:  6m 24s | Max: 11m 37s | Hits:  90%/1460  
  🟩 nvcc12.8           Pass: 100%/23  | Total:  2h 08m | Avg:  5m 34s | Max: 12m 18s | Hits:  93%/13156 
🟩 cudacxx_family
  🟩 nvcc               Pass: 100%/26  | Total:  2h 27m | Avg:  5m 39s | Max: 12m 18s | Hits:  93%/14616 
🟩 cxx
  🟩 Clang14            Pass: 100%/2   | Total:  7m 52s | Avg:  3m 56s | Max:  4m 08s | Hits:  93%/1174  
  🟩 Clang15            Pass: 100%/1   | Total:  4m 20s | Avg:  4m 20s | Max:  4m 20s | Hits:  93%/585   
  🟩 Clang16            Pass: 100%/1   | Total:  4m 12s | Avg:  4m 12s | Max:  4m 12s | Hits:  93%/585   
  🟩 Clang17            Pass: 100%/1   | Total:  5m 11s | Avg:  5m 11s | Max:  5m 11s | Hits:  93%/585   
  🟩 Clang18            Pass: 100%/1   | Total:  4m 13s | Avg:  4m 13s | Max:  4m 13s | Hits:  93%/585   
  🟩 Clang19            Pass: 100%/4   | Total: 21m 12s | Avg:  5m 18s | Max:  9m 04s | Hits:  94%/2340  
  🟩 GCC10              Pass: 100%/2   | Total:  8m 14s | Avg:  4m 07s | Max:  4m 22s | Hits:  92%/1174  
  🟩 GCC11              Pass: 100%/1   | Total:  4m 27s | Avg:  4m 27s | Max:  4m 27s | Hits:  92%/585   
  🟩 GCC12              Pass: 100%/1   | Total:  4m 37s | Avg:  4m 37s | Max:  4m 37s | Hits:  92%/585   
  🟩 GCC13              Pass: 100%/8   | Total: 41m 27s | Avg:  5m 10s | Max:  9m 28s | Hits:  94%/4680  
  🟩 MSVC14.39          Pass: 100%/1   | Total: 11m 37s | Avg: 11m 37s | Max: 11m 37s | Hits:  81%/286   
  🟩 MSVC14.42          Pass: 100%/1   | Total: 12m 18s | Avg: 12m 18s | Max: 12m 18s | Hits:  81%/286   
  🟩 NVHPC25.3          Pass: 100%/2   | Total: 17m 36s | Avg:  8m 48s | Max:  9m 02s | Hits:  90%/1166  
🟩 cxx_family
  🟩 Clang              Pass: 100%/10  | Total: 47m 00s | Avg:  4m 42s | Max:  9m 04s | Hits:  93%/5854  
  🟩 GCC                Pass: 100%/12  | Total: 58m 45s | Avg:  4m 53s | Max:  9m 28s | Hits:  93%/7024  
  🟩 MSVC               Pass: 100%/2   | Total: 23m 55s | Avg: 11m 57s | Max: 12m 18s | Hits:  81%/572   
  🟩 NVHPC              Pass: 100%/2   | Total: 17m 36s | Avg:  8m 48s | Max:  9m 02s | Hits:  90%/1166  
🟩 gpu
  🟩 h100               Pass: 100%/2   | Total: 11m 48s | Avg:  5m 54s | Max:  8m 07s | Hits:  96%/1170  
  🟩 rtx2080            Pass: 100%/24  | Total:  2h 15m | Avg:  5m 38s | Max: 12m 18s | Hits:  92%/13446 
🟩 jobs
  🟩 Build              Pass: 100%/23  | Total:  2h 00m | Avg:  5m 14s | Max: 12m 18s | Hits:  92%/12861 
  🟩 Test               Pass: 100%/3   | Total: 26m 39s | Avg:  8m 53s | Max:  9m 28s | Hits:  99%/1755  
🟩 sm
  🟩 90                 Pass: 100%/3   | Total: 15m 25s | Avg:  5m 08s | Max:  8m 07s | Hits:  95%/1755  
  🟩 90a                Pass: 100%/1   | Total:  3m 36s | Avg:  3m 36s | Max:  3m 36s | Hits:  92%/585   
🟩 std
  🟩 17                 Pass: 100%/4   | Total: 20m 23s | Avg:  5m 05s | Max:  9m 02s | Hits:  92%/2338  
  🟩 20                 Pass: 100%/22  | Total:  2h 06m | Avg:  5m 46s | Max: 12m 18s | Hits:  93%/12278 
```

</details>

</ul>

<details><summary><h3>👃 Inspect Changes</h3></summary>

### Modifications in project?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper

### Modifications in project or dependencies?

|     | Project
|-----|---------
|     | CCCL Infrastructure
|     | libcu++
|     | CUB
|     | Thrust
| +/- | CUDA Experimental
|     | stdpar
|     | python
|     | CCCL C Parallel Library
|     | Catch2Helper
</details>


<details><summary><h2>🏃‍ Runner counts (total jobs: 26)</h2></summary>

|  #   | Runner
|------|------
|   17 | `linux-amd64-cpu16`
|    4 | `linux-arm64-cpu16`
|    2 | `windows-amd64-cpu16`
|    2 | `linux-amd64-gpu-rtx2080-latest-1`
|    1 | `linux-amd64-gpu-h100-latest-1`


</details>

</details>

author_association: CONTRIBUTOR