How to `g_slist_prepend` on a boxed typed `GValue`?

I want to add elements to a GSList, that’s residing within a GValue as a boxed type. I.e. I’m searching for a function, that would simply replace the current value of GValue - nothing more.

The following function don’t work]

  • take_boxed will remove appended items of list (i.e. free current value inside GValue)
  • set_boxed will copy the whole list
  • set_static_boxed will prevent freeing of list on g_value_unset

Is there any way to achieve, what I’m trying to do?

Example extract

  GValue * gvalue = g_new0 (GValue, 1);
  g_value_init (gvalue, TYPE_BOXED_SLIST_OF_GCHAR);

  // Initialize to NULL
  g_value_take_boxed (gvalue, NULL);

  // 1nd Element
  {
    GSList * list = (GSList*)(g_value_get_boxed (gvalue));
    list = g_slist_prepend (list, g_strdup("item1"));
    g_value_take_boxed (gvalue, list);
    // list size 1 now
  }

  //2nd Element
  {
    GSList * list = (GSList*)(g_value_get_boxed (gvalue));
    g_slist_print (list, "  ");
    list = g_slist_prepend (list, g_strdup("item2"));
    g_value_take_boxed (gvalue, list);
    // `take` freed the first value; list size 1 now
  }

  // Show list size
  {
    GSList * list = (GSList*)(g_value_get_boxed (gvalue));
    g_print ("list size: %d\n", g_slist_length (list)); 
       // Actual output: 1
       // Expected output: 2
  }

  g_value_unset (gvalue);
  g_free (gvalue);

Full Example Code

#include <gtk/gtk.h>

void
g_slist_print(GSList *list,
               const gchar *prefix)
{
  g_print ("%slist (size:%d): ",  prefix, g_slist_length (list));
  while (list)
  {
    g_print ("%p, ", list);
    list = list->next;
  }
  g_print ("\n");
}



void
boxed_slist_gchar_finalize(gpointer _self)
{
  g_print ("       boxed_slist_gchar_finalize\n");
  GSList * self = (GSList*)_self;
  if (NULL == self) return;

  g_slist_free_full (self, g_free);
}



gpointer
boxed_copy_default(gpointer _self)
{
  g_printerr ("ERROR: Boxed type does not support copying, but copy was called.\n");
  return NULL;
}

#define TYPE_BOXED_SLIST_OF_GCHAR _TYPE_BOXED_SLIST_OF_GCHAR()
GType
_TYPE_BOXED_SLIST_OF_GCHAR()
{
  static GType type;
  if (!type)
    type = g_boxed_type_register_static (
                                "type_boxed_slist_of_gchar",
                                boxed_copy_default,
                                boxed_slist_gchar_finalize);
  return type;
}


int
main(int argc, char *argv[])
{
  gtk_init(&argc, &argv);

  GValue * gvalue = g_new0 (GValue, 1);
  g_value_init (gvalue, TYPE_BOXED_SLIST_OF_GCHAR);

  g_value_take_boxed (gvalue, NULL);

  g_print ("\n1nd Element:\n");
  {
    GSList * list = (GSList*)(g_value_get_boxed (gvalue));
    g_slist_print (list, "  ");
    list = g_slist_append (list, g_strdup("item1"));

    g_value_take_boxed (gvalue, list);
    list = (GSList*)(g_value_get_boxed (gvalue));
    g_slist_print (list, "  ");
  }

  g_print ("\n2nd Element:\n");
  {
    GSList * list = (GSList*)(g_value_get_boxed (gvalue));
    g_slist_print (list, "  ");
    list = g_slist_prepend (list, g_strdup("item2"));

    g_value_take_boxed (gvalue, list);
    list = (GSList*)(g_value_get_boxed (gvalue));
    g_slist_print (list, "  ");
  }


  g_value_unset (gvalue);
  g_free (gvalue);
  return 0;
}

What’s the context of what you’re trying to do? Typically, GValue is used as a transfer container across a polymorphic function call boundary: values are boxed up in a GValue, passed across the boundary, and then unboxed. It’s quite unusual to be trying to use it as a mutable container.

The global context is, I’d like to parse a gconf xml file, where each “option entry” has it’s own datatype and value - also “list” is a datatype. The types and values are represented as GValues.

Within that context, the semi-global context is, I’d like to parse an xml input like this:

	<entry name="list" type="list">
		<li type="string"><stringvalue>list item 1</stringvalue></li>
		<li type="string"><stringvalue>list item 2</stringvalue></li>
	</entry>

This should ultimately result in a data structure like below

GValue 
 └ type:  [boxed GSList*]
 └ value: GSList*
          └ data:  GValue*
                   └ type: G_TYPE_STRING
                   └ value: "list item 1"
          └ next:  GSList*
                   └ data:  GValue*
                            └ type: G_TYPE_STRING
                            └ value: "list item 1"

Note: Naturally for this scenario would be g_slist_append instead of g_slist_prepend. But to make things easier for this questions I formulated it with _prepend.

Why are you trying to parse a GConf XML file? GConf was deprecated almost a decade ago.

I’d appreciate, if we could skip that discussion. If it bothers, just think of a random xml file instead, that happens to be similar to the old gconf style.

GConf XML files only support a limited set of types, so you don’t need the full type genericness of GValue. I’d probably define a custom struct with a union of the different supported types, and design it to be mutable.

I’d also recommend against using linked lists – they require O(N) allocations for N elements – and would use a pointer array (GPtrArray) instead for storing lists of things. It uses 2 allocations for N elements.

If you really are parsing GConf XML files, you may want to consider using libgconf to do the parsing for you. I’ve never tried using it myself, though, so ymmv.

Could you reason about this decision? Why specifically would GValue be unpractical in this situation?

Thank you for the advice. I’ll look into that!

It’s not really designed to be used as a mutable container, and you need something which is mutable.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.