[glibmm] Variant: Add a cast operator.



commit 4af5c32ac1c325a63d89e5a35ca8647c4a4bb908
Author: Yannick Guesnet <yannick guesnet univ-rouen fr>
Date:   Mon Mar 14 20:49:52 2011 +0100

    Variant: Add a cast operator.
    
    * gio/src/glib/src/variant.[ccg|hg]: Add a VariantBase::cast_dynamic()
    static method.
    * tests/glibmm_variant/main.cc: Add some tests.
    
    This is useful because VariantBase can and will be passed by value sometimes
    and DBus may have actual Variant types whose underlying type will not be
    known at compile time (this note was by Murray).
    
    Bug #644146

 ChangeLog                    |   14 ++++++++++++
 glib/src/variant.ccg         |   19 ++++++++++++++++
 glib/src/variant.hg          |   29 ++++++++++++++++++++++++-
 tests/glibmm_variant/main.cc |   49 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 110 insertions(+), 1 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b48ea39..3467618 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2011-03-14  Yannick Guesnet  <Yannick Guesnet univ-rouen fr>
+
+  Variant: Add a cast operator.
+
+	* gio/src/glib/src/variant.[ccg|hg]: Add a VariantBase::cast_dynamic()
+	static method.
+	* tests/glibmm_variant/main.cc: Add some tests.
+
+	This is useful because VariantBase can and will be passed by value sometimes
+	and DBus may have actual Variant types whose underlying type will not be
+	known at compile time (this note was by Murray).
+
+	Bug #644146
+
 2011-03-16  Murray Cumming  <murrayc murrayc com>
 
 	Fix missing doc-install.pl problem with the tarball build.
diff --git a/glib/src/variant.ccg b/glib/src/variant.ccg
index 6246304..c8dc242 100644
--- a/glib/src/variant.ccg
+++ b/glib/src/variant.ccg
@@ -90,6 +90,25 @@ void VariantContainerBase::get(VariantBase& child, gsize index) const
   child.init(gvariant);
 }
 
+// VariantContainerBase has no method variant_type()
+template<>
+VariantContainerBase VariantBase::cast_dynamic<VariantContainerBase>(const VariantBase& v)
+throw(std::bad_cast)
+{
+  if(v.gobj() == NULL)
+  {
+    return VariantContainerBase();
+  }
+  if(v.get_type().is_container())
+  {    
+    return VariantContainerBase(const_cast<GVariant*>(v.gobj()), true);
+  }
+  else
+  {
+    throw std::bad_cast();
+  }
+}
+
 bool VariantContainerBase::get_maybe(Glib::VariantBase& maybe) const
 {
   GVariant* const g_value =
diff --git a/glib/src/variant.hg b/glib/src/variant.hg
index 7161278..d1e7d6c 100644
--- a/glib/src/variant.hg
+++ b/glib/src/variant.hg
@@ -25,6 +25,7 @@ _DEFS(glibmm,glib)
 #include <vector>
 #include <map>
 #include <stdexcept>
+#include <typeinfo>
 
 namespace Glib
 {
@@ -125,8 +126,31 @@ public:
    */
    void byteswap(VariantBase& result) const;
    _IGNORE(g_variant_byteswap)
+
+   template<class V_CastTo>
+   static V_CastTo cast_dynamic(const VariantBase& v)
+   throw(std::bad_cast);
+
 };
 
+template<class V_CastTo>
+V_CastTo VariantBase::cast_dynamic(const VariantBase& v)
+throw(std::bad_cast)
+{
+  if(v.gobj() == NULL)
+  {
+    return V_CastTo();
+  }
+  if(v.is_of_type(V_CastTo::variant_type()))
+  {    
+    return V_CastTo(const_cast<GVariant*>(v.gobj()), true);
+  }
+  else
+  {
+   throw std::bad_cast();
+  }
+}
+
 /** Base class from which string variant classes derive.
  * @newin{2,28}
  * @ingroup Variant
@@ -256,6 +280,10 @@ public:
   _IGNORE(g_variant_get_maybe)
 };
 
+template<>
+VariantContainerBase VariantBase::cast_dynamic<VariantContainerBase>(const VariantBase& v)
+throw(std::bad_cast);
+
 /** Template class used for the specialization of the Glib::Variant<> classes.
  * @newin{2,28}
  * @ingroup Variant
@@ -267,7 +295,6 @@ public:
   typedef T CppType;
 };
 
-
 // Each specialization has (or should have) a variant_type() method that gets
 // the type. So the C g_variant_get_type() function can be ignored.
 _IGNORE(g_variant_get_type)
diff --git a/tests/glibmm_variant/main.cc b/tests/glibmm_variant/main.cc
index cfe12ac..1f463e4 100644
--- a/tests/glibmm_variant/main.cc
+++ b/tests/glibmm_variant/main.cc
@@ -8,6 +8,8 @@
 std::stringstream debug;
 std::ostream& ostr = debug;
 
+static void test_dynamic_cast();
+
 int main(int, char**)
 {
   Glib::init();
@@ -107,5 +109,52 @@ int main(int, char**)
       " in the variant are: " << value << '.' << std::endl;
   }
 
+  test_dynamic_cast();
+
   return EXIT_SUCCESS;
 }
+
+static void test_dynamic_cast()
+{
+  Glib::Variant< int > v1 = Glib::Variant< int >::create(10);
+  Glib::VariantBase& v2 = v1;
+  Glib::Variant< int > v3 = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(v2);
+  g_assert(v3.get() == 10);
+
+  Glib::VariantBase v5 = v1;
+  v3 = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(v5);
+  g_assert(v3.get() == 10);
+
+  Glib::Variant< double > v4;
+  // v4 contain a NULL GVariant: The cast succeed
+  v3 = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(v4);
+
+  v4 = Glib::Variant< double >::create(1.0);
+  try
+  {
+    v3 = Glib::VariantBase::cast_dynamic<Glib::Variant<int> >(v4);
+    g_assert_not_reached();
+  }
+  catch(const std::bad_cast& e)
+  {
+  }
+
+  // A t-uple
+  std::vector<Glib::VariantBase> vec_var(2);
+  vec_var[0] = Glib::Variant<int>::create(1);
+  vec_var[1] = Glib::Variant<Glib::ustring>::create("coucou");
+  Glib::VariantContainerBase var_tuple = Glib::VariantContainerBase::create_tuple(vec_var);
+  g_assert(var_tuple.get_type_string() == "(is)");
+  
+  v5 = var_tuple;
+  Glib::VariantContainerBase v6 = Glib::VariantBase::cast_dynamic<Glib::VariantContainerBase >(v5);
+  
+  try
+  {
+    v6 = Glib::VariantBase::cast_dynamic<Glib::VariantContainerBase >(v1);
+    g_assert_not_reached();
+  }
+  catch (const std::bad_cast& e)
+  {
+  }
+}



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