@@ -43,12 +43,6 @@ template <int N, typename... Ts>
4343using nth_type_t = typename nth_type<N, Ts...>::type;
4444#endif
4545
46- template <typename T, typename PropList> struct PrependProperty {};
47- template <typename T, typename ... Ts>
48- struct PrependProperty <T, properties_type_list<Ts...>> {
49- using type = properties_type_list<T, Ts...>;
50- };
51-
5246// ******************************************************************************
5347// Property identification
5448// ******************************************************************************
@@ -63,91 +57,6 @@ struct AllPropertyValues<std::tuple<T, Ts...>>
6357 AllPropertyValues<std::tuple<Ts...>>,
6458 std::false_type> {};
6559
66- // ******************************************************************************
67- // Property type sorting
68- // ******************************************************************************
69-
70- // Splits a tuple into head and tail if ShouldSplit is true. If ShouldSplit is
71- // false the head will be void and the tail will be the full tuple.
72- template <typename T1, bool ShouldSplit> struct HeadSplit {};
73- template <typename T, typename ... Ts>
74- struct HeadSplit <properties_type_list<T, Ts...>, true > {
75- using htype = T;
76- using ttype = properties_type_list<Ts...>;
77- };
78- template <typename ... Ts> struct HeadSplit <properties_type_list<Ts...>, false > {
79- using htype = void ;
80- using ttype = properties_type_list<Ts...>;
81- };
82-
83- // Selects the one of two types that is not void. This assumes that at least one
84- // of the two template arguemnts is void.
85- template <typename LHS, typename RHS> struct SelectNonVoid {};
86- template <typename LHS> struct SelectNonVoid <LHS, void > {
87- using type = LHS;
88- };
89- template <typename RHS> struct SelectNonVoid <void , RHS> {
90- using type = RHS;
91- };
92-
93- // ******************************************************************************
94- // Property merging
95- // ******************************************************************************
96-
97- // Merges two sets of properties, failing if two properties are the same but
98- // with different values.
99- // NOTE: This assumes that the properties are in sorted order.
100- template <typename LHSPropertyT, typename RHSPropertyT> struct MergeProperties ;
101-
102- template <>
103- struct MergeProperties <properties_type_list<>, properties_type_list<>> {
104- using type = properties_type_list<>;
105- };
106-
107- template <typename ... LHSPropertyTs>
108- struct MergeProperties <properties_type_list<LHSPropertyTs...>,
109- properties_type_list<>> {
110- using type = properties_type_list<LHSPropertyTs...>;
111- };
112-
113- template <typename ... RHSPropertyTs>
114- struct MergeProperties <properties_type_list<>,
115- properties_type_list<RHSPropertyTs...>> {
116- using type = properties_type_list<RHSPropertyTs...>;
117- };
118-
119- // Identical properties are allowed, but only one will carry over.
120- template <typename PropertyT, typename ... LHSPropertyTs,
121- typename ... RHSPropertyTs>
122- struct MergeProperties <properties_type_list<PropertyT, LHSPropertyTs...>,
123- properties_type_list<PropertyT, RHSPropertyTs...>> {
124- using merge_tails =
125- typename MergeProperties<properties_type_list<LHSPropertyTs...>,
126- properties_type_list<RHSPropertyTs...>>::type;
127- using type = typename PrependProperty<PropertyT, merge_tails>::type;
128- };
129-
130- template <typename ... LHSPropertyTs, typename ... RHSPropertyTs>
131- struct MergeProperties <properties_type_list<LHSPropertyTs...>,
132- properties_type_list<RHSPropertyTs...>> {
133- using l_head = nth_type_t <0 , LHSPropertyTs...>;
134- using r_head = nth_type_t <0 , RHSPropertyTs...>;
135- static_assert (
136- PropertyID<l_head>::value != PropertyID<r_head>::value,
137- " Failed to merge property lists due to conflicting properties." );
138- static constexpr bool left_has_min =
139- PropertyID<l_head>::value < PropertyID<r_head>::value;
140- using l_split =
141- HeadSplit<properties_type_list<LHSPropertyTs...>, left_has_min>;
142- using r_split =
143- HeadSplit<properties_type_list<RHSPropertyTs...>, !left_has_min>;
144- using min = typename SelectNonVoid<typename l_split::htype,
145- typename r_split::htype>::type;
146- using merge_tails = typename MergeProperties<typename l_split::ttype,
147- typename r_split::ttype>::type;
148- using type = typename PrependProperty<min, merge_tails>::type;
149- };
150-
15160// ******************************************************************************
15261// Property value tooling
15362// ******************************************************************************
@@ -349,6 +258,44 @@ constexpr auto filter_properties(
349258 return filter_properties_impl<predicate, property_tys...>::apply (props);
350259}
351260
261+ template <typename ... lhs_property_tys> struct merge_filter {
262+ template <typename rhs_property_ty>
263+ struct predicate
264+ : std::bool_constant<!((std::is_same_v<typename lhs_property_tys::key_t ,
265+ typename rhs_property_ty::key_t > ||
266+ ...))> {};
267+ };
268+
269+ template <typename ... lhs_property_tys, typename ... rhs_property_tys>
270+ constexpr auto merge_properties (
271+ const properties<properties_type_list<lhs_property_tys...>> &lhs,
272+ const properties<properties_type_list<rhs_property_tys...>> &rhs) {
273+ auto rhs_unique_props =
274+ filter_properties<merge_filter<lhs_property_tys...>::template predicate>(
275+ rhs);
276+ if constexpr (std::is_same_v<std::decay_t <decltype (rhs)>,
277+ std::decay_t <decltype (rhs_unique_props)>>) {
278+ // None of RHS properties share keys with LHS, no conflicts possible.
279+ return properties{
280+ lhs.template get_property <typename lhs_property_tys::key_t >()...,
281+ rhs.template get_property <typename rhs_property_tys::key_t >()...};
282+ } else {
283+ // Ensure no conflicts, then merge.
284+ constexpr auto has_conflict = [](auto *lhs_prop) constexpr {
285+ using lhs_property_ty = std::remove_pointer_t <decltype (lhs_prop)>;
286+ return (((std::is_same_v<typename lhs_property_ty::key_t ,
287+ typename rhs_property_tys::key_t > &&
288+ (!std::is_same_v<lhs_property_ty, rhs_property_tys> ||
289+ !std::is_empty_v<lhs_property_ty>)) ||
290+ ...));
291+ };
292+ static_assert (
293+ !((has_conflict (static_cast <lhs_property_tys *>(nullptr )) || ...)),
294+ " Failed to merge property lists due to conflicting properties." );
295+ return merge_properties (lhs, rhs_unique_props);
296+ }
297+ }
298+
352299} // namespace detail
353300} // namespace ext::oneapi::experimental
354301} // namespace _V1
0 commit comments