[glibmm] Variant: Allow containing complex types in arrays and in variants.



commit 8460377403f9cb02f2fd3972a9dcfa1d978ab7ab
Author: Josà Alburquerque <jaalburqu svn gnome org>
Date:   Fri Dec 28 11:10:46 2012 -0500

    Variant: Allow containing complex types in arrays and in variants.
    
    	* glib/src/variant.hg (Variant< Variant<T> >): Add a new class capable
    	of containing any Variant<>.  The class is just like
    	Variant<VariantBase> except that with it, it is now possible to store
    	and handle complex variant types in a variant easily in a C++ way.
    	The modified test below exemplifies.
    	(Variant< std::vector<T> >::create): Create a Variant<> for each of
    	the members in the vector and then use g_variant_builder_add_value()
    	to add the underlying GVariant of the wrapped elements in the builder
    	instead of using the variadic g_variant_builder_add() function which
    	causes problems when dealing with types that are more complex than
    	basic ones.
    	(Variant< std::vector<T> >::get_child): Rewritten to get the child as
    	a GVariant, wrap the GVariant in a Variant<> and then get its value
    	instead of assuming that the array in the variant is a fixed array of
    	basic types so that complex types are supported in arrays.
    	(Variant< std::vector<T> >::get): Rewritten as get_child() above so
    	that the elements in the array are gotten as a GVariant, wrapped in a
    	Variant<> and then retrieved and placed in the resulting vector,
    	again, to ensure that a vector of complex types can be stored in a
    	variant.
    	* tests/glibmm_variant/main.cc: Modify the test to ensure that any
    	type other than basic ones are supported.

 ChangeLog                    |   27 ++++++++++
 glib/src/variant.hg          |  118 ++++++++++++++++++++++++++++++++++++-----
 tests/glibmm_variant/main.cc |   57 ++++++++++++++++++++-
 3 files changed, 186 insertions(+), 16 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index a33a7ea..e673c7c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2012-12-28  Josà Alburquerque  <jaalburquerque gmail com>
+
+	Variant: Allow containing complex types in arrays and in variants.
+
+	* glib/src/variant.hg (Variant< Variant<T> >): Add a new class capable
+	of containing any Variant<>.  The class is just like
+	Variant<VariantBase> except that with it, it is now possible to store
+	and handle complex variant types in a variant easily in a C++ way.
+	The modified test below exemplifies.
+	(Variant< std::vector<T> >::create): Create a Variant<> for each of
+	the members in the vector and then use g_variant_builder_add_value()
+	to add the underlying GVariant of the wrapped elements in the builder
+	instead of using the variadic g_variant_builder_add() function which
+	causes problems when dealing with types that are more complex than
+	basic ones.
+	(Variant< std::vector<T> >::get_child): Rewritten to get the child as
+	a GVariant, wrap the GVariant in a Variant<> and then get its value
+	instead of assuming that the array in the variant is a fixed array of
+	basic types so that complex types are supported in arrays.
+	(Variant< std::vector<T> >::get): Rewritten as get_child() above so
+	that the elements in the array are gotten as a GVariant, wrapped in a
+	Variant<> and then retrieved and placed in the resulting vector,
+	again, to ensure that a vector of complex types can be stored in a
+	variant.
+	* tests/glibmm_variant/main.cc: Modify the test to ensure that any
+	type other than basic ones are supported.
+
 2012-12-28  Kjell Ahlstedt  <kjell ahlstedt bredband net>
 
 	Gio::Action: Add more documentation of get_state_hint() and get_state().
diff --git a/glib/src/variant.hg b/glib/src/variant.hg
index 19e84f8..1237ee1 100644
--- a/glib/src/variant.hg
+++ b/glib/src/variant.hg
@@ -439,6 +439,50 @@ public:
   _WRAP_METHOD(VariantBase get() const, g_variant_get_variant)
 };
 
+/** Specialization of Variant containing a Variant<T>.
+ * @newin{2,36}
+ * @ingroup Variant
+ */
+template<class T>
+class Variant< Variant<T> > : public VariantContainerBase
+{
+public:
+  typedef GVariant*                     CType;
+  typedef Variant<T>                    CppType;
+  typedef Variant<CppType>              CppContainerType;
+
+  /// Default constructor.
+  Variant< Variant<T> >();
+
+  /** 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).
+   * @newin{2,36}
+   */
+  explicit Variant< Variant<T> >(GVariant* castitem, bool take_a_reference = false);
+
+  /** Gets the VariantType.
+   * @return The VariantType.
+   * @newin{2,36}
+   */
+  static const VariantType& variant_type() G_GNUC_CONST;
+
+  /** Creates a new Variant< Variant<T> >.
+   * @param data The value of the new Variant.
+   * @return The new Variant.
+   * @newin{2,36}
+   */
+  static Variant< Variant<T> > create(const Variant<T>& data);
+
+  /** Gets the contents of the Variant.
+   * @return The contents of the Variant.
+   * @newin{2,36}
+   */
+  Variant<T> get() const;
+};
+
 /** Specialization of Variant containing a Glib::ustring, for variants of type
  * string, bytestring, object path, or signature.
  * @newin{2,28}
@@ -899,6 +943,42 @@ _IGNORE(
 namespace Glib
 {
 
+/*--------------------Variant< Variant<T> >---------------------*/
+
+template<class T>
+Variant< Variant<T> >::Variant()
+: VariantContainerBase()
+{
+}
+
+template<class T>
+Variant< Variant<T> >::Variant(GVariant* castitem, bool take_a_reference)
+: VariantContainerBase(castitem, take_a_reference)
+{
+}
+
+// static
+template<class T>
+const VariantType& Variant< Variant<T> >::variant_type()
+{
+  return VARIANT_TYPE_VARIANT;
+}
+
+template<class T>
+Variant< Variant<T> > Variant< Variant<T> >::create(const Variant<T>& data)
+{
+  Variant< Variant<T> > result = Variant< Variant<T> >(
+    g_variant_new_variant(const_cast<GVariant*>(data.gobj())));
+  return result;
+}
+
+template<class T>
+Variant<T> Variant< Variant<T> >::get() const
+{
+  GVariant* const gvariant = g_variant_get_variant(gobject_);
+  return Variant<T>(gvariant, true);
+}
+
 /*--------------------Variant< std::pair<K, V> >---------------------*/
 
 // static
@@ -970,8 +1050,8 @@ Variant< std::vector<T> >::create(const std::vector<T>& data)
   for(typename std::vector<T>::const_iterator iter = data.begin();
    iter < data.end(); iter++)
   {
-    g_variant_builder_add(builder,
-      reinterpret_cast<gchar*>(element_variant_type.gobj()), *iter);
+    Glib::Variant<T> variant = Glib::Variant<T>::create(*iter);
+    g_variant_builder_add_value(builder, variant.gobj());
   }
 
   // Create the variant using the builder.
@@ -985,29 +1065,37 @@ Variant< std::vector<T> >::create(const std::vector<T>& data)
 template<class T>
 T Variant< std::vector<T> >::get_child(gsize index) const
 {
-  gsize n_elements = 0;
+  if(index >= g_variant_n_children(const_cast<GVariant*>(gobj())))
+    throw std::out_of_range(
+      "Variant< std::vector<T> >::get_child(): Index out of bounds.");
 
-  const T* array = reinterpret_cast<const T*>(
-    g_variant_get_fixed_array(const_cast<GVariant*>(gobj()), &n_elements,
-    sizeof(T)));
+  Glib::Variant<T> variant;
 
-  if(index >= n_elements)
-    throw std::out_of_range(
-      "Variant< std::vector<T> >::get(): Index out of bounds.");
+  GVariant* gvariant =
+    g_variant_get_child_value(const_cast<GVariant*>(gobj()), index);
 
-  return array[index];
+  variant.init(gvariant);
+  return variant.get();
 }
 
 template<class T>
 std::vector<T> Variant< std::vector<T> >::get() const
 {
-  gsize n_elements = 0;
+  std::vector<T> result;
+
+  gsize n_children = g_variant_n_children(const_cast<GVariant*>(gobj()));
 
-  const T* array = reinterpret_cast<const T*>(
-    g_variant_get_fixed_array(const_cast<GVariant*>(gobj()), &n_elements,
-    sizeof(T)));
+  for(gsize i = 0; i < n_children; i++)
+  {
+    Glib::Variant<T> variant;
+
+    GVariant* gvariant =
+      g_variant_get_child_value(const_cast<GVariant*>(gobj()), i);
+
+    variant.init(gvariant);
+    result.push_back(variant.get());
+  }
 
-  std::vector<T> result(array, array + n_elements);
   return result;
 }
 
diff --git a/tests/glibmm_variant/main.cc b/tests/glibmm_variant/main.cc
index 49da1e2..086719f 100644
--- a/tests/glibmm_variant/main.cc
+++ b/tests/glibmm_variant/main.cc
@@ -55,7 +55,7 @@ int main(int, char**)
   vec_strings.push_back("a");
   Glib::Variant<std::vector<std::string> > variant_vec_strings =
     Glib::Variant<std::vector<std::string> >::create(vec_strings);
-  
+
   //Dict:
 
   typedef std::pair<Glib::ustring, Glib::ustring> TypeDictEntry;
@@ -120,6 +120,61 @@ int main(int, char**)
       " in the variant are: " << value << '.' << std::endl;
   }
 
+  //std::vector< std::map< Glib::ustring, Glib::Variant<int> > >
+  typedef std::map< Glib::ustring, Glib::Variant<int> > ComplexDictType;
+
+  ComplexDictType complex_dict1;
+  ComplexDictType complex_dict2;
+
+  for(int i = 0; i < 10; i++)
+  {
+    // Convert integer i to string.
+    std::stringstream ss;
+    ss << i;
+
+    Glib::ustring s = "String " + ss.str();
+
+    Glib::Variant<int> v = Glib::Variant<int>::create(i);
+
+    complex_dict1.insert(
+      std::pair< Glib::ustring, Glib::Variant<int> >("Map 1 " + s, v));
+
+    complex_dict2.insert(
+      std::pair< Glib::ustring, Glib::Variant<int> >("Map 2 " + s, v));
+  }
+
+  typedef std::vector< std::map< Glib::ustring, Glib::Variant<int> > >
+    ComplexVecType;
+
+  ComplexVecType complex_vector;
+  complex_vector.push_back(complex_dict1);
+  complex_vector.push_back(complex_dict2);
+
+  Glib::Variant<ComplexVecType> complex_variant =
+    Glib::Variant<ComplexVecType>::create(complex_vector);
+
+  // This will output the type string aa{sv}.
+  ostr << "The type string of the variant containing a vector of "
+    "dictionaries is: " << std::endl << complex_variant.get_type_string() <<
+    "." << std::endl << std::endl;
+
+  ComplexVecType copy_complex_vector = complex_variant.get();
+
+  for(guint i = 0; i < copy_complex_vector.size(); i++)
+  {
+    ostr << "Printing dictionary # " << i + 1 << ":" << std::endl;
+
+    ComplexDictType map = copy_complex_vector[i];
+
+    for(ComplexDictType::const_iterator iter = map.begin();
+      iter != map.end(); iter++)
+    {
+      std::pair< Glib::ustring, Glib::Variant<int> > entry = *iter;
+      ostr << entry.first << " -> " << entry.second.get() << "." << std::endl;
+    }
+    ostr << std::endl;
+  }
+  
   test_variant_floating();
   test_dynamic_cast();
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]