1 #pragma once
2 #include <type_traits>
3 #include <variant>
4 
5 /** See `sdbusplus::utility::dedup_variant` below. */
6 
7 namespace sdbusplus
8 {
9 namespace utility
10 {
11 
12 namespace details
13 {
14 
15 /** Find the deduplicated variant type.
16  *
17  *  @tparam T - A type of the form 'variant<...>'.
18  *  @tparam Unused - An empty type set (non-empty sets are matched in
19  *                   specialization).
20  *
21  *  This template is only matched when Unused is empty, which means all
22  *  types have been processed (deduplicated).
23  */
24 template <typename T, typename... Unused>
25 struct dedup_variant
26 {
27     using type = T;
28     static_assert(sizeof...(Unused) == 0);
29 };
30 
31 /** Find the deduplicated variant type.
32  *
33  * @tparam Done - The types which have already been deduplicated.
34  * @tparam First - The first type to be deduplicated.
35  * @tparam Rest - The remaining types to be deduplicated.
36  *
37  * This template specialization is matched when there are remaining
38  * items to be analyzed, since the 'First' is a stronger match than the
39  * (empty) 'Types' in the previous template.
40  *
41  * Check for First in Done and recursively create the variant type as
42  * appropriate (add First if First not in Done, skip otherwise).
43  */
44 template <typename... Done, typename First, typename... Rest>
45 struct dedup_variant<std::variant<Done...>, First, Rest...> :
46     public std::conditional_t<
47         (std::is_same_v<First, Done> || ...),
48         dedup_variant<std::variant<Done...>, Rest...>,
49         dedup_variant<std::variant<Done..., First>, Rest...>>
50 {};
51 
52 } // namespace details
53 
54 /** This type is useful for generated code which may inadvertently contain
55  *  duplicate types if specified simply as `std::variant<A, B, C>`.  Some
56  *  types, such as `uint32_t` and `size_t` are the same on some architectures
57  *  and different on others.  `dedup_variant_t<uint32_t, size_t>` will evaluate
58  *  to `std::variant<uint32_t>` on architectures where there is a collision.
59  */
60 template <typename T, typename... Types>
61 using dedup_variant_t =
62     typename details::dedup_variant<std::variant<T>, Types...>::type;
63 
64 // Keep temporarily for backwards compatibility.
65 //  openbmc/bmcweb
66 //  openbmc/smbios-mdr
67 template <typename T, typename... Types>
68 using dedup_variant = dedup_variant_t<T, Types...>;
69 
70 } // namespace utility
71 } // namespace sdbusplus
72