@@ -31,6 +31,10 @@ namespace sycl {
31
31
inline namespace _V1 {
32
32
namespace ext ::oneapi::experimental {
33
33
namespace new_properties {
34
+
35
+ template <typename properties_type_list_ty, typename = void >
36
+ class __SYCL_EBO properties;
37
+
34
38
namespace detail {
35
39
template <typename ... property_tys> struct properties_type_list ;
36
40
@@ -112,18 +116,22 @@ struct property_base : property_key_tag<property_key_t> {
112
116
return *static_cast <const property_t *>(this );
113
117
}
114
118
}
119
+
120
+ // For key_t access in error reporting specialization.
121
+ template <typename , typename >
122
+ friend class __SYCL_EBO new_properties::properties;
115
123
};
116
124
117
125
template <typename ... property_tys>
118
- inline constexpr bool property_keys_are_unique = []() constexpr {
126
+ inline constexpr bool property_names_are_unique = []() constexpr {
119
127
if constexpr (sizeof ...(property_tys) == 0 ) {
120
128
return true ;
121
129
} else {
122
- const std::array keys = {property_tys::property_name...};
123
- auto N = keys .size ();
130
+ const std::array names = {property_tys::property_name...};
131
+ auto N = names .size ();
124
132
for (int i = 0 ; i < N; ++i)
125
133
for (int j = i + 1 ; j < N; ++j)
126
- if (keys [i] == keys [j])
134
+ if (names [i] == names [j])
127
135
return false ;
128
136
129
137
return true ;
@@ -135,23 +143,21 @@ inline constexpr bool properties_are_sorted = []() constexpr {
135
143
if constexpr (sizeof ...(property_tys) == 0 ) {
136
144
return true ;
137
145
} else {
138
- const std::array sort_keys = {property_tys::property_name...};
146
+ const std::array sort_names = {property_tys::property_name...};
139
147
// std::is_sorted isn't constexpr until C++20.
140
148
//
141
- // Sorting is an implementation detail while uniqueness of the property_keys
142
- // is an API restriction. This internal check actually combines both
143
- // conditions as we expect that user error is handled before the internal
144
- // `properties_are_sorted` assert is checked.
145
- for (std::size_t idx = 1 ; idx < sort_keys .size (); ++idx)
146
- if (sort_keys [idx - 1 ] >= sort_keys [idx])
149
+ // Sorting is an implementation detail while uniqueness of the
150
+ // property_name's is an API restriction. This internal check actually
151
+ // combines both conditions as we expect that user error is handled before
152
+ // the internal `properties_are_sorted` assert is checked.
153
+ for (std::size_t idx = 1 ; idx < sort_names .size (); ++idx)
154
+ if (sort_names [idx - 1 ] >= sort_names [idx])
147
155
return false ;
148
156
return true ;
149
157
}
150
158
}();
151
159
} // namespace detail
152
160
153
- template <typename properties_type_list_ty, typename = void > class properties ;
154
-
155
161
template <typename T> struct is_property_list : std::false_type {};
156
162
template <typename PropListTy>
157
163
struct is_property_list <properties<PropListTy>> : std::true_type {};
@@ -164,20 +170,40 @@ inline constexpr bool is_property_v =
164
170
!is_property_list_v<T>;
165
171
166
172
// Empty property list.
167
- template <> class properties <detail::properties_type_list<>, void > {
173
+ template <> class __SYCL_EBO properties<detail::properties_type_list<>, void > {
168
174
template <typename > static constexpr bool has_property () { return false ; }
169
175
};
170
176
171
177
// Base implementation to provide nice user error in case of mis-use. Without it
172
178
// an error "base class '<property>' specified more than once as a direct base
173
179
// class" is reported prior to static_assert's error.
174
180
template <typename ... property_tys>
175
- class properties <
181
+ class __SYCL_EBO properties<
176
182
detail::properties_type_list<property_tys...>,
177
- std::enable_if_t <!detail::property_keys_are_unique<property_tys...>>> {
183
+ std::enable_if_t <!detail::property_names_are_unique<property_tys...>>> {
184
+
185
+ // This is a separate specialization to report an error, we can afford doing
186
+ // extra work to provide nice error message without sacrificing compile time
187
+ // on non-exceptional path. Let's find *a* pair of properties that failed the
188
+ // check. Note that there might be multiple duplicate names, we're only
189
+ // reporting one instance. Once user addresses that, the next pair will be
190
+ // reported.
191
+ static constexpr auto conflict = []() constexpr {
192
+ const std::array keys = {property_tys::property_name...};
193
+ auto N = keys.size ();
194
+ for (int i = 0 ; i < N; ++i)
195
+ for (int j = i + 1 ; j < N; ++j)
196
+ if (keys[i] == keys[j])
197
+ return std::pair{i, j};
198
+ }();
199
+ using first_type = detail::nth_type_t <conflict.first, property_tys...>;
200
+ using second_type = detail::nth_type_t <conflict.second, property_tys...>;
201
+ static_assert (
202
+ !std::is_same_v<typename first_type::key_t , typename second_type::key_t >,
203
+ " Duplicate property!" );
204
+ static_assert (first_type::property_name != second_type::property_name,
205
+ " Property name collision between different property keys!" );
178
206
static_assert ((is_property_v<property_tys> && ...));
179
- static_assert (detail::property_keys_are_unique<property_tys...>,
180
- " Property keys must be unique" );
181
207
};
182
208
183
209
template <typename ... property_tys>
0 commit comments