@@ -21,8 +21,30 @@ namespace sycl {
2121inline namespace _V1 {
2222namespace ext ::oneapi::experimental {
2323
24+ template <typename properties_type_list_ty> class __SYCL_EBO properties;
25+
2426namespace detail {
2527
28+ // NOTE: Meta-function to implement CTAD rules isn't allowed to return
29+ // `properties<something>` and it's impossible to return a pack as well. As
30+ // such, we're forced to have an extra level of `detail::properties_type_list`
31+ // for the purpose of providing CTAD rules.
32+ template <typename ... property_tys> struct properties_type_list ;
33+
34+ // This is used in a separate `properties` specialization to report friendlier
35+ // errors.
36+ template <typename ... property_tys> struct invalid_properties_type_list {};
37+
38+ // Helper for reconstructing a properties type. This assumes that
39+ // PropertyValueTs is sorted and contains only valid properties.
40+ //
41+ // It also allows us to hide details of `properties` implementation from the
42+ // code that uses/defines them (with the exception of ESIMD which is extremely
43+ // hacky in its own esimd::properties piggybacking on these ones).
44+ template <typename ... PropertyValueTs>
45+ using properties_t =
46+ properties<detail::properties_type_list<PropertyValueTs...>>;
47+
2648template <typename ... property_tys>
2749inline constexpr bool properties_are_unique = []() constexpr {
2850 if constexpr (sizeof ...(property_tys) == 0 ) {
@@ -66,9 +88,6 @@ constexpr bool properties_are_valid_for_ctad = []() constexpr {
6688 }
6789}();
6890
69- template <typename ... property_tys> struct properties_type_list ;
70- template <typename ... property_tys> struct invalid_properties_type_list {};
71-
7291template <typename ... property_tys> struct properties_sorter {
7392 // Not using "auto" due to MSVC bug in v19.36 and older. v19.37 and later is
7493 // able to compile "auto" just fine. See https://godbolt.org/z/eW3rjjs7n.
@@ -118,8 +137,6 @@ template <> struct properties_sorter<> {
118137
119138} // namespace detail
120139
121- template <typename properties_type_list_ty> class __SYCL_EBO properties;
122-
123140// Empty property list.
124141template <> class __SYCL_EBO properties<detail::properties_type_list<>> {
125142 template <typename T>
@@ -183,10 +200,6 @@ class __SYCL_EBO
183200 }
184201};
185202
186- // NOTE: Meta-function to implement CTAD rules isn't allowed to return
187- // `properties<something>` and it's impossible to return a pack as well. As
188- // such, we're forced to have an extra level of `detail::properties_type_list`
189- // for the purpose of providing CTAD rules.
190203template <typename ... property_tys>
191204class __SYCL_EBO properties<detail::properties_type_list<property_tys...>>
192205 : private property_tys... {
@@ -287,11 +300,85 @@ using empty_properties_t = decltype(properties{});
287300
288301namespace detail {
289302
290- // Helper for reconstructing a properties type. This assumes that
291- // PropertyValueTs is sorted and contains only valid properties.
292- template <typename ... PropertyValueTs>
293- using properties_t =
294- properties<detail::properties_type_list<PropertyValueTs...>>;
303+ template <template <typename > typename predicate, typename ... property_tys>
304+ struct filter_properties_impl {
305+ static constexpr auto idx_info = []() constexpr {
306+ constexpr int N = sizeof ...(property_tys);
307+ std::array<int , N> indexes{};
308+ int num_matched = 0 ;
309+ int idx = 0 ;
310+ (((predicate<property_tys>::value ? indexes[num_matched++] = idx++ : idx++),
311+ ...));
312+
313+ return std::pair{indexes, num_matched};
314+ }();
315+
316+ // Helper to convert constexpr indices values to an std::index_sequence type.
317+ // Values -> type is the key here.
318+ template <int ... Idx>
319+ static constexpr auto idx_seq (std::integer_sequence<int , Idx...>) {
320+ return std::integer_sequence<int , idx_info.first [Idx]...>{};
321+ }
322+
323+ using selected_idx_seq =
324+ decltype (idx_seq(std::make_integer_sequence<int , idx_info.second>{}));
325+
326+ // Using prop_list_ty so that we don't need to explicitly spell out
327+ // `properties` template parameters' implementation-details.
328+ template <typename prop_list_ty, int ... Idxs>
329+ static constexpr auto apply_impl (const prop_list_ty &props,
330+ std::integer_sequence<int , Idxs...>) {
331+ return properties{props.template get_property <
332+ typename nth_type_t <Idxs, property_tys...>::key_t >()...};
333+ }
334+
335+ template <typename prop_list_ty>
336+ static constexpr auto apply (const prop_list_ty &props) {
337+ return apply_impl (props, selected_idx_seq{});
338+ }
339+ };
340+
341+ template <template <typename > typename predicate, typename ... property_tys>
342+ constexpr auto filter_properties (const properties_t <property_tys...> &props) {
343+ return filter_properties_impl<predicate, property_tys...>::apply (props);
344+ }
345+
346+ template <typename ... lhs_property_tys> struct merge_filter {
347+ template <typename rhs_property_ty>
348+ struct predicate
349+ : std::bool_constant<!((std::is_same_v<typename lhs_property_tys::key_t ,
350+ typename rhs_property_ty::key_t > ||
351+ ...))> {};
352+ };
353+
354+ template <typename ... lhs_property_tys, typename ... rhs_property_tys>
355+ constexpr auto merge_properties (const properties_t <lhs_property_tys...> &lhs,
356+ const properties_t <rhs_property_tys...> &rhs) {
357+ auto rhs_unique_props =
358+ filter_properties<merge_filter<lhs_property_tys...>::template predicate>(
359+ rhs);
360+ if constexpr (std::is_same_v<std::decay_t <decltype (rhs)>,
361+ std::decay_t <decltype (rhs_unique_props)>>) {
362+ // None of RHS properties share keys with LHS, no conflicts possible.
363+ return properties{
364+ lhs.template get_property <typename lhs_property_tys::key_t >()...,
365+ rhs.template get_property <typename rhs_property_tys::key_t >()...};
366+ } else {
367+ // Ensure no conflicts, then merge.
368+ constexpr auto has_conflict = [](auto *lhs_prop) constexpr {
369+ using lhs_property_ty = std::remove_pointer_t <decltype (lhs_prop)>;
370+ return (((std::is_same_v<typename lhs_property_ty::key_t ,
371+ typename rhs_property_tys::key_t > &&
372+ (!std::is_same_v<lhs_property_ty, rhs_property_tys> ||
373+ !std::is_empty_v<lhs_property_ty>)) ||
374+ ...));
375+ };
376+ static_assert (
377+ !((has_conflict (static_cast <lhs_property_tys *>(nullptr )) || ...)),
378+ " Failed to merge property lists due to conflicting properties." );
379+ return merge_properties (lhs, rhs_unique_props);
380+ }
381+ }
295382
296383template <typename LHSPropertiesT, typename RHSPropertiesT>
297384using merged_properties_t = decltype (merge_properties(
0 commit comments