@@ -21,8 +21,30 @@ namespace sycl {
21
21
inline namespace _V1 {
22
22
namespace ext ::oneapi::experimental {
23
23
24
+ template <typename properties_type_list_ty> class __SYCL_EBO properties;
25
+
24
26
namespace detail {
25
27
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
+
26
48
template <typename ... property_tys>
27
49
inline constexpr bool properties_are_unique = []() constexpr {
28
50
if constexpr (sizeof ...(property_tys) == 0 ) {
@@ -66,9 +88,6 @@ constexpr bool properties_are_valid_for_ctad = []() constexpr {
66
88
}
67
89
}();
68
90
69
- template <typename ... property_tys> struct properties_type_list ;
70
- template <typename ... property_tys> struct invalid_properties_type_list {};
71
-
72
91
template <typename ... property_tys> struct properties_sorter {
73
92
// Not using "auto" due to MSVC bug in v19.36 and older. v19.37 and later is
74
93
// able to compile "auto" just fine. See https://godbolt.org/z/eW3rjjs7n.
@@ -118,8 +137,6 @@ template <> struct properties_sorter<> {
118
137
119
138
} // namespace detail
120
139
121
- template <typename properties_type_list_ty> class __SYCL_EBO properties;
122
-
123
140
// Empty property list.
124
141
template <> class __SYCL_EBO properties<detail::properties_type_list<>> {
125
142
template <typename T>
@@ -183,10 +200,6 @@ class __SYCL_EBO
183
200
}
184
201
};
185
202
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.
190
203
template <typename ... property_tys>
191
204
class __SYCL_EBO properties<detail::properties_type_list<property_tys...>>
192
205
: private property_tys... {
@@ -287,11 +300,85 @@ using empty_properties_t = decltype(properties{});
287
300
288
301
namespace detail {
289
302
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
+ }
295
382
296
383
template <typename LHSPropertiesT, typename RHSPropertiesT>
297
384
using merged_properties_t = decltype (merge_properties(
0 commit comments