Skip to content

Instantly share code, notes, and snippets.

@geoffjay
Created July 12, 2019 20:35
Show Gist options
  • Save geoffjay/47de7983bed90a262ffc663166f36da5 to your computer and use it in GitHub Desktop.
Save geoffjay/47de7983bed90a262ffc663166f36da5 to your computer and use it in GitHub Desktop.
/**
* compile:
* gcc -g -o json-hashtable `pkg-config --cflags --libs json-glib-1.0` json-hashtable.c
*
* memcheck:
* G_SLICE=always-malloc G_DEBUG=gc-friendly valgrind --tool=memcheck \
* --leak-check=full --show-leak-kinds=definite --errors-for-leak-kinds=definite \
* --leak-resolution=high --num-callers=20 \
* --suppressions=/usr/share/glib-2.0/valgrind/glib.supp \
* ./json-hashtable
*/
#include <json-glib/json-glib.h>
#define FOO_TYPE_OBJECT foo_object_get_type ()
G_DECLARE_FINAL_TYPE (FooObject, foo_object, FOO, OBJECT, GObject)
GHashTable *foo_object_get_list (FooObject *self);
void foo_object_set_list (FooObject *self,
GHashTable *list);
struct _FooObject
{
GObject parent;
GHashTable *list;
};
enum {
PROP_0,
PROP_LIST,
N_PROPS
};
static GParamSpec *properties [N_PROPS];
static void json_serializable_iface_init (gpointer g_iface);
G_DEFINE_TYPE_WITH_CODE (FooObject, foo_object, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (JSON_TYPE_SERIALIZABLE,
json_serializable_iface_init));
static JsonNode *
foo_object_serialize_property (JsonSerializable *serializable,
const gchar *name,
const GValue *value,
GParamSpec *pspec)
{
if (g_strcmp0 (name, "list") == 0)
{
JsonNode *retval;
JsonObject *obj;
GHashTable *list;
GHashTableIter iter;
gpointer key, val;
retval = json_node_new (JSON_NODE_OBJECT);
g_return_val_if_fail (value != NULL, retval);
g_return_val_if_fail (G_VALUE_HOLDS_POINTER (value), retval);
list = g_value_get_pointer (value);
g_return_val_if_fail (list != NULL, retval);
obj = json_object_new ();
if (list != NULL)
{
g_hash_table_iter_init (&iter, list);
while (g_hash_table_iter_next (&iter, &key, &val))
{
json_object_set_double_member (obj,
(const gchar *) key,
g_strtod ((const gchar *) val, NULL));
}
}
json_node_take_object (retval, obj);
return retval;
}
return json_serializable_default_serialize_property (serializable, name, value, pspec);
}
static gboolean
foo_object_deserialize_property (JsonSerializable *serializable,
const gchar *name,
GValue *value,
GParamSpec *pspec,
JsonNode *property_node)
{
if (g_strcmp0 (name, "list") == 0)
{
g_autoptr (GHashTable) list = NULL;
JsonObject *obj;
JsonObjectIter iter;
const gchar *key;
JsonNode *val;
list = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
obj = json_node_dup_object (property_node);
json_object_iter_init (&iter, obj);
while (json_object_iter_next (&iter, &key, &val))
{
g_hash_table_insert (list,
g_strdup (key),
g_strdup_printf ("%.9f", json_node_get_double (val)));
json_node_free (val);
}
g_value_set_pointer (value, list);
g_hash_table_ref (list);
return TRUE;
}
return json_serializable_default_deserialize_property (serializable, name, value, pspec, property_node);
}
static void
json_serializable_iface_init (gpointer g_iface)
{
JsonSerializableIface *iface = g_iface;
iface->serialize_property = foo_object_serialize_property;
iface->deserialize_property = foo_object_deserialize_property;
}
static void
foo_object_dispose (GObject *object)
{
G_GNUC_UNUSED FooObject *self = (FooObject *)object;
g_debug ("dispose");
G_OBJECT_CLASS (foo_object_parent_class)->dispose (object);
}
static void
foo_object_finalize (GObject *object)
{
FooObject *self = (FooObject *)object;
g_clear_pointer (&self->list, g_hash_table_unref);
G_OBJECT_CLASS (foo_object_parent_class)->finalize (object);
}
static void
foo_object_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
FooObject *self = FOO_OBJECT (object);
switch (prop_id)
{
case PROP_LIST:
g_value_set_pointer (value, self->list);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
foo_object_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
FooObject *self = FOO_OBJECT (object);
switch (prop_id)
{
case PROP_LIST:
foo_object_set_list (self, g_value_get_pointer (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
foo_object_class_init (FooObjectClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = foo_object_dispose;
object_class->finalize = foo_object_finalize;
object_class->get_property = foo_object_get_property;
object_class->set_property = foo_object_set_property;
properties [PROP_LIST] =
g_param_spec_pointer ("list",
"List",
"List of things.",
(G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_CONSTRUCT));
g_object_class_install_properties (object_class, N_PROPS, properties);
}
static void
foo_object_init (FooObject *self)
{
}
FooObject *
foo_object_new ()
{
return g_object_new (FOO_TYPE_OBJECT, NULL);
}
gchar *
foo_object_serialize (FooObject *self)
{
g_return_val_if_fail (FOO_IS_OBJECT (self), NULL);
return json_gobject_to_data (G_OBJECT (self), NULL);
}
void
foo_object_deserialize (FooObject *self,
const gchar *data)
{
g_autoptr (GObject) object = NULL;
g_autoptr (GHashTable) list = NULL;
GError *err = NULL;
object = json_gobject_from_data (FOO_TYPE_OBJECT,
data,
-1,
&err);
if (err != NULL)
{
g_critical ("%s", err->message);
g_error_free (err);
}
g_return_if_fail (object != NULL);
g_return_if_fail (FOO_IS_OBJECT (object));
list = foo_object_get_list (FOO_OBJECT (object));
foo_object_set_list (self, list);
g_clear_object (&object);
}
GObject *
foo_gobject_from_data (const gchar *data)
{
GError *err = NULL;
GObject *object = json_gobject_from_data (FOO_TYPE_OBJECT,
data,
-1,
&err);
if (err != NULL)
{
g_critical ("%s", err->message);
g_error_free (err);
}
g_return_val_if_fail (object != NULL, NULL);
g_return_val_if_fail (FOO_IS_OBJECT (object), NULL);
return object;
}
void
foo_object_dummy_data (FooObject *self)
{
g_autoptr (GHashTable) list = NULL;
g_return_if_fail (FOO_IS_OBJECT (self));
list = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
g_free);
g_hash_table_insert (list, g_strdup ("a"), g_strdup ("0.0"));
g_hash_table_insert (list, g_strdup ("b"), g_strdup ("1.0"));
g_hash_table_insert (list, g_strdup ("c"), g_strdup ("2.0"));
g_hash_table_insert (list, g_strdup ("d"), g_strdup ("3.0"));
foo_object_set_list (self, list);
}
GHashTable *
foo_object_get_list (FooObject *self)
{
GHashTable *list;
g_return_val_if_fail (FOO_IS_OBJECT (self), NULL);
g_object_get (self, "list", &list, NULL);
return list;
}
void
foo_object_set_list (FooObject *self,
GHashTable *list)
{
g_return_if_fail (FOO_IS_OBJECT (self));
if (self->list == list)
return;
if (list)
g_hash_table_ref (list);
if (self->list)
g_hash_table_unref (self->list);
self->list = list;
g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LIST]);
}
static const gchar *json = "{ \
\"list\": { \
\"a\": 0.0, \
\"b\": 1.0, \
\"c\": 2.0, \
\"d\": 3.0 \
} \
}";
gint
main (gint argc, gchar *argv[])
{
{
g_autoptr (FooObject) obj = NULL;
g_autofree gchar *data = NULL;
obj = foo_object_new ();
foo_object_dummy_data (obj);
data = foo_object_serialize (obj);
g_print ("%s\n", data);
}
{
g_autoptr (FooObject) obj = NULL;
g_autofree gchar *data = NULL;
obj = foo_object_new ();
foo_object_deserialize (obj, json);
/*obj = foo_gobject_from_data (json);*/
/*obj = FOO_OBJECT (json_gobject_from_data (FOO_TYPE_OBJECT, json, -1, NULL));*/
data = foo_object_serialize (obj);
g_print ("%s\n", data);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment