summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Rössler <alexander.roessler@zuehlke.com>2017-09-08 13:33:03 +0200
committerKjell Ahlstedt <kjellahlstedt@gmail.com>2017-09-08 13:33:03 +0200
commitcca6a67aeef42a79c9b7896ab092e513a779a8b3 (patch)
tree6d165c9704e1cf9b8f1ca91c6390ad1331d9eb92
parent0afae1a2bb25f39e039fe1476881982f49627dab (diff)
downloadglibmm-cca6a67aeef42a79c9b7896ab092e513a779a8b3.tar.gz
Glib::Variant: Add template specialization for std::tuple
Bug 777791
-rw-r--r--glib/src/variant.hg186
1 files changed, 186 insertions, 0 deletions
diff --git a/glib/src/variant.hg b/glib/src/variant.hg
index b4e469e1..f0cf212c 100644
--- a/glib/src/variant.hg
+++ b/glib/src/variant.hg
@@ -25,6 +25,7 @@ _DEFS(glibmm,glib)
#include <utility>
#include <vector>
#include <map>
+#include <tuple>
#include <stdexcept>
#include <typeinfo>
@@ -977,6 +978,71 @@ public:
VariantIter get_iter() const;
};
+/** Specialization of Variant containing a tuple.
+ * @newin{2,54}
+ * @ingroup Variant
+ */
+template <class... Types>
+class Variant<std::tuple<Types...>> : public VariantContainerBase
+{
+public:
+ using CppContainerType = std::tuple<Types...>;
+
+ /// Default constructor
+ Variant<std::tuple<Types...>>()
+ : VariantContainerBase()
+ {}
+
+ /** GVariant constructor.
+ * @param castitem The GVariant to wrap.
+ * @param take_a_reference Whether to take an extra reference of the GVariant
+ * or not (not taking one could destroy the GVariant with the wrapper).
+ */
+ explicit Variant<std::tuple<Types...>>(GVariant* castitem, bool take_a_reference = false)
+ : VariantContainerBase(castitem, take_a_reference)
+ {}
+
+ /** Creates a new Variant containing a tuple.
+ * @param data The tuple to use for creation.
+ * @return The new Variant holding a tuple.
+ * @newin{2,54}
+ */
+ static Variant<std::tuple<Types...>> create(const std::tuple<Types...>& data);
+
+ /** Gets the VariantType.
+ * @return The VariantType.
+ * @newin{2,54}
+ */
+ static const VariantType& variant_type() G_GNUC_CONST;
+
+ /** Gets a specific element from the tuple.
+ * It is an error if @a index is greater than or equal to the number of
+ * elements in the tuple. See VariantContainerBase::get_n_children().
+ *
+ * @param index The index of the element.
+ * @return The tuple element at index @a index.
+ * @throw std::out_of_range
+ * @newin{2,54}
+ */
+ template<class T>
+ T get_child(gsize index) const;
+
+ template<class T>
+ Variant<T> get_child_variant(gsize index) const;
+
+ /** Gets the tuple of the Variant.
+ * @return The tuple.
+ * @newin{2,54}
+ */
+ std::tuple<Types...> get() const;
+
+ /** Gets a VariantIter of the Variant.
+ * @return The VariantIter.
+ * @newin{2,54}
+ */
+ VariantIter get_iter() const;
+};
+
} // namespace Glib
@@ -1260,4 +1326,124 @@ VariantIter Variant< std::map<K, V> >::get_iter() const
return VariantContainerBase::get_iter(variant_type());
}
+/*---------------------Variant<std::tuple<class... Types>> --------------------*/
+
+// static
+template <class... Types>
+const VariantType& Variant<std::tuple<Types...>>::variant_type()
+{
+ std::vector<VariantType> types;
+ auto expander = [&types](const VariantType &type) mutable -> int
+ {
+ types.push_back(type);
+ return 0;
+ };
+
+ // expands the variadic template parameters
+ using swallow = int[]; // ensures left to right order
+ swallow{(expander(Variant<Types>::variant_type()))...};
+ static auto type = VariantType::create_tuple(types);
+
+ return type;
+}
+
+namespace detail
+{
+template <class Tuple, std::size_t... Is>
+void expand_tuple(std::vector<VariantBase> &variants, const Tuple & t,
+ std::index_sequence<Is...>)
+{
+ using swallow = int[]; // ensures left to right order
+ auto expander = [&variants](const VariantBase &variant) -> int
+ {
+ variants.push_back(variant);
+ return 0;
+ };
+ (void)swallow {(expander(Variant<typename std::tuple_element<Is, Tuple>::type>::create(std::get<Is>(t))))...};
+}
+} // namespace detail
+
+template <class... Types>
+Variant<std::tuple<Types...>>
+Variant<std::tuple<Types...>>::create(const std::tuple<Types...>& data)
+{
+ // create a vector containing all tuple values as variants
+ std::vector<Glib::VariantBase> variants;
+ detail::expand_tuple(variants, data, std::index_sequence_for<Types...>{});
+
+ using var_ptr = GVariant*;
+ var_ptr* const var_array = new var_ptr[sizeof... (Types)];
+
+ for (std::vector<VariantBase>::size_type i = 0; i < variants.size(); i++)
+ var_array[i] = const_cast<GVariant*>(variants[i].gobj());
+
+ Variant<std::tuple<Types...>> result = Variant<std::tuple<Types...>>(
+ g_variant_new_tuple(var_array, variants.size()));
+
+ return result;
+}
+
+template <class... Types>
+template <class T>
+T Variant<std::tuple<Types...>>::get_child(gsize index) const
+{
+ Variant<T> entry;
+ VariantContainerBase::get_child(entry, index);
+ return entry.get();
+}
+
+template <class... Types>
+template <class T>
+Variant<T> Variant<std::tuple<Types...>>::get_child_variant(gsize index) const
+{
+ Variant<T> entry;
+ VariantContainerBase::get_child(entry, index);
+ return entry;
+}
+
+namespace detail
+{
+// swallows any argument
+template <class T>
+constexpr int any_arg(T&& arg)
+{
+ (void)arg;
+ return 0;
+}
+
+template <class Tuple, std::size_t... Is>
+void assign_tuple(std::vector<VariantBase> &variants, Tuple & t, std::index_sequence<Is...>)
+{
+ int i = 0;
+ using swallow = int[]; // ensures left to right order
+ (void)swallow {(any_arg(std::get<Is>(t) = VariantBase::cast_dynamic<Variant<typename std::tuple_element<Is, Tuple>::type > >(variants[i++]).get()))...};
+}
+} // namespace detail
+
+template <class... Types>
+std::tuple<Types...> Variant<std::tuple<Types...>>::get() const
+{
+ std::tuple<Types...> data;
+ int i = 0;
+
+ std::vector<VariantBase> variants;
+ using swallow = int[]; // ensures left to right order
+ auto expander = [&variants, &i](const VariantBase &variant) -> int
+ {
+ variants.push_back(variant);
+ return i++;
+ };
+ swallow{(expander(get_child_variant<Types>(i)))...};
+ detail::assign_tuple(variants, data, std::index_sequence_for<Types...>{});
+
+ return data;
+}
+
+template< class... Types>
+VariantIter Variant<std::tuple<Types...>>::get_iter() const
+{
+ const auto type = variant_type();
+ return VariantContainerBase::get_iter(type);
+}
+
} // namespace Glib