[glib/gvariantiter] GVariantIter



commit 3a930ceb4f24f6cd8c05c68ccf809029df352ec8
Author: Ryan Lortie <desrt desrt ca>
Date:   Fri Feb 19 10:36:07 2010 -0500

    GVariantIter

 docs/reference/glib/glib-sections.txt     |   10 +
 docs/reference/glib/tmpl/glib-unused.sgml |   67 ------
 docs/reference/glib/tmpl/macros_misc.sgml |    5 +-
 docs/reference/glib/tmpl/version.sgml     |   68 ++++++
 glib/glib.symbols                         |    9 +
 glib/gvariant.c                           |  350 +++++++++++++++++++++++++++++
 glib/gvariant.h                           |   20 ++
 7 files changed, 460 insertions(+), 69 deletions(-)
---
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index dcb245a..65a02e0 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -2847,6 +2847,16 @@ g_variant_store
 <SUBSECTION>
 g_variant_hash
 g_variant_equal
+
+<SUBSECTION>
+g_variant_iter_copy
+g_variant_iter_free
+g_variant_iter_init
+g_variant_iter_n_children
+g_variant_iter_new
+g_variant_iter_next
+g_variant_iter_next_nofree
+g_variant_iter_next_value
 </SECTION>
 
 <SECTION>
diff --git a/docs/reference/glib/tmpl/glib-unused.sgml b/docs/reference/glib/tmpl/glib-unused.sgml
index 139c500..ca73e16 100644
--- a/docs/reference/glib/tmpl/glib-unused.sgml
+++ b/docs/reference/glib/tmpl/glib-unused.sgml
@@ -900,73 +900,6 @@ Turns the argument into a string literal by using the '#' stringizing operator.
 </para>
 
 
-<!-- ##### VARIABLE glib_binary_age ##### -->
-<para>
-This is the binary age passed to <application>libtool</application>. If 
-<application>libtool</application> means nothing to you, don't worry 
-about it. ;-)
-</para>
-
-
-<!-- ##### FUNCTION glib_check_version ##### -->
-<para>
-
-</para>
-
- required_major: 
- required_minor: 
- required_micro: 
- Returns: 
-
-<!-- ##### VARIABLE glib_interface_age ##### -->
-<para>
-This is the interface age passed to <application>libtool</application>. If 
-<application>libtool</application> means nothing to you, don't worry 
-about it. ;-)
-</para>
-
-
-<!-- ##### VARIABLE glib_major_version ##### -->
-<para>
-The major version number of the GLib library. 
-(e.g. in GLib version 1.2.5 this is 1.)
-</para>
-
-<para>
-This variable is in the library, so represents the
-GLib library you have linked against. Contrast with the
-#GLIB_MAJOR_VERSION macro, which represents the major version of the
-GLib headers you have included.
-</para>
-
-
-<!-- ##### VARIABLE glib_micro_version ##### -->
-<para>
-The micro version number of the GLib library.
-(e.g. in GLib version 1.2.5 this is 5.)
-</para>
-
-<para>
-This variable is in the library, so represents the GLib library you
-have linked against. Contrast with the #GLIB_MICRO_VERSION macro, which
-represents the micro version of the GLib headers you have included.
-</para>
-
-
-<!-- ##### VARIABLE glib_minor_version ##### -->
-<para>
-The minor version number of the GLib library.
-(e.g. in GLib version 1.2.5 this is 2.)
-</para>
-
-<para>
-This variable is in the library, so represents the
-GLib library you have linked against. Contrast with the
-#GLIB_MINOR_VERSION macro, which represents the minor version of the
-GLib headers you have included.
-</para>
-
-
 <!-- ##### MACRO lseek ##### -->
 <para>
 
diff --git a/docs/reference/glib/tmpl/macros_misc.sgml b/docs/reference/glib/tmpl/macros_misc.sgml
index 29ad670..7ce3ff3 100644
--- a/docs/reference/glib/tmpl/macros_misc.sgml
+++ b/docs/reference/glib/tmpl/macros_misc.sgml
@@ -403,7 +403,7 @@ Since: 2.14
 
 
 
-<!-- ##### MACRO G_LIKELY ##### -->
+<!-- ##### FUNCTION G_LIKELY ##### -->
 <para>
 Hints the compiler that the expression is likely to evaluate to a true
 value. The compiler may use this information for optimizations.
@@ -413,9 +413,10 @@ if (G_LIKELY (random () != 1))
   g_print ("not one");
 </programlisting></informalexample>
 
- expr: the expression
 @Returns: the value of @expr
 @Since: 2.2
+<!-- # Unused Parameters # -->
+ expr: the expression
 
 
 <!-- ##### MACRO G_UNLIKELY ##### -->
diff --git a/docs/reference/glib/tmpl/version.sgml b/docs/reference/glib/tmpl/version.sgml
index b1cf0bb..f46c1e1 100644
--- a/docs/reference/glib/tmpl/version.sgml
+++ b/docs/reference/glib/tmpl/version.sgml
@@ -19,6 +19,74 @@ typically use the features described here.
 <!-- ##### SECTION Stability_Level ##### -->
 
 
+<!-- ##### VARIABLE glib_major_version ##### -->
+<para>
+The major version number of the GLib library. 
+(e.g. in GLib version 1.2.5 this is 1.)
+</para>
+
+<para>
+This variable is in the library, so represents the
+GLib library you have linked against. Contrast with the
+#GLIB_MAJOR_VERSION macro, which represents the major version of the
+GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_minor_version ##### -->
+<para>
+The minor version number of the GLib library.
+(e.g. in GLib version 1.2.5 this is 2.)
+</para>
+
+<para>
+This variable is in the library, so represents the
+GLib library you have linked against. Contrast with the
+#GLIB_MINOR_VERSION macro, which represents the minor version of the
+GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_micro_version ##### -->
+<para>
+The micro version number of the GLib library.
+(e.g. in GLib version 1.2.5 this is 5.)
+</para>
+
+<para>
+This variable is in the library, so represents the GLib library you
+have linked against. Contrast with the #GLIB_MICRO_VERSION macro, which
+represents the micro version of the GLib headers you have included.
+</para>
+
+
+<!-- ##### VARIABLE glib_binary_age ##### -->
+<para>
+This is the binary age passed to <application>libtool</application>. If 
+<application>libtool</application> means nothing to you, don't worry 
+about it. ;-)
+</para>
+
+
+<!-- ##### VARIABLE glib_interface_age ##### -->
+<para>
+This is the interface age passed to <application>libtool</application>. If 
+<application>libtool</application> means nothing to you, don't worry 
+about it. ;-)
+</para>
+
+
+<!-- ##### FUNCTION glib_check_version ##### -->
+<para>
+
+</para>
+
+ required_major: 
+ required_minor: 
+ required_micro: 
+ Returns: 
+
+
 <!-- ##### MACRO GLIB_MAJOR_VERSION ##### -->
 <para>
 The major version number of the GLib library.
diff --git a/glib/glib.symbols b/glib/glib.symbols
index 8222b2b..970bf16 100644
--- a/glib/glib.symbols
+++ b/glib/glib.symbols
@@ -1754,6 +1754,15 @@ g_variant_print_string
 
 g_variant_hash
 g_variant_equal
+
+g_variant_iter_copy
+g_variant_iter_free
+g_variant_iter_init
+g_variant_iter_n_children
+g_variant_iter_new
+g_variant_iter_next
+g_variant_iter_next_nofree
+g_variant_iter_next_value
 #endif
 #endif
 
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 6ed560d..e1a0c60 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -1854,5 +1854,355 @@ g_variant_equal (gconstpointer one,
   return equal;
 }
 
+/**
+ * GVariantIter:
+ *
+ * #GVariantIter is an opaque data structure and can only be accessed
+ * using the following functions.
+ **/
+struct stack_iter
+{
+  GVariant *value;
+  gssize n, i;
+  gsize magic;
+};
+
+struct heap_iter
+{
+  struct stack_iter iter;
+
+  GVariant *value_ref;
+  gsize magic;
+};
+
+#define GVSI(i)                 ((struct stack_iter *) (i))
+#define GVHI(i)                 ((struct heap_iter *) (i))
+#define GVSI_MAGIC              ((gsize) 3579507750u)
+#define GVHI_MAGIC              ((gsize) 1450270775u)
+#define is_valid_iter(i)        (GVSI(i)->magic == GVSI_MAGIC)
+#define is_valid_heap_iter(i)   (GVHI(i)->magic == GVHI_MAGIC && \
+                                 is_valid_iter(i))
+
+/**
+ * g_variant_iter_new:
+ * @value: a container #GVariant
+ * @returns: a new heap-allocated #GVariantIter
+ *
+ * Creates a heap-allocated #GVariantIter for iterating over the items
+ * in @value.
+ *
+ * It is appropriate to call g_variant_iter_free() on the return value
+ * of this function.
+ *
+ * A reference is taken to @value and will be released only when
+ * g_variant_iter_free() is called.
+ *
+ * Since: 2.24
+ **/
+GVariantIter *
+g_variant_iter_new (GVariant *value)
+{
+  GVariantIter *iter;
+
+  iter = (GVariantIter *) g_slice_new (struct heap_iter);
+  GVHI(iter)->value_ref = g_variant_ref (value);
+  GVHI(iter)->magic = GVHI_MAGIC;
+
+  g_variant_iter_init (iter, value);
+
+  return iter;
+}
+
+/**
+ * g_variant_iter_init:
+ * @iter: a pointer to a #GVariantIter
+ * @value: a container #GVariant
+ * @returns: the number of items in @value
+ *
+ * Initialises (without allocating) a #GVariantIter.  @iter may be
+ * completely uninitialised prior to this call; its old value is
+ * ignored.
+ *
+ * The iterator remains valid for as long as @value exists, and need not
+ * be freed in any way.
+ *
+ * Since: 2.24
+ **/
+gsize
+g_variant_iter_init (GVariantIter *iter,
+                     GVariant     *value)
+{
+  g_assert (sizeof (GVariantIter) == sizeof (struct stack_iter));
+
+  GVSI(iter)->magic = GVSI_MAGIC;
+  GVSI(iter)->value = value;
+  GVSI(iter)->n = g_variant_n_children (value);
+  GVSI(iter)->i = -1;
+
+  return GVSI(iter)->n;
+}
+
+/**
+ * g_variant_iter_copy:
+ * @iter: a #GVariantIter
+ * @returns: a new heap-allocated #GVariantIter
+ *
+ * Creates a new heap-allocated #GVariantIter to iterate over the
+ * container that was being iterated over by @iter.  The iterator is
+ * rewound and starts at the beginning.
+ *
+ * It is appropriate to call g_variant_iter_free() on the return value
+ * of this function.
+ *
+ * Since: 2.24
+ **/
+GVariantIter *
+g_variant_iter_copy (GVariantIter *iter)
+{
+  g_return_val_if_fail (is_valid_iter (iter), 0);
+
+  return g_variant_iter_new (GVSI(iter)->value);
+}
+
+/**
+ * g_variant_iter_n_children:
+ * @iter: a #GVariantIter
+ * @returns: the number of children in the container
+ *
+ * Queries the number of child items in the container that we are
+ * iterating over.  This is the total number of items -- not the number
+ * of items remaining.
+ *
+ * This function might be useful for preallocation of arrays.
+ *
+ * Since: 2.24
+ **/
+gsize
+g_variant_iter_n_children (GVariantIter *iter)
+{
+  g_return_val_if_fail (is_valid_iter (iter), 0);
+
+  return GVSI(iter)->n;
+}
+
+/**
+ * g_variant_iter_free:
+ * @iter: a heap-allocated #GVariantIter
+ *
+ * Frees a heap-allocated #GVariantIter.  Only call this function on
+ * iterators that were returned by g_variant_iter_new() or
+ * g_variant_iter_copy().
+ *
+ * Since: 2.24
+ **/
+void
+g_variant_iter_free (GVariantIter *iter)
+{
+  g_return_if_fail (is_valid_heap_iter (iter));
+
+  g_variant_unref (GVHI(iter)->value_ref);
+  GVHI(iter)->magic = 0;
+
+  g_slice_free (struct heap_iter, GVHI(iter));
+}
+
+/**
+ * g_variant_iter_next_value:
+ * @iter: a #GVariantIter
+ * @returns: a #GVariant, or %NULL
+ *
+ * Gets the next item in the container.  If no more items remain then
+ * %NULL is returned.
+ *
+ * It is appropriate to call g_variant_unref() on the return value of
+ * this function.
+ *
+ * <example>
+ *  <title>Iterating with g_variant_iter_next_value()</title>
+ *  <programlisting>
+ *   /<!-- -->* recursively iterate a container *<!-- -->/
+ *   void
+ *   iterate_container_recursive (GVariant *container)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *child;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while ((child = g_variant_iter_next_value (&iter)))
+ *       {
+ *         g_print ("type '%s'\n", g_variant_get_type_string (child));
+ *
+ *         if (g_variant_is_container (child))
+ *           iterate_container_recursive (child);
+ *
+ *         g_variant_unref (child);
+ *       }
+ *   }
+ * </programlisting>
+ * </example>
+ *
+ * Since: 2.24
+ **/
+GVariant *
+g_variant_iter_next_value (GVariantIter *iter)
+{
+  g_return_val_if_fail (is_valid_iter (iter), FALSE);
+
+  if G_UNLIKELY (GVSI(iter)->i >= GVSI(iter)->n)
+    {
+      g_critical ("g_variant_iter_get: must not be called again "
+                  "after NULL has already been returned.");
+      return NULL;
+    }
+
+  GVSI(iter)->i++;
+
+  if (GVSI(iter)->i < GVSI(iter)->n)
+    return g_variant_get_child_value (GVSI(iter)->value, GVSI(iter)->i);
+
+  return NULL;
+}
+
+/**
+ * g_variant_iter_next:
+ * @iter: a #GVariantIter
+ * @format_string: a GVariant format string
+ * @...: the arguments to unpack the value into
+ * @returns: %TRUE if a value was unpacked, or %FALSE if there as no
+ *           value
+ *
+ * Gets the next item in the container and unpacks it into the variable
+ * argument list according to @format_string, returning %TRUE.
+ *
+ * If no more items remain then %FALSE is returned.
+ *
+ * On the first call to this function, the pointers appearing on the
+ * variable argument list are assumed to point at uninitialised memory.
+ * On the second and later calls, it is assumed that the same pointers
+ * will be given and that they will point to the memory as set by the
+ * previous call to this function.  This allows the previous values to
+ * be freed, as appropriate.
+ *
+ * <example>
+ *  <title>Memory management with g_variant_iter_next()</title>
+ *  <programlisting>
+ *   /<!-- -->* Iterates a dictionary of type 'a{sv}' *<!-- -->/
+ *   void
+ *   iterate_dictionary (GVariant *dictionary)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *value;
+ *     gchar *key;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+ *       {
+ *         g_print ("Item '%s' has type '%s'\n", key,
+ *                  g_variant_get_type_string (value));
+ *
+ *         /<!-- -->* no need to free 'key' and 'value' here *<!-- -->/
+ *       }
+ *   }
+ *  </programlisting>
+ * </example>
+ *
+ * If you want a slightly less magical alternative that requires more
+ * typing, see g_variant_iter_next_nofree().
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_iter_next (GVariantIter *iter,
+                     const gchar  *format_string,
+                     ...)
+{
+  GVariant *value;
+
+  value = g_variant_iter_next_value (iter);
+
+  if (value != NULL)
+    {
+      va_list ap;
+
+      va_start (ap, format_string);
+      /* varargs get stuff */
+      va_end (ap);
+
+      g_variant_unref (value);
+    }
+
+  return FALSE;
+}
+
+/**
+ * @iter: a #GVariantIter
+ * @format_string: a GVariant format string
+ * @...: the arguments to unpack the value into
+ * @returns: %TRUE if a value was unpacked, or %FALSE if there as no
+ *           value
+ *
+ * Gets the next item in the container and unpacks it into the variable
+ * argument list according to @format_string, returning %TRUE.
+ *
+ * If no more items remain then %FALSE is returned.
+ *
+ * All of the pointers given on the varaible arguments list of this
+ * function are assumed to point at uninitialised memory.  It is the
+ * responsibility of the caller to free all of the values returned by
+ * the unpacking process.
+ *
+ * <example>
+ *  <title>Memory management with g_variant_iter_next_nofree()</title>
+ *  <programlisting>
+ *   /<!-- -->* Iterates a dictionary of type 'a{sv}' *<!-- -->/
+ *   void
+ *   iterate_dictionary (GVariant *dictionary)
+ *   {
+ *     GVariantIter iter;
+ *     GVariant *value;
+ *     gchar *key;
+ *
+ *     g_variant_iter_init (&iter, dictionary);
+ *     while (g_variant_iter_next_nofree (&iter, "{sv}", &key, &value))
+ *       {
+ *         g_print ("Item '%s' has type '%s'\n", key,
+ *                  g_variant_get_type_string (value));
+ *
+ *         /<!-- -->* must free data for ourselves *<!-- -->/
+ *         g_variant_unref (value);
+ *         g_free (key);
+ *       }
+ *   }
+ *  </programlisting>
+ * </example>
+ *
+ * For a solution that is likely to be more convenient to C programmers,
+ * see g_variant_iter_next().
+ *
+ * Since: 2.24
+ **/
+gboolean
+g_variant_iter_next_nofree (GVariantIter *iter,
+                            const gchar  *format_string,
+                            ...)
+{
+  GVariant *value;
+
+  value = g_variant_iter_next_value (iter);
+
+  if (value != NULL)
+    {
+      va_list ap;
+
+      va_start (ap, format_string);
+      /* varargs get stuff */
+      va_end (ap);
+
+      g_variant_unref (value);
+    }
+
+  return FALSE;
+}
+
 #define __G_VARIANT_C__
 #include "galiasdef.c"
diff --git a/glib/gvariant.h b/glib/gvariant.h
index 1860bc2..847ed7e 100644
--- a/glib/gvariant.h
+++ b/glib/gvariant.h
@@ -135,6 +135,26 @@ guint                           g_variant_hash                          (gconstp
 gboolean                        g_variant_equal                         (gconstpointer         one,
                                                                          gconstpointer         two);
 
+typedef struct _GVariantIter GVariantIter;
+struct _GVariantIter {
+  /*< private >*/
+  gsize x[4];
+};
+
+GVariantIter *                  g_variant_iter_new                      (GVariant             *value);
+gsize                           g_variant_iter_init                     (GVariantIter         *iter,
+                                                                         GVariant             *value);
+GVariantIter *                  g_variant_iter_copy                     (GVariantIter         *iter);
+gsize                           g_variant_iter_n_children               (GVariantIter         *iter);
+void                            g_variant_iter_free                     (GVariantIter         *iter);
+GVariant *                      g_variant_iter_next_value               (GVariantIter         *iter);
+gboolean                        g_variant_iter_next                     (GVariantIter         *iter,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+gboolean                        g_variant_iter_next_nofree              (GVariantIter         *iter,
+                                                                         const gchar          *format_string,
+                                                                         ...);
+
 G_END_DECLS
 
 #endif /* __G_VARIANT_H__ */



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