[PATCH 3/5] core: made plugin registry handle itself key id assignments



Instead of relying on GQuarks, a similar mechanism is implemented in the plugin
registry. This gives more flexibility and allows  to #define the values of core
keys, which automatically give their symbols in GObject-introspection bindings.
---
 src/grl-plugin-registry.c |  229 +++++++++++++++++++++++++++++++--------------
 src/grl-plugin-registry.h |    8 ++-
 2 files changed, 166 insertions(+), 71 deletions(-)

diff --git a/src/grl-plugin-registry.c b/src/grl-plugin-registry.c
index a7d62ea..8a5f011 100644
--- a/src/grl-plugin-registry.c
+++ b/src/grl-plugin-registry.c
@@ -61,6 +61,13 @@ GRL_LOG_DOMAIN(plugin_registry_log_domain);
                                GRL_TYPE_PLUGIN_REGISTRY,        \
                                GrlPluginRegistryPrivate))
 
+/* GQuark-like implementation, where we manually assign the first IDs. */
+struct IDHandler {
+  GHashTable *string_to_id;
+  GArray *id_to_string;
+  gint last_id;
+};
+
 struct _GrlPluginRegistryPrivate {
   GHashTable *configs;
   GHashTable *plugins;
@@ -70,11 +77,17 @@ struct _GrlPluginRegistryPrivate {
   GParamSpecPool *system_keys;
   GHashTable *ranks;
   GSList *plugins_dir;
+  struct IDHandler id_handler;
 };
 
 static void grl_plugin_registry_setup_ranks (GrlPluginRegistry *registry);
 static void grl_plugin_registry_load_plugin_infos (GrlPluginRegistry *registry);
 
+static void id_handler_init (struct IDHandler *handler);
+static GrlKeyID id_handler_get_key (struct IDHandler *handler, const gchar *key_name);
+static const gchar *id_handler_get_name (struct IDHandler *handler, GrlKeyID key);
+static GrlKeyID id_handler_add (struct IDHandler *handler, GrlKeyID key, const gchar *key_name);
+
 /* ================ GrlPluginRegistry GObject ================ */
 
 enum {
@@ -144,6 +157,8 @@ grl_plugin_registry_init (GrlPluginRegistry *registry)
   registry->priv->system_keys =
     g_param_spec_pool_new (FALSE);
 
+  id_handler_init (&registry->priv->id_handler);
+
   grl_plugin_registry_setup_ranks (registry);
   grl_plugin_registry_load_plugin_infos (registry);
 }
@@ -315,6 +330,97 @@ grl_plugin_registry_load_plugin_infos (GrlPluginRegistry *registry)
   g_dir_close (dir);
 }
 
+static void
+id_handler_init (struct IDHandler *handler)
+{
+  const gchar *null_string = NULL;
+  handler->string_to_id = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  handler->id_to_string = g_array_new (FALSE, /* zero terminated */
+                                       TRUE,  /* zero-initialised */
+                                       sizeof (const gchar *));
+  /* We want indices in ->id_to_string to start from 1, so we add a NULL entry
+   * for GRL_METADATA_KEY_INVALID (i.e. 0) */
+  g_array_insert_val (handler->id_to_string,
+                      GRL_METADATA_KEY_INVALID,
+                      null_string);
+}
+
+static
+GrlKeyID id_handler_get_key (struct IDHandler *handler, const gchar *key_name)
+{
+  gpointer val = g_hash_table_lookup (handler->string_to_id, key_name);
+  if (val == NULL)
+    return GRL_METADATA_KEY_INVALID;
+
+  return GRLPOINTER_TO_KEYID (val);
+}
+
+static const gchar *
+id_handler_get_name (struct IDHandler *handler, GrlKeyID key)
+{
+  if (key < handler->id_to_string->len)
+    return g_array_index (handler->id_to_string, const gchar *, key);
+
+  return NULL;
+}
+
+/**
+ * id_handler_add:
+ * @handler: the handler
+ * @key: a specific key for system keys, or GRL_METADATA_KEY_INVALID for it to
+ * be assigned
+ * @name: the name of the key.
+ *
+ * Add a new key<->name correspondence.
+ *
+ * Returns: the new key number, or GRL_METADATA_KEY_INVALID if the key could
+ * not be created (typically if @key or @name is already registered).
+ */
+static GrlKeyID
+id_handler_add (struct IDHandler *handler, GrlKeyID key, const gchar *name)
+{
+  GrlKeyID _key = key;
+
+  if (_key == GRL_METADATA_KEY_INVALID) {
+    /* existing keys go from 1 to (id_to_string->len - 1), so the next
+     * available key is id_to_string->len, which will be incremented by
+     * g_array_insert_val() */
+    _key = handler->id_to_string->len;
+  }
+
+  if (NULL != id_handler_get_name (handler, _key)) {
+    GRL_WARNING ("Cannot register %d:%s because key is already defined as %s",
+                 _key, name, id_handler_get_name (handler, _key));
+    return GRL_METADATA_KEY_INVALID;
+  } else if ( GRL_METADATA_KEY_INVALID != id_handler_get_key (handler, name)) {
+    /* _key or name is already in use! */
+    GRL_WARNING ("Cannot register %d:%s because name is already registered with key %d",
+                 _key, name, id_handler_get_key (handler, name));
+    return GRL_METADATA_KEY_INVALID;
+  } else {
+    /* name_copy is shared between handler->id_to_string and
+     * handler->string_to_id */
+    gchar *name_copy = g_strdup (name);
+
+    if (_key >= handler->id_to_string->len)
+      g_array_set_size (handler->id_to_string, _key + 1);
+
+    /* yes, g_array_index() is a macro that give you an lvalue */
+    g_array_index (handler->id_to_string, const gchar *, _key) = name_copy;
+    g_hash_table_insert (handler->string_to_id,
+                         name_copy, GRLKEYID_TO_POINTER (_key));
+  }
+
+  return _key;
+
+}
+
+static GList *
+id_handler_get_all_keys (struct IDHandler *handler)
+{
+  return g_hash_table_get_values (handler->string_to_id);
+}
+
 /* ================ API ================ */
 
 /**
@@ -951,7 +1057,7 @@ grl_plugin_registry_unload (GrlPluginRegistry *registry,
 /**
  * grl_plugin_registry_register_metadata_key:
  * @registry: The plugin registry
- * @key: The key to register
+ * @param_spec: The definition of the key to register
  * @error: error return location or @NULL to ignore
  *
  * Registers a metadata key
@@ -962,41 +1068,63 @@ grl_plugin_registry_unload (GrlPluginRegistry *registry,
  */
 GrlKeyID
 grl_plugin_registry_register_metadata_key (GrlPluginRegistry *registry,
-                                           GParamSpec *key,
+                                           GParamSpec *param_spec,
                                            GError **error)
 {
+  return grl_plugin_registry_register_metadata_key_full (registry,
+                                                         param_spec,
+                                                         GRL_METADATA_KEY_INVALID,
+                                                         error);
+}
+
+/* internal! */
+/**
+ * grl_plugin_registry_register_metadata_key_full: (skip)
+ *
+ * This is an internal method only meant to be used to register core keys.
+ * Plugin developers should use grl_plugin_registry_register_metadata_key().
+ *
+ */
+GrlKeyID
+grl_plugin_registry_register_metadata_key_full (GrlPluginRegistry *registry,
+                                                GParamSpec *param_spec,
+                                                GrlKeyID key,
+                                                GError **error)
+{
   const gchar *key_name;
 
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), 0);
-  g_return_val_if_fail (G_IS_PARAM_SPEC (key), 0);
+  g_return_val_if_fail (G_IS_PARAM_SPEC (param_spec), 0);
+  GrlKeyID registered_key;
 
-  key_name = g_param_spec_get_name (key);
+  key_name = g_param_spec_get_name (param_spec);
 
-  /* Check if key is already registered */
-  if (g_param_spec_pool_lookup (registry->priv->system_keys,
-                                key_name,
-                                GRL_TYPE_MEDIA,
-                                FALSE)) {
-    GRL_WARNING ("metadata key '%s' already registered",
-                 g_param_spec_get_name (key));
+  registered_key = id_handler_add (&registry->priv->id_handler, key, key_name);
+
+  if (registered_key == GRL_METADATA_KEY_INVALID) {
+    GRL_WARNING ("metadata key '%s' cannot be registered", key_name);
     g_set_error (error,
                  GRL_CORE_ERROR,
                  GRL_CORE_ERROR_REGISTER_METADATA_KEY_FAILED,
-                 "Metadata key '%s' was already registered",
-                 g_param_spec_get_name (key));
-    return 0;
-  } else {
-    g_param_spec_pool_insert (registry->priv->system_keys,
-                              key,
-                              GRL_TYPE_MEDIA);
-    /* Each key is related with itself */
-    g_hash_table_insert (registry->priv->related_keys,
-                         GRLKEYID_TO_POINTER (key),
-                         g_list_prepend (NULL, key));
-    return (GrlKeyID) g_quark_from_static_string (key_name);
+                 "Metadata key '%s' cannot be registered",
+                 key_name);
+
+    return GRL_METADATA_KEY_INVALID;
   }
+
+  g_param_spec_pool_insert (registry->priv->system_keys,
+                            param_spec,
+                            GRL_TYPE_MEDIA);
+  /* Each key is related to itself */
+  g_hash_table_insert (registry->priv->related_keys,
+                       GRLKEYID_TO_POINTER (registered_key),
+                       g_list_prepend (NULL,
+                                       GRLKEYID_TO_POINTER (registered_key)));
+
+  return registered_key;
 }
 
+
 /**
  * grl_plugin_registry_register_metadata_key_relation:
  * @registry: the plugin registry
@@ -1057,7 +1185,7 @@ grl_plugin_registry_register_metadata_key_relation (GrlPluginRegistry *registry,
  *
  * Look up for the metadata key with name @key_name.
  *
- * Returns: The metadata key, or 0 if not found
+ * Returns: The metadata key, or GRL_METADATA_KEY_INVALID if not found
  *
  * Since: 0.1.6
  */
@@ -1068,14 +1196,7 @@ grl_plugin_registry_lookup_metadata_key (GrlPluginRegistry *registry,
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), 0);
   g_return_val_if_fail (key_name, 0);
 
-  if (g_param_spec_pool_lookup (registry->priv->system_keys,
-                                key_name,
-                                GRL_TYPE_MEDIA,
-                                FALSE)) {
-    return (GrlKeyID) g_quark_try_string (key_name);
-  } else {
-    return 0;
-  }
+  return id_handler_get_key (&registry->priv->id_handler, key_name);
 }
 
 /**
@@ -1091,24 +1212,9 @@ const gchar *
 grl_plugin_registry_lookup_metadata_key_name (GrlPluginRegistry *registry,
                                               GrlKeyID key)
 {
-  const gchar *key_name;
-  GParamSpec *key_pspec;
-
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), 0);
 
-  key_name = g_quark_to_string (key);
-  if (!key_name) {
-    return NULL;
-  }
-  key_pspec = g_param_spec_pool_lookup (registry->priv->system_keys,
-                                        key_name,
-                                        GRL_TYPE_MEDIA,
-                                        FALSE);
-  if (key_pspec) {
-    return g_param_spec_get_name (key_pspec);
-  } else {
-    return NULL;
-  }
+  return id_handler_get_name (&registry->priv->id_handler, key);
 }
 
 /**
@@ -1129,7 +1235,7 @@ grl_plugin_registry_lookup_metadata_key_desc (GrlPluginRegistry *registry,
 
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), 0);
 
-  key_name = g_quark_to_string (key);
+  key_name = id_handler_get_name (&registry->priv->id_handler, key);
   if (!key_name) {
     return NULL;
   }
@@ -1162,7 +1268,7 @@ grl_plugin_registry_lookup_metadata_key_type (GrlPluginRegistry *registry,
 
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), 0);
 
-  key_name = g_quark_to_string (key);
+  key_name = id_handler_get_name (&registry->priv->id_handler, key);
   if (!key_name) {
     return G_TYPE_INVALID;
   }
@@ -1200,7 +1306,7 @@ grl_plugin_registry_metadata_key_validate (GrlPluginRegistry *registry,
   g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), FALSE);
   g_return_val_if_fail (G_IS_VALUE (value), FALSE);
 
-  key_name = g_quark_to_string (key);
+  key_name = id_handler_get_name (&registry->priv->id_handler, key);
   if (!key_name) {
     return FALSE;
   }
@@ -1244,7 +1350,7 @@ grl_plugin_registry_lookup_metadata_key_relation (GrlPluginRegistry *registry,
  *
  * Returns a list with all registered keys in system.
  *
- * Returns: (transfer container): a #GList with all the available
+ * Returns: (transfer container) (element-type GrlKeyID): a #GList with all the available
  * #GrlKeyID<!-- -->s. The content of the list should not be modified or freed.
  * Use g_list_free() when done using the list.
  *
@@ -1253,24 +1359,7 @@ grl_plugin_registry_lookup_metadata_key_relation (GrlPluginRegistry *registry,
 GList *
 grl_plugin_registry_get_metadata_keys (GrlPluginRegistry *registry)
 {
-  GList *key_list = NULL;
-  GParamSpec **keys;
-  guint i;
-  guint keys_length;
-
-  g_return_val_if_fail (GRL_IS_PLUGIN_REGISTRY (registry), NULL);
-
-  keys = g_param_spec_pool_list (registry->priv->system_keys,
-                                 GRL_TYPE_MEDIA,
-                                 &keys_length);
-
-  for (i = 0; i < keys_length; i++) {
-    key_list = g_list_prepend (key_list, GRLKEYID_TO_POINTER (keys[i]));
-  }
-
-  g_free (keys);
-
-  return key_list;
+  return id_handler_get_all_keys (&registry->priv->id_handler);
 }
 
 /**
diff --git a/src/grl-plugin-registry.h b/src/grl-plugin-registry.h
index 2f5e641..39b5742 100644
--- a/src/grl-plugin-registry.h
+++ b/src/grl-plugin-registry.h
@@ -244,9 +244,15 @@ GList *grl_plugin_registry_get_sources_by_operations (GrlPluginRegistry *registr
                                                                 gboolean ranked);
 
 GrlKeyID grl_plugin_registry_register_metadata_key (GrlPluginRegistry *registry,
-                                                    GParamSpec *key,
+                                                    GParamSpec *param_spec,
                                                     GError **error);
 
+/* internal! FIXME: put in a separate header */
+GrlKeyID grl_plugin_registry_register_metadata_key_full (GrlPluginRegistry *registry,
+                                                         GParamSpec *param_spec,
+                                                         GrlKeyID key,
+                                                         GError **error);
+
 void grl_plugin_registry_register_metadata_key_relation (GrlPluginRegistry *registry,
                                                          GrlKeyID key1,
                                                          GrlKeyID key2);
-- 
1.7.1



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