|
| 1 | +//==---------- properties.hpp --- SYCL extended property list --------------==// |
| 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 <CL/sycl/detail/property_helper.hpp> |
| 12 | +#include <CL/sycl/types.hpp> |
| 13 | +#include <sycl/ext/oneapi/properties/property.hpp> |
| 14 | +#include <sycl/ext/oneapi/properties/property_utils.hpp> |
| 15 | +#include <sycl/ext/oneapi/properties/property_value.hpp> |
| 16 | + |
| 17 | +#include <tuple> |
| 18 | +#include <type_traits> |
| 19 | + |
| 20 | +__SYCL_INLINE_NAMESPACE(cl) { |
| 21 | +namespace sycl { |
| 22 | +namespace ext { |
| 23 | +namespace oneapi { |
| 24 | +namespace experimental { |
| 25 | + |
| 26 | +namespace detail { |
| 27 | + |
| 28 | +// Checks if a tuple of properties contains a property. |
| 29 | +template <typename PropT, typename PropertiesT> |
| 30 | +struct ContainsProperty : std::false_type {}; |
| 31 | +template <typename PropT, typename T, typename... Ts> |
| 32 | +struct ContainsProperty<PropT, std::tuple<T, Ts...>> |
| 33 | + : ContainsProperty<PropT, std::tuple<Ts...>> {}; |
| 34 | +template <typename PropT, typename... Rest> |
| 35 | +struct ContainsProperty<PropT, std::tuple<PropT, Rest...>> : std::true_type {}; |
| 36 | +template <typename PropT, typename... PropValuesTs, typename... Rest> |
| 37 | +struct ContainsProperty< |
| 38 | + PropT, std::tuple<property_value<PropT, PropValuesTs...>, Rest...>> |
| 39 | + : std::true_type {}; |
| 40 | + |
| 41 | +// Finds the full property_value type of a property in a tuple of properties. |
| 42 | +// type is void if the type was not found in the tuple of properties. |
| 43 | +template <typename CTPropertyT, typename PropertiesT = void> |
| 44 | +struct FindCompileTimePropertyValueType { |
| 45 | + using type = void; |
| 46 | +}; |
| 47 | +template <typename CTPropertyT, typename OtherProperty, typename... Rest> |
| 48 | +struct FindCompileTimePropertyValueType<CTPropertyT, |
| 49 | + std::tuple<OtherProperty, Rest...>> { |
| 50 | + using type = |
| 51 | + typename FindCompileTimePropertyValueType<CTPropertyT, |
| 52 | + std::tuple<Rest...>>::type; |
| 53 | +}; |
| 54 | +template <typename CTPropertyT, typename... CTPropertyValueTs, typename... Rest> |
| 55 | +struct FindCompileTimePropertyValueType< |
| 56 | + CTPropertyT, |
| 57 | + std::tuple<property_value<CTPropertyT, CTPropertyValueTs...>, Rest...>> { |
| 58 | + using type = property_value<CTPropertyT, CTPropertyValueTs...>; |
| 59 | +}; |
| 60 | + |
| 61 | +template <typename CTPropertyT, bool HasProperty, typename PropertiesT = void> |
| 62 | +static constexpr std::enable_if_t< |
| 63 | + HasProperty, |
| 64 | + typename FindCompileTimePropertyValueType<CTPropertyT, PropertiesT>::type> |
| 65 | +get_property() { |
| 66 | + return {}; |
| 67 | +} |
| 68 | + |
| 69 | +template <typename CTPropertyT, bool HasProperty, typename PropertiesT = void> |
| 70 | +static constexpr std::enable_if_t<!HasProperty, void> get_property() { |
| 71 | + return; |
| 72 | +} |
| 73 | + |
| 74 | +// Filters for all runtime properties with data in a tuple of properties. |
| 75 | +// NOTE: We only need storage for runtime properties with data. |
| 76 | +template <typename T> struct RuntimePropertyStorage {}; |
| 77 | +template <typename... Ts> struct RuntimePropertyStorage<std::tuple<Ts...>> { |
| 78 | + using type = std::tuple<>; |
| 79 | +}; |
| 80 | +template <typename T, typename... Ts> |
| 81 | +struct RuntimePropertyStorage<std::tuple<T, Ts...>> |
| 82 | + : sycl::detail::conditional_t< |
| 83 | + IsRuntimeProperty<T>::value, |
| 84 | + PrependTuple< |
| 85 | + T, typename RuntimePropertyStorage<std::tuple<Ts...>>::type>, |
| 86 | + RuntimePropertyStorage<std::tuple<Ts...>>> {}; |
| 87 | + |
| 88 | +// Helper class to extract a subset of elements from a tuple. |
| 89 | +// NOTES: This assumes no duplicate properties and that all properties in the |
| 90 | +// struct template argument appear in the tuple passed to Extract. |
| 91 | +template <typename PropertiesT> struct ExtractProperties {}; |
| 92 | +template <typename... PropertiesTs> |
| 93 | +struct ExtractProperties<std::tuple<PropertiesTs...>> { |
| 94 | + template <typename... PropertyValueTs> |
| 95 | + using ExtractedPropertiesT = std::tuple<>; |
| 96 | + |
| 97 | + template <typename... PropertyValueTs> |
| 98 | + static ExtractedPropertiesT<PropertyValueTs...> |
| 99 | + Extract(std::tuple<PropertyValueTs...> PropertyValues) { |
| 100 | + return {}; |
| 101 | + } |
| 102 | +}; |
| 103 | +template <typename PropertyT, typename... PropertiesTs> |
| 104 | +struct ExtractProperties<std::tuple<PropertyT, PropertiesTs...>> { |
| 105 | + template <typename... PropertyValueTs> |
| 106 | + using NextExtractedPropertiesT = |
| 107 | + typename ExtractProperties<std::tuple<PropertiesTs...>>:: |
| 108 | + template ExtractedPropertiesT<PropertyValueTs...>; |
| 109 | + template <typename... PropertyValueTs> |
| 110 | + using ExtractedPropertiesT = |
| 111 | + typename PrependTuple<PropertyT, |
| 112 | + NextExtractedPropertiesT<PropertyValueTs...>>::type; |
| 113 | + |
| 114 | + template <typename... PropertyValueTs> |
| 115 | + static ExtractedPropertiesT<PropertyValueTs...> |
| 116 | + Extract(std::tuple<PropertyValueTs...> PropertyValues) { |
| 117 | + PropertyT ThisExtractedProperty = std::get<PropertyT>(PropertyValues); |
| 118 | + NextExtractedPropertiesT<PropertyValueTs...> NextExtractedProperties = |
| 119 | + ExtractProperties<std::tuple<PropertiesTs...>>::template Extract< |
| 120 | + PropertyValueTs...>(PropertyValues); |
| 121 | + return std::tuple_cat(std::tuple<PropertyT>{ThisExtractedProperty}, |
| 122 | + NextExtractedProperties); |
| 123 | + } |
| 124 | +}; |
| 125 | + |
| 126 | +} // namespace detail |
| 127 | + |
| 128 | +template <typename PropertiesT> class properties { |
| 129 | + static_assert(detail::IsTuple<PropertiesT>::value, |
| 130 | + "Properties must be in a tuple."); |
| 131 | + static_assert(detail::AllPropertyValues<PropertiesT>::value, |
| 132 | + "Unrecognized property in property list."); |
| 133 | + static_assert(detail::IsSorted<PropertiesT>::value, |
| 134 | + "Properties in property list are not sorted."); |
| 135 | + static_assert(detail::SortedAllUnique<PropertiesT>::value, |
| 136 | + "Duplicate properties in property list."); |
| 137 | + |
| 138 | +public: |
| 139 | + template <typename... PropertyValueTs> |
| 140 | + properties(PropertyValueTs... props) |
| 141 | + : Storage(detail::ExtractProperties<StorageT>::Extract( |
| 142 | + std::tuple<PropertyValueTs...>{props...})) {} |
| 143 | + |
| 144 | + template <typename PropertyT> |
| 145 | + static constexpr std::enable_if_t<detail::IsProperty<PropertyT>::value, bool> |
| 146 | + has_property() { |
| 147 | + return detail::ContainsProperty<PropertyT, PropertiesT>::value; |
| 148 | + } |
| 149 | + |
| 150 | + template <typename PropertyT> |
| 151 | + typename std::enable_if_t<detail::IsRuntimeProperty<PropertyT>::value && |
| 152 | + has_property<PropertyT>(), |
| 153 | + PropertyT> |
| 154 | + get_property() const { |
| 155 | + return std::get<PropertyT>(Storage); |
| 156 | + } |
| 157 | + |
| 158 | + template <typename PropertyT> |
| 159 | + typename std::enable_if_t<detail::IsRuntimeProperty<PropertyT>::value && |
| 160 | + !has_property<PropertyT>(), |
| 161 | + void> |
| 162 | + get_property() const { |
| 163 | + static_assert(has_property<PropertyT>(), |
| 164 | + "Property list does not contain the requested property."); |
| 165 | + return; |
| 166 | + } |
| 167 | + |
| 168 | + template <typename PropertyT> |
| 169 | + static constexpr auto get_property( |
| 170 | + typename std::enable_if_t<detail::IsCompileTimeProperty<PropertyT>::value> |
| 171 | + * = 0) { |
| 172 | + static_assert(has_property<PropertyT>(), |
| 173 | + "Property list does not contain the requested property."); |
| 174 | + return detail::get_property<PropertyT, has_property<PropertyT>(), |
| 175 | + PropertiesT>(); |
| 176 | + } |
| 177 | + |
| 178 | +private: |
| 179 | + using StorageT = typename detail::RuntimePropertyStorage<PropertiesT>::type; |
| 180 | + |
| 181 | + StorageT Storage; |
| 182 | +}; |
| 183 | + |
| 184 | +#ifdef __cpp_deduction_guides |
| 185 | +// Deduction guides |
| 186 | +template <typename... PropertyValueTs> |
| 187 | +properties(PropertyValueTs... props) |
| 188 | + -> properties<typename detail::Sorted<PropertyValueTs...>::type>; |
| 189 | +#endif |
| 190 | + |
| 191 | +// Property list traits |
| 192 | +template <typename propertiesT> struct is_property_list : std::false_type {}; |
| 193 | +template <typename... PropertyValueTs> |
| 194 | +struct is_property_list<properties<std::tuple<PropertyValueTs...>>> |
| 195 | + : std::is_same< |
| 196 | + properties<std::tuple<PropertyValueTs...>>, |
| 197 | + properties<typename detail::Sorted<PropertyValueTs...>::type>> {}; |
| 198 | + |
| 199 | +#if __cplusplus > 201402L |
| 200 | +template <typename propertiesT> |
| 201 | +inline constexpr bool is_property_list_v = is_property_list<propertiesT>::value; |
| 202 | +#endif |
| 203 | + |
| 204 | +} // namespace experimental |
| 205 | +} // namespace oneapi |
| 206 | +} // namespace ext |
| 207 | + |
| 208 | +// If property_list is not trivially copyable, allow properties to propagate |
| 209 | +// is_device_copyable |
| 210 | +template <typename PropertiesT> |
| 211 | +struct is_device_copyable< |
| 212 | + ext::oneapi::experimental::properties<PropertiesT>, |
| 213 | + std::enable_if_t<!std::is_trivially_copyable< |
| 214 | + ext::oneapi::experimental::properties<PropertiesT>>::value>> |
| 215 | + : is_device_copyable<PropertiesT> {}; |
| 216 | +template <typename PropertiesT> |
| 217 | +struct is_device_copyable< |
| 218 | + const ext::oneapi::experimental::properties<PropertiesT>, |
| 219 | + std::enable_if_t<!std::is_trivially_copyable< |
| 220 | + const ext::oneapi::experimental::properties<PropertiesT>>::value>> |
| 221 | + : is_device_copyable<PropertiesT> {}; |
| 222 | + |
| 223 | +} // namespace sycl |
| 224 | +} // __SYCL_INLINE_NAMESPACE(cl) |
0 commit comments