DPC++ Runtime
Runtime libraries for oneAPI DPC++
property_utils.hpp
Go to the documentation of this file.
1 //==-- property_utils.hpp --- SYCL extended property list common utilities -==//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #pragma once
10 
11 #include <sycl/detail/boost/mp11/algorithm.hpp> // for mp_sort_q
12 #include <sycl/detail/boost/mp11/detail/mp_list.hpp> // for mp_list
13 #include <sycl/detail/boost/mp11/detail/mp_rename.hpp> // for mp_rename
14 #include <sycl/detail/boost/mp11/integral.hpp> // for mp_bool
15 #include <sycl/ext/oneapi/properties/property.hpp> // for PropertyID, IsRun...
16 
17 #include <array> // for tuple_element
18 #include <stddef.h> // for size_t
19 #include <tuple> // for tuple
20 #include <type_traits> // for false_type, true_...
21 #include <variant> // for tuple
22 
23 namespace sycl {
24 inline namespace _V1 {
25 namespace ext::oneapi::experimental {
26 
27 // Forward declaration
28 template <typename PropertyT, typename... Ts> struct property_value;
29 
30 namespace detail {
31 
32 //******************************************************************************
33 // Misc
34 //******************************************************************************
35 
36 // Checks if a type is a tuple.
37 template <typename T> struct IsTuple : std::false_type {};
38 template <typename... Ts> struct IsTuple<std::tuple<Ts...>> : std::true_type {};
39 
40 // Gets the first type in a parameter pack of types.
41 template <typename... Ts>
42 using GetFirstType = typename std::tuple_element<0, std::tuple<Ts...>>::type;
43 
44 // Prepends a value to a tuple.
45 template <typename T, typename Tuple> struct PrependTuple {};
46 template <typename T, typename... Ts>
47 struct PrependTuple<T, std::tuple<Ts...>> {
48  using type = std::tuple<T, Ts...>;
49 };
50 
51 // Checks if a type T has a static value member variable.
52 template <typename T, typename U = int> struct HasValue : std::false_type {};
53 template <typename T>
54 struct HasValue<T, decltype((void)T::value, 0)> : std::true_type {};
55 
56 //******************************************************************************
57 // Property identification
58 //******************************************************************************
59 
60 // Checks if a type is a compile-time property values.
61 // Note: This is specialized for property_value elsewhere.
62 template <typename PropertyT>
63 struct IsCompileTimePropertyValue : std::false_type {};
64 
65 // Checks if a type is either a runtime property or if it is a compile-time
66 // property
67 template <typename T> struct IsProperty {
68  static constexpr bool value =
70 };
71 
72 // Checks if a type is a valid property value, i.e either runtime property or
73 // property_value with a valid compile-time property
74 template <typename T> struct IsPropertyValue {
75  static constexpr bool value =
77 };
78 
79 // Checks that all types in a tuple are valid properties.
80 template <typename T> struct AllPropertyValues {};
81 template <typename... Ts>
82 struct AllPropertyValues<std::tuple<Ts...>> : std::true_type {};
83 template <typename T, typename... Ts>
84 struct AllPropertyValues<std::tuple<T, Ts...>>
85  : std::conditional_t<IsPropertyValue<T>::value,
86  AllPropertyValues<std::tuple<Ts...>>,
87  std::false_type> {};
88 
89 //******************************************************************************
90 // Property type sorting
91 //******************************************************************************
92 
93 // Splits a tuple into head and tail if ShouldSplit is true. If ShouldSplit is
94 // false the head will be void and the tail will be the full tuple.
95 template <typename T1, bool ShouldSplit> struct HeadSplit {};
96 template <typename T, typename... Ts>
97 struct HeadSplit<std::tuple<T, Ts...>, true> {
98  using htype = T;
99  using ttype = std::tuple<Ts...>;
100 };
101 template <typename... Ts> struct HeadSplit<std::tuple<Ts...>, false> {
102  using htype = void;
103  using ttype = std::tuple<Ts...>;
104 };
105 
106 // Selects the one of two types that is not void. This assumes that at least one
107 // of the two template arguemnts is void.
108 template <typename LHS, typename RHS> struct SelectNonVoid {};
109 template <typename LHS> struct SelectNonVoid<LHS, void> {
110  using type = LHS;
111 };
112 template <typename RHS> struct SelectNonVoid<void, RHS> {
113  using type = RHS;
114 };
115 
116 // Sort types accoring to their PropertyID.
118  template <typename T1, typename T2>
119  using fn = sycl::detail::boost::mp11::mp_bool<(PropertyID<T1>::value <
121 };
122 template <typename... Ts> struct Sorted {
123  static_assert(detail::AllPropertyValues<std::tuple<Ts...>>::value,
124  "Unrecognized property in property list.");
125  using properties = sycl::detail::boost::mp11::mp_list<Ts...>;
127  sycl::detail::boost::mp11::mp_sort_q<properties, SortByPropertyId>;
128  using type =
129  sycl::detail::boost::mp11::mp_rename<sortedProperties, std::tuple>;
130 };
131 
132 // Checks if the types in a tuple are sorted w.r.t. their PropertyID.
133 template <typename T> struct IsSorted {};
134 template <typename... Ts>
135 struct IsSorted<std::tuple<Ts...>> : std::true_type {};
136 template <typename T> struct IsSorted<std::tuple<T>> : std::true_type {};
137 template <typename L, typename R, typename... Rest>
138 struct IsSorted<std::tuple<L, R, Rest...>>
139  : std::conditional_t<PropertyID<L>::value <= PropertyID<R>::value,
140  IsSorted<std::tuple<R, Rest...>>, std::false_type> {};
141 
142 // Checks that all types in a sorted tuple have unique PropertyID.
143 template <typename T> struct SortedAllUnique {};
144 template <typename... Ts>
145 struct SortedAllUnique<std::tuple<Ts...>> : std::true_type {};
146 template <typename T> struct SortedAllUnique<std::tuple<T>> : std::true_type {};
147 template <typename L, typename R, typename... Rest>
148 struct SortedAllUnique<std::tuple<L, R, Rest...>>
149  : std::conditional_t<PropertyID<L>::value != PropertyID<R>::value,
150  SortedAllUnique<std::tuple<R, Rest...>>,
151  std::false_type> {};
152 
153 //******************************************************************************
154 // Property merging
155 //******************************************************************************
156 
157 // Merges two sets of properties, failing if two properties are the same but
158 // with different values.
159 // NOTE: This assumes that the properties are in sorted order.
160 template <typename LHSPropertyT, typename RHSPropertyT> struct MergeProperties;
161 
162 template <> struct MergeProperties<std::tuple<>, std::tuple<>> {
163  using type = std::tuple<>;
164 };
165 
166 template <typename... LHSPropertyTs>
167 struct MergeProperties<std::tuple<LHSPropertyTs...>, std::tuple<>> {
168  using type = std::tuple<LHSPropertyTs...>;
169 };
170 
171 template <typename... RHSPropertyTs>
172 struct MergeProperties<std::tuple<>, std::tuple<RHSPropertyTs...>> {
173  using type = std::tuple<RHSPropertyTs...>;
174 };
175 
176 // Identical properties are allowed, but only one will carry over.
177 template <typename PropertyT, typename... LHSPropertyTs,
178  typename... RHSPropertyTs>
179 struct MergeProperties<std::tuple<PropertyT, LHSPropertyTs...>,
180  std::tuple<PropertyT, RHSPropertyTs...>> {
181  using merge_tails =
182  typename MergeProperties<std::tuple<LHSPropertyTs...>,
183  std::tuple<RHSPropertyTs...>>::type;
184  using type = typename PrependTuple<PropertyT, merge_tails>::type;
185 };
186 
187 template <typename... LHSPropertyTs, typename... RHSPropertyTs>
188 struct MergeProperties<std::tuple<LHSPropertyTs...>,
189  std::tuple<RHSPropertyTs...>> {
190  using l_head = GetFirstType<LHSPropertyTs...>;
191  using r_head = GetFirstType<RHSPropertyTs...>;
192  static_assert(
193  PropertyID<l_head>::value != PropertyID<r_head>::value,
194  "Failed to merge property lists due to conflicting properties.");
195  static constexpr bool left_has_min =
196  PropertyID<l_head>::value < PropertyID<r_head>::value;
197  using l_split = HeadSplit<std::tuple<LHSPropertyTs...>, left_has_min>;
198  using r_split = HeadSplit<std::tuple<RHSPropertyTs...>, !left_has_min>;
199  using min = typename SelectNonVoid<typename l_split::htype,
200  typename r_split::htype>::type;
201  using merge_tails = typename MergeProperties<typename l_split::ttype,
202  typename r_split::ttype>::type;
203  using type = typename PrependTuple<min, merge_tails>::type;
204 };
205 
206 //******************************************************************************
207 // Property value tooling
208 //******************************************************************************
209 
210 // Simple helpers for containing primitive types as template arguments.
211 template <size_t... Sizes> struct SizeList {};
212 template <char... Sizes> struct CharList {};
213 
214 // Helper for converting characters to a constexpr string.
215 template <char... Chars> struct CharsToStr {
216  static constexpr const char value[] = {Chars..., '\0'};
217 };
218 
219 // Helper for converting a list of size_t values to a comma-separated string
220 // representation. This is done by extracting the digit one-by-one and when
221 // finishing a value, the parsed result is added to a separate list of
222 // "parsed" characters with the delimiter.
223 template <typename List, typename ParsedList, char... Chars>
224 struct SizeListToStrHelper;
225 
226 // Specialization for when we are in the process of converting a non-zero value
227 // (Value). Chars will have the already converted digits of the original value
228 // being converted. Instantiation of this will convert the least significant
229 // digit in Value.
230 // Example:
231 // - Current: SizeListToStrHelper<SizeList<12>, CharList<'1', '0', ','>, '3'>
232 // - Next: SizeListToStrHelper<SizeList<1>, CharList<'1', '0', ','>, '2', '3'>
233 // - Outermost: SizeListToStrHelper<SizeList<10,123>, CharList<>>
234 // - Final: SizeListToStrHelper<SizeList<0>,
235 // CharList<'1', '0', ','>, '1', '2', '3'>>
236 // - Result string: "10,123"
237 template <size_t Value, size_t... Values, char... ParsedChars, char... Chars>
238 struct SizeListToStrHelper<SizeList<Value, Values...>, CharList<ParsedChars...>,
239  Chars...>
240  : SizeListToStrHelper<SizeList<Value / 10, Values...>,
241  CharList<ParsedChars...>, '0' + (Value % 10),
242  Chars...> {};
243 
244 // Specialization for when we have reached 0 in the current value we are
245 // converting. In this case we are done with converting the current value and
246 // we insert the converted digits from Chars into ParsedChars.
247 // Example:
248 // - Current: SizeListToStrHelper<SizeList<0,123>, CharList<>, '1', '0'>
249 // - Next: SizeListToStrHelper<SizeList<123>, CharList<'1', '0', ','>>
250 // - Outermost: SizeListToStrHelper<SizeList<10,123>, CharList<>>
251 // - Final: SizeListToStrHelper<SizeList<0>,
252 // CharList<'1', '0', ','>, '1', '2', '3'>>
253 // - Result string: "10,123"
254 template <size_t... Values, char... ParsedChars, char... Chars>
255 struct SizeListToStrHelper<SizeList<0, Values...>, CharList<ParsedChars...>,
256  Chars...>
257  : SizeListToStrHelper<SizeList<Values...>,
258  CharList<ParsedChars..., Chars..., ','>> {};
259 
260 // Specialization for the special case where the value we are converting is 0
261 // but the list of converted digits is empty. This means there was a 0 value in
262 // the list and we can add it to ParsedChars directly.
263 // Example:
264 // - Current: SizeListToStrHelper<SizeList<0,123>, CharList<>>
265 // - Next: SizeListToStrHelper<SizeList<123>, CharList<'0', ','>>
266 // - Outermost: SizeListToStrHelper<SizeList<0,123>, CharList<>>
267 // - Final: SizeListToStrHelper<SizeList<0>,
268 // CharList<'0', ','>, '1', '2', '3'>>
269 // - Result string: "0,123"
270 template <size_t... Values, char... ParsedChars>
271 struct SizeListToStrHelper<SizeList<0, Values...>, CharList<ParsedChars...>>
272  : SizeListToStrHelper<SizeList<Values...>,
273  CharList<ParsedChars..., '0', ','>> {};
274 
275 // Specialization for when we have reached 0 in the current value we are
276 // converting and there a no more values to parse. In this case we are done with
277 // converting the current value and we insert the converted digits from Chars
278 // into ParsedChars. We do not add a ',' as it is the end of the list.
279 // Example:
280 // - Current: SizeListToStrHelper<SizeList<0>, CharList<'1', '0', ','>, '1',
281 // '2', '3'>>
282 // - Next: None.
283 // - Outermost: SizeListToStrHelper<SizeList<10,123>, CharList<>>
284 // - Final: SizeListToStrHelper<SizeList<0>,
285 // CharList<'1', '0', ','>, '1', '2', '3'>>
286 // - Result string: "10,123"
287 template <char... ParsedChars, char... Chars>
288 struct SizeListToStrHelper<SizeList<0>, CharList<ParsedChars...>, Chars...>
289  : CharsToStr<ParsedChars..., Chars...> {};
290 
291 // Specialization for when we have reached 0 in the current value we are
292 // converting and there a no more values to parse, but the list of converted
293 // digits is empty. This means the last value in the list was a 0 so we can add
294 // that to the ParsedChars and finish.
295 // Example:
296 // - Current: SizeListToStrHelper<SizeList<0>, CharList<'1', '0', ','>>>
297 // - Next: None.
298 // - Outermost: SizeListToStrHelper<SizeList<10,0>, CharList<>>
299 // - Final: SizeListToStrHelper<SizeList<0>, CharList<>, '1', '0'>>
300 // - Result string: "10,0"
301 template <char... ParsedChars>
302 struct SizeListToStrHelper<SizeList<0>, CharList<ParsedChars...>>
303  : CharsToStr<ParsedChars..., '0'> {};
304 
305 // Specialization for the empty list of values to convert. This results in an
306 // empty string.
307 template <>
308 struct SizeListToStrHelper<SizeList<>, CharList<>> : CharsToStr<> {};
309 
310 // Converts size_t values to a comma-separated string representation.
311 template <size_t... Sizes>
312 struct SizeListToStr : SizeListToStrHelper<SizeList<Sizes...>, CharList<>> {};
313 
314 //******************************************************************************
315 // Property mutual exclusivity
316 //******************************************************************************
317 
318 // Specializations of the following trait should not consider itself a
319 // conflicting property.
320 template <typename PropKey, typename Properties>
321 struct ConflictingProperties : std::false_type {};
322 
323 template <typename Properties, typename T>
324 struct NoConflictingPropertiesHelper {};
325 
326 template <typename Properties, typename... Ts>
327 struct NoConflictingPropertiesHelper<Properties, std::tuple<Ts...>>
328  : std::true_type {};
329 
330 template <typename Properties, typename T, typename... Ts>
331 struct NoConflictingPropertiesHelper<Properties, std::tuple<T, Ts...>>
332  : NoConflictingPropertiesHelper<Properties, std::tuple<Ts...>> {};
333 
334 template <typename Properties, typename... Rest, typename PropT,
335  typename... PropValuesTs>
336 struct NoConflictingPropertiesHelper<
337  Properties, std::tuple<property_value<PropT, PropValuesTs...>, Rest...>>
338  : std::conditional_t<
339  ConflictingProperties<PropT, Properties>::value, std::false_type,
340  NoConflictingPropertiesHelper<Properties, std::tuple<Rest...>>> {};
341 template <typename PropertiesT>
342 struct NoConflictingProperties
343  : NoConflictingPropertiesHelper<PropertiesT, PropertiesT> {};
344 
345 //******************************************************************************
346 // Conditional property meta-info
347 //******************************************************************************
348 
349 // Base class for property meta info that is ignored when propagating
350 // information through the compiler.
351 struct IgnoredPropertyMetaInfo {
352  static constexpr const char *name = "";
353  static constexpr std::nullptr_t value = nullptr;
354 };
355 
356 // Trait for picking either property meta information for PropT if Condition is
357 // true or ignored information if Condition is false.
358 template <typename PropT, bool Condition>
359 struct ConditionalPropertyMetaInfo
360  : std::conditional_t<Condition, PropertyMetaInfo<PropT>,
361  IgnoredPropertyMetaInfo> {};
362 
363 } // namespace detail
364 } // namespace ext::oneapi::experimental
365 } // namespace _V1
366 } // namespace sycl
sycl::ext::oneapi::experimental::property_value< PropertyT, Ts... > property_value
typename std::tuple_element< 0, std::tuple< Ts... > >::type GetFirstType
Definition: access.hpp:18
sycl::detail::boost::mp11::mp_bool<(PropertyID< T1 >::value< PropertyID< T2 >::value)> fn
sycl::detail::boost::mp11::mp_rename< sortedProperties, std::tuple > type
sycl::detail::boost::mp11::mp_list< Ts... > properties
sycl::detail::boost::mp11::mp_sort_q< properties, SortByPropertyId > sortedProperties