From cb9722836ad85a89254e54950db8fb01335799da Mon Sep 17 00:00:00 2001 From: Dan Hoeflinger Date: Thu, 23 Jul 2026 07:58:09 -0400 Subject: [PATCH 1/2] opssible implement with placement new (BREAKING CHANGE) Signed-off-by: Dan Hoeflinger --- include/oneapi/dpl/pstl/iterator_impl.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/include/oneapi/dpl/pstl/iterator_impl.h b/include/oneapi/dpl/pstl/iterator_impl.h index 6863e3c1380..929eec7c773 100644 --- a/include/oneapi/dpl/pstl/iterator_impl.h +++ b/include/oneapi/dpl/pstl/iterator_impl.h @@ -516,14 +516,14 @@ class transform_iterator { __my_it_ = __input.__my_it_; - // If copy assignment is available, copy the functor, otherwise skip it. - // For non-copy assignable functors, this copy assignment operator departs from the sycl 2020 specification - // requirement of device copyable types for copy assignment to be the same as a bitwise copy of the object. - // TODO: Explore (ABI breaking) change to use std::optional or similar and using copy constructor to implement - // copy assignment to better comply with SYCL 2020 specification. - if constexpr (std::is_copy_assignable_v<_UnaryFunc>) + // Implement functor copy assignment via destroy + copy-construct rather than _UnaryFunc::operator=. + // This supports copy assignment of functors which are not copy assignable (like c++17 lambdas). + // For a unary functor who's copy assignment operator differs from its copy constructor, the semantics of this + // copy assignment will follow that of its copy constructor. + if (this != std::addressof(__input)) { - __my_unary_func_ = __input.__my_unary_func_; + __my_unary_func_.~_UnaryFunc(); + ::new (std::addressof(__my_unary_func_)) _UnaryFunc(__input.__my_unary_func_); } return *this; } From 27562c0139f24d0a3eda7a213dfa6600b868f310 Mon Sep 17 00:00:00 2001 From: Dan Hoeflinger Date: Thu, 23 Jul 2026 08:31:28 -0400 Subject: [PATCH 2/2] adjusts tests to match new transform_iterator semantics Signed-off-by: Dan Hoeflinger --- .../iterator/transform_iterator_constructible.pass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp b/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp index 589b5b2fe20..215214a7f48 100644 --- a/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp +++ b/test/parallel_api/iterator/transform_iterator_constructible.pass.cpp @@ -101,11 +101,11 @@ test_copy_assignment() EXPECT_EQ(9, trans6[5], "transform_iterator returns the incorrect result"); - //should NOT copy __x state of functor (but still allows assignment of iterator) + //should still copy __x state of functor (despite not being copy-assignable) trans6 = trans5; //trans6 functor.__x remains the same, but iterator has been updated to be 100 elements later in the counting iter - EXPECT_EQ(109, trans6[5], "transform_iterator assignment with non-copy-assignable functor copies functor"); + EXPECT_EQ(108, trans6[5], "transform_iterator assignment with non-copy-assignable functor still copies functor"); } void