From cca6a67aeef42a79c9b7896ab092e513a779a8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20R=C3=B6ssler?= Date: Fri, 8 Sep 2017 13:33:03 +0200 Subject: Glib::Variant: Add template specialization for std::tuple Bug 777791 --- glib/src/variant.hg | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) 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 #include #include +#include #include #include @@ -977,6 +978,71 @@ public: VariantIter get_iter() const; }; +/** Specialization of Variant containing a tuple. + * @newin{2,54} + * @ingroup Variant + */ +template +class Variant> : public VariantContainerBase +{ +public: + using CppContainerType = std::tuple; + + /// Default constructor + Variant>() + : 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>(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> create(const std::tuple& 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 + T get_child(gsize index) const; + + template + Variant get_child_variant(gsize index) const; + + /** Gets the tuple of the Variant. + * @return The tuple. + * @newin{2,54} + */ + std::tuple 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 >::get_iter() const return VariantContainerBase::get_iter(variant_type()); } +/*---------------------Variant> --------------------*/ + +// static +template +const VariantType& Variant>::variant_type() +{ + std::vector 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::variant_type()))...}; + static auto type = VariantType::create_tuple(types); + + return type; +} + +namespace detail +{ +template +void expand_tuple(std::vector &variants, const Tuple & t, + std::index_sequence) +{ + 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::type>::create(std::get(t))))...}; +} +} // namespace detail + +template +Variant> +Variant>::create(const std::tuple& data) +{ + // create a vector containing all tuple values as variants + std::vector variants; + detail::expand_tuple(variants, data, std::index_sequence_for{}); + + using var_ptr = GVariant*; + var_ptr* const var_array = new var_ptr[sizeof... (Types)]; + + for (std::vector::size_type i = 0; i < variants.size(); i++) + var_array[i] = const_cast(variants[i].gobj()); + + Variant> result = Variant>( + g_variant_new_tuple(var_array, variants.size())); + + return result; +} + +template +template +T Variant>::get_child(gsize index) const +{ + Variant entry; + VariantContainerBase::get_child(entry, index); + return entry.get(); +} + +template +template +Variant Variant>::get_child_variant(gsize index) const +{ + Variant entry; + VariantContainerBase::get_child(entry, index); + return entry; +} + +namespace detail +{ +// swallows any argument +template +constexpr int any_arg(T&& arg) +{ + (void)arg; + return 0; +} + +template +void assign_tuple(std::vector &variants, Tuple & t, std::index_sequence) +{ + int i = 0; + using swallow = int[]; // ensures left to right order + (void)swallow {(any_arg(std::get(t) = VariantBase::cast_dynamic::type > >(variants[i++]).get()))...}; +} +} // namespace detail + +template +std::tuple Variant>::get() const +{ + std::tuple data; + int i = 0; + + std::vector 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(i)))...}; + detail::assign_tuple(variants, data, std::index_sequence_for{}); + + return data; +} + +template< class... Types> +VariantIter Variant>::get_iter() const +{ + const auto type = variant_type(); + return VariantContainerBase::get_iter(type); +} + } // namespace Glib -- cgit v1.2.1