utility: add merge_variants_t
This type is useful for processing D-Bus messages containing information
for multiple interfaces. For doing sdbusplus::message::message::read()
on them one needs to define an std::variant which would be a combination
of all the PropertiesVariant's involved.
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Change-Id: Idcb7b9841cc0253f2f7d5552dae540fba5ad488d
diff --git a/include/sdbusplus/utility/merge_variants.hpp b/include/sdbusplus/utility/merge_variants.hpp
new file mode 100644
index 0000000..89c5571
--- /dev/null
+++ b/include/sdbusplus/utility/merge_variants.hpp
@@ -0,0 +1,59 @@
+#pragma once
+#include <sdbusplus/utility/dedup_variant.hpp>
+
+#include <variant>
+
+/** See `sdbusplus::utility::merge_variants` below. */
+
+namespace sdbusplus
+{
+namespace utility
+{
+
+namespace details
+{
+
+/** Find the deduplicated variant type.
+ *
+ * @tparam T - A type of the form 'variant<...>'.
+ * @tparam Unused - An empty type set (non-empty sets are matched in
+ * specialization).
+ *
+ * This template is only matched when Unused is empty, which means all
+ * types have been processed (merged).
+ */
+template <typename T, typename... Unused>
+struct merge_variants
+{
+ using type = T;
+};
+
+/** Compute the merged variant type.
+ *
+ * @tparam D, Done - Head and tail of the alternative types list of the
+ * first variant.
+ * @tparam Next - The types of the next variant<...> to be merged with the
+ * first.
+ * @tparam Rest - The remaining variants to be merged.
+ *
+ * Use dedup_variant_t to recursively combine alternative types of all the
+ * supplied variants without duplication.
+ */
+template <typename D, typename... Done, typename... Next, typename... Rest>
+struct merge_variants<std::variant<D, Done...>, std::variant<Next...>,
+ Rest...> :
+ public merge_variants<
+ sdbusplus::utility::dedup_variant_t<D, Done..., Next...>, Rest...>
+{};
+
+} // namespace details
+
+/** This type is useful for processing D-Bus messages containing information for
+ * multiple interfaces. For doing sdbusplus::message::message::read() on them
+ * one needs to define an std::variant which would be a combination of all the
+ * PropertiesVariant's involved. */
+template <typename... T>
+using merge_variants_t = typename details::merge_variants<T...>::type;
+
+} // namespace utility
+} // namespace sdbusplus
diff --git a/test/utility/type_traits.cpp b/test/utility/type_traits.cpp
index a192bdf..8526f29 100644
--- a/test/utility/type_traits.cpp
+++ b/test/utility/type_traits.cpp
@@ -1,4 +1,5 @@
#include <sdbusplus/utility/dedup_variant.hpp>
+#include <sdbusplus/utility/merge_variants.hpp>
#include <sdbusplus/utility/type_traits.hpp>
#include <type_traits>
@@ -93,4 +94,13 @@
std::variant<uint32_t, uint64_t>,
sdbusplus::utility::dedup_variant_t<uint32_t, uint64_t, size_t>>);
+// Tests for merge_variants.
+static_assert(
+ std::is_same_v<std::variant<size_t>,
+ sdbusplus::utility::merge_variants_t<std::variant<size_t>>>);
+static_assert(std::is_same_v<std::variant<char, uint32_t, uint64_t>,
+ sdbusplus::utility::merge_variants_t<
+ std::variant<char, uint32_t>,
+ std::variant<uint32_t, uint64_t, size_t>>>);
+
} // namespace