Skip to content

Commit 07ac818

Browse files
Support for implicit key
1 parent 46dae6e commit 07ac818

File tree

2 files changed

+100
-26
lines changed

2 files changed

+100
-26
lines changed

sycl/include/sycl/ext/oneapi/properties/new_properties.hpp

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,10 @@ struct property_base : property_key_tag<property_key_t> {
142142
}
143143
};
144144

145+
template <template <auto...> typename property> struct property_key;
146+
template <template <auto...> typename property>
147+
using property_key_t = typename property_key<property>::type;
148+
145149
template <typename... property_tys>
146150
inline constexpr bool property_names_are_unique = []() constexpr {
147151
if constexpr (sizeof...(property_tys) == 0) {
@@ -177,14 +181,23 @@ inline constexpr bool properties_are_sorted = []() constexpr {
177181
}
178182
}();
179183

180-
template <typename property_key_t>
181-
inline constexpr property_key_tag<property_key_t> key{};
184+
template <template <auto...> typename property>
185+
constexpr auto key() {
186+
return property_key_tag<property_key_t<property>>{};
187+
}
188+
template <typename property>
189+
constexpr auto key() {
190+
return property_key_tag<property>{};
191+
}
182192
} // namespace detail
183193

184194
// Empty property list.
185195
template <> class __SYCL_EBO properties<detail::properties_type_list<>, void> {
186196
public:
187197
template <typename> static constexpr bool has_property() { return false; }
198+
template <template <auto...> typename> static constexpr bool has_property() {
199+
return false;
200+
}
188201

189202
// TODO: How does this work without qualified name?
190203
template <typename other_property_t>
@@ -253,38 +266,54 @@ class __SYCL_EBO properties<
253266
constexpr properties(unsorted_property_tys... props)
254267
: unsorted_property_tys(props)... {}
255268

256-
template <typename property_key_t> static constexpr bool has_property() {
257-
return std::is_base_of_v<detail::property_key_tag<property_key_t>,
258-
properties>;
269+
template <template <auto...> typename property>
270+
static constexpr bool has_property() {
271+
return std::is_base_of_v<decltype(detail::key<property>()), properties>;
272+
}
273+
274+
template <typename property> static constexpr bool has_property() {
275+
return std::is_base_of_v<decltype(detail::key<property>()), properties>;
276+
}
277+
278+
// First, do return type SFINAE to choose between static/non-static. Second,
279+
// duplicate the code for non-templated properties (until we have "universal
280+
// template" in C++).
281+
template <template <auto...> typename property>
282+
static constexpr auto get_property() -> std::enable_if_t<
283+
std::is_empty_v<decltype(std::declval<properties>().get_property_impl(
284+
detail::key<property>()))>,
285+
decltype(std::declval<properties>().get_property_impl(
286+
detail::key<property>()))> {
287+
return decltype(std::declval<properties>().get_property_impl(
288+
detail::key<property>())){};
289+
}
290+
291+
template <template <auto...> typename property>
292+
constexpr auto get_property() const -> std::enable_if_t<
293+
!std::is_empty_v<decltype(std::declval<properties>().get_property_impl(
294+
detail::key<property>()))>,
295+
decltype(std::declval<properties>().get_property_impl(
296+
detail::key<property>()))> {
297+
return get_property_impl(detail::key<property>());
259298
}
260299

261-
// Two methods below do the following (pseudocode):
262-
//
263-
// template <property_key_t>
264-
// using ret_t = decltype(this->get_property_impl(key_tag<property_key_t>{}));
265-
// static constexpr auto get_property() requires(is_empty_v<ret_t>) {
266-
// return ret_t{};
267-
// }
268-
// constexpr auto get_property() const requires(!is_empty_v<ret_t>) {
269-
// return get_property_impl(key_tag<property_key_t>{});
270-
// }
271-
template <typename property_key_t>
300+
template <typename property>
272301
static constexpr auto get_property() -> std::enable_if_t<
273302
std::is_empty_v<decltype(std::declval<properties>().get_property_impl(
274-
detail::key<property_key_t>))>,
303+
detail::key<property>()))>,
275304
decltype(std::declval<properties>().get_property_impl(
276-
detail::key<property_key_t>))> {
305+
detail::key<property>()))> {
277306
return decltype(std::declval<properties>().get_property_impl(
278-
detail::key<property_key_t>)){};
307+
detail::key<property>())){};
279308
}
280309

281-
template <typename property_key_t>
310+
template <typename property>
282311
constexpr auto get_property() const -> std::enable_if_t<
283312
!std::is_empty_v<decltype(std::declval<properties>().get_property_impl(
284-
detail::key<property_key_t>))>,
313+
detail::key<property>()))>,
285314
decltype(std::declval<properties>().get_property_impl(
286-
detail::key<property_key_t>))> {
287-
return get_property_impl(detail::key<property_key_t>);
315+
detail::key<property>()))> {
316+
return get_property_impl(detail::key<property>());
288317
}
289318

290319
// TODO: Use more effective insert sort for single-property insertion.
@@ -322,6 +351,7 @@ properties(unsorted_property_tys...)
322351

323352
using empty_properties_t = decltype(properties{});
324353

354+
// FIXME:
325355
template <typename property_list_ty, typename... allowed_property_keys>
326356
struct all_properties_in : std::false_type {};
327357
template <typename... property_tys, typename... allowed_property_keys>

sycl/test/extensions/properties/new_properties.cpp

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ struct named_property_base
2222
};
2323

2424
namespace test_sorting {
25+
// Treat each instantiation as a separate property by not providing a common
26+
// key.
2527
template <int N> struct Property : named_property_base<Property<N>> {};
2628
static_assert(
2729
std::is_same_v<decltype(properties{Property<3>{}, Property<2>{}}),
@@ -33,7 +35,13 @@ struct property1 : named_property_base<property1> {};
3335

3436
template <int N>
3537
struct property2 : named_property_base<property2<N>, struct property2_key> {};
38+
} // namespace test
39+
40+
template <> struct detail::property_key<test::property2> {
41+
using type = test::property2_key;
42+
};
3643

44+
namespace test {
3745
struct property3 : named_property_base<property3> {
3846
property3(int x) : x(x) {}
3947
int x;
@@ -50,8 +58,8 @@ void test() {
5058
static_assert(pl1.has_property<property1>());
5159
static_assert(!pl2.has_property<property1>());
5260

53-
static_assert(pl1.has_property<property2_key>());
54-
static_assert(!pl2.has_property<property2_key>());
61+
static_assert(pl1.has_property<property2>());
62+
static_assert(!pl2.has_property<property2>());
5563

5664
static_assert(pl1.has_property<property3>());
5765
static_assert(pl2.has_property<property3>());
@@ -86,6 +94,14 @@ template <int N>
8694
struct ct_prop : named_property_base<ct_prop<N>, struct ct_prop_key> {
8795
static constexpr auto value() { return N; }
8896
};
97+
} // namespace test_compile_prop_in_runtime_list
98+
99+
template <>
100+
struct detail::property_key<test_compile_prop_in_runtime_list::ct_prop> {
101+
using type = test_compile_prop_in_runtime_list::ct_prop_key;
102+
};
103+
104+
namespace test_compile_prop_in_runtime_list {
89105
struct rt_prop : named_property_base<rt_prop> {
90106
rt_prop(int N) : x(N) {}
91107

@@ -96,7 +112,7 @@ struct rt_prop : named_property_base<rt_prop> {
96112
void test() {
97113
int x = 42;
98114
properties pl{ct_prop<42>{}, rt_prop{x}};
99-
constexpr auto p = pl.get_property<struct ct_prop_key>();
115+
constexpr auto p = pl.get_property<ct_prop>();
100116
static_assert(std::is_same_v<decltype(p), const ct_prop<42>>);
101117
static_assert(p.value() == 42);
102118
}
@@ -114,6 +130,7 @@ namespace test_static_get_property {
114130
}
115131
}
116132

133+
// TODO:
117134
namespace test_trait {
118135
struct prop : named_property_base<prop> {};
119136
struct prop2 : named_property_base<prop2> {};
@@ -162,6 +179,33 @@ static_assert(!has_value_v<decltype(pl1)>);
162179
static_assert(!has_value_v<decltype(pl2)>);
163180
}
164181

182+
namespace implicit_key {
183+
struct non_template_prop : named_property_base<non_template_prop> {};
184+
template <int N> struct prop : named_property_base<prop<N>, struct prop_key_t> {
185+
static constexpr int value = N;
186+
};
187+
} // namespace implicit_key
188+
189+
template <> struct detail::property_key<implicit_key::prop> {
190+
using type = implicit_key::prop_key_t;
191+
};
192+
193+
namespace implicit_key {
194+
constexpr properties pl1{non_template_prop{}};
195+
constexpr properties pl2{prop<42>{}};
196+
static_assert(pl1.has_property<non_template_prop>());
197+
static_assert(!pl1.has_property<prop>());
198+
static_assert(!pl2.has_property<non_template_prop>());
199+
static_assert(pl2.has_property<prop>());
200+
static_assert(!empty_properties_t::has_property<non_template_prop>());
201+
static_assert(!empty_properties_t::has_property<prop>());
202+
203+
constexpr auto p1 = pl1.get_property<non_template_prop>();
204+
static_assert(std::is_same_v<decltype(p1), const non_template_prop>);
205+
constexpr auto p2 = pl2.get_property<prop>();
206+
static_assert(std::is_same_v<decltype(p2), const prop<42>>);
207+
} // namespace implicit_key
208+
165209
int main() {
166210
test::test();
167211
bench::test(std::make_integer_sequence<int, 67>{});

0 commit comments

Comments
 (0)