--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/glib/libglib/src/gdataset.c Tue Feb 02 02:01:42 2010 +0200
@@ -0,0 +1,794 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
+ * Copyright (C) 1998 Tim Janik
+ * Portions copyright (c) 2006 Nokia Corporation. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+/*
+ * MT safe ; except for g_data*_foreach()
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "glib.h"
+#include "galias.h"
+#include "gdatasetprivate.h"
+
+#ifdef __SYMBIAN32__
+#include <glib_wsd.h>
+#endif /* __SYMBIAN32__ */
+
+#if EMULATOR
+#define g_thread_functions_for_glib_use (*_g_thread_functions_for_glib_use())
+#define g_thread_use_default_impl (*_g_thread_use_default_impl())
+#endif /* EMULATOR */
+
+/* --- defines --- */
+#define G_QUARK_BLOCK_SIZE (512)
+
+/* datalist pointer accesses vae to be carried out atomically */
+#define G_DATALIST_GET_POINTER(datalist) \
+ ((GData*) ((gsize) g_atomic_pointer_get ((gpointer*) datalist) & ~(gsize) G_DATALIST_FLAGS_MASK))
+
+#define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \
+ gpointer _oldv, _newv; \
+ do { \
+ _oldv = g_atomic_pointer_get (datalist); \
+ _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK) | (gsize) pointer); \
+ } while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, _oldv, _newv)); \
+} G_STMT_END
+
+/* --- structures --- */
+#if !(EMULATOR)
+typedef struct _GDataset GDataset;
+#endif /* EMULATOR */
+struct _GData
+{
+ GData *next;
+ GQuark id;
+ gpointer data;
+ GDestroyNotify destroy_func;
+};
+
+#if !(EMULATOR)
+struct _GDataset
+{
+ gconstpointer location;
+ GData *datalist;
+};
+#endif /* EMULATOR */
+
+
+/* --- prototypes --- */
+static inline GDataset* g_dataset_lookup (gconstpointer dataset_location);
+static inline void g_datalist_clear_i (GData **datalist);
+static void g_dataset_destroy_internal (GDataset *dataset);
+static inline gpointer g_data_set_internal (GData **datalist,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func,
+ GDataset *dataset);
+static void g_data_initialize (void);
+static inline GQuark g_quark_new (gchar *string);
+
+
+/* --- variables --- */
+#if EMULATOR
+
+PLS_MACRO(g_dataset_global,gdataset,GStaticMutex)
+PLS(g_dataset_location_ht,gdataset,GHashTable *)
+PLS(g_dataset_cached,gdataset,GDataset *)
+PLS_MACRO(g_quark_global,gdataset,GStaticMutex)
+PLS(g_quark_ht,gdataset,GHashTable *)
+PLS(g_quarks,gdataset,gchar **)
+PLS(g_quark_seq_id,gdataset,GQuark)
+
+#define g__g_dataset_global_lock (*FUNCTION_NAME_MACRO(g_dataset_global,gdataset)())
+#define g_dataset_location_ht (*FUNCTION_NAME(g_dataset_location_ht,gdataset)())
+#define g_dataset_cached (*FUNCTION_NAME(g_dataset_cached,gdataset)())
+#define g__g_quark_global_lock (*FUNCTION_NAME_MACRO(g_quark_global,gdataset)())
+#define g_quark_ht (*FUNCTION_NAME(g_quark_ht,gdataset)())
+#define g_quarks (*FUNCTION_NAME(g_quarks,gdataset)())
+#define g_quark_seq_id (*FUNCTION_NAME(g_quark_seq_id,gdataset)())
+
+#else
+
+G_LOCK_DEFINE_STATIC (g_dataset_global);
+static GHashTable *g_dataset_location_ht = NULL;
+static GDataset *g_dataset_cached = NULL; /* should this be
+ threadspecific? */
+G_LOCK_DEFINE_STATIC (g_quark_global);
+static GHashTable *g_quark_ht = NULL;
+static gchar **g_quarks = NULL;
+static GQuark g_quark_seq_id = 0;
+
+#endif /* EMULATOR */
+
+/* --- functions --- */
+
+/* HOLDS: g_dataset_global_lock */
+static inline void
+g_datalist_clear_i (GData **datalist)
+{
+ register GData *list;
+
+ /* unlink *all* items before walking their destructors
+ */
+ list = G_DATALIST_GET_POINTER (datalist);
+ G_DATALIST_SET_POINTER (datalist, NULL);
+
+ while (list)
+ {
+ register GData *prev;
+
+ prev = list;
+ list = prev->next;
+
+ if (prev->destroy_func)
+ {
+ G_UNLOCK (g_dataset_global);
+ prev->destroy_func (prev->data);
+ G_LOCK (g_dataset_global);
+ }
+
+ g_slice_free (GData, prev);
+ }
+}
+
+EXPORT_C void
+g_datalist_clear (GData **datalist)
+{
+ g_return_if_fail (datalist != NULL);
+
+ G_LOCK (g_dataset_global);
+ if (!g_dataset_location_ht)
+ g_data_initialize ();
+
+ while (G_DATALIST_GET_POINTER (datalist))
+ g_datalist_clear_i (datalist);
+ G_UNLOCK (g_dataset_global);
+}
+
+/* HOLDS: g_dataset_global_lock */
+static inline GDataset*
+g_dataset_lookup (gconstpointer dataset_location)
+{
+ register GDataset *dataset;
+
+ if (g_dataset_cached && g_dataset_cached->location == dataset_location)
+ return g_dataset_cached;
+
+ dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
+ if (dataset)
+ g_dataset_cached = dataset;
+
+ return dataset;
+}
+
+/* HOLDS: g_dataset_global_lock */
+static void
+g_dataset_destroy_internal (GDataset *dataset)
+{
+ register gconstpointer dataset_location;
+
+ dataset_location = dataset->location;
+ while (dataset)
+ {
+ if (!dataset->datalist)
+ {
+ if (dataset == g_dataset_cached)
+ g_dataset_cached = NULL;
+ g_hash_table_remove (g_dataset_location_ht, dataset_location);
+ g_slice_free (GDataset, dataset);
+ break;
+ }
+
+ g_datalist_clear_i (&dataset->datalist);
+ dataset = g_dataset_lookup (dataset_location);
+ }
+}
+
+EXPORT_C void
+g_dataset_destroy (gconstpointer dataset_location)
+{
+ g_return_if_fail (dataset_location != NULL);
+
+ G_LOCK (g_dataset_global);
+ if (g_dataset_location_ht)
+ {
+ register GDataset *dataset;
+
+ dataset = g_dataset_lookup (dataset_location);
+ if (dataset)
+ g_dataset_destroy_internal (dataset);
+ }
+ G_UNLOCK (g_dataset_global);
+}
+
+/* HOLDS: g_dataset_global_lock */
+static inline gpointer
+g_data_set_internal (GData **datalist,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func,
+ GDataset *dataset)
+{
+ register GData *list;
+
+ list = G_DATALIST_GET_POINTER (datalist);
+ if (!data)
+ {
+ register GData *prev;
+
+ prev = NULL;
+ while (list)
+ {
+ if (list->id == key_id)
+ {
+ gpointer ret_data = NULL;
+
+ if (prev)
+ prev->next = list->next;
+ else
+ {
+ G_DATALIST_SET_POINTER (datalist, list->next);
+
+ /* the dataset destruction *must* be done
+ * prior to invocation of the data destroy function
+ */
+ if (!list->next && dataset)
+ g_dataset_destroy_internal (dataset);
+ }
+
+ /* the GData struct *must* already be unlinked
+ * when invoking the destroy function.
+ * we use (data==NULL && destroy_func!=NULL) as
+ * a special hint combination to "steal"
+ * data without destroy notification
+ */
+ if (list->destroy_func && !destroy_func)
+ {
+ G_UNLOCK (g_dataset_global);
+ list->destroy_func (list->data);
+ G_LOCK (g_dataset_global);
+ }
+ else
+ ret_data = list->data;
+
+ g_slice_free (GData, list);
+
+ return ret_data;
+ }
+
+ prev = list;
+ list = list->next;
+ }
+ }
+ else
+ {
+ while (list)
+ {
+ if (list->id == key_id)
+ {
+ if (!list->destroy_func)
+ {
+ list->data = data;
+ list->destroy_func = destroy_func;
+ }
+ else
+ {
+ register GDestroyNotify dfunc;
+ register gpointer ddata;
+
+ dfunc = list->destroy_func;
+ ddata = list->data;
+ list->data = data;
+ list->destroy_func = destroy_func;
+
+ /* we need to have updated all structures prior to
+ * invocation of the destroy function
+ */
+ G_UNLOCK (g_dataset_global);
+ dfunc (ddata);
+ G_LOCK (g_dataset_global);
+ }
+
+ return NULL;
+ }
+
+ list = list->next;
+ }
+
+
+ list = g_slice_new (GData);
+
+ list->next = G_DATALIST_GET_POINTER (datalist);
+ list->id = key_id;
+ list->data = data;
+ list->destroy_func = destroy_func;
+ G_DATALIST_SET_POINTER (datalist, list);
+ }
+
+ return NULL;
+}
+
+EXPORT_C void
+g_dataset_id_set_data_full (gconstpointer dataset_location,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func)
+{
+ register GDataset *dataset;
+
+ g_return_if_fail (dataset_location != NULL);
+ if (!data)
+ g_return_if_fail (destroy_func == NULL);
+ if (!key_id)
+ {
+ if (data)
+ g_return_if_fail (key_id > 0);
+ else
+ return;
+ }
+
+ G_LOCK (g_dataset_global);
+ if (!g_dataset_location_ht)
+ g_data_initialize ();
+
+ dataset = g_dataset_lookup (dataset_location);
+ if (!dataset)
+ {
+ dataset = g_slice_new (GDataset);
+ dataset->location = dataset_location;
+ g_datalist_init (&dataset->datalist);
+ g_hash_table_insert (g_dataset_location_ht,
+ (gpointer) dataset->location,
+ dataset);
+ }
+
+ g_data_set_internal (&dataset->datalist, key_id, data, destroy_func, dataset);
+ G_UNLOCK (g_dataset_global);
+}
+
+EXPORT_C void
+g_datalist_id_set_data_full (GData **datalist,
+ GQuark key_id,
+ gpointer data,
+ GDestroyNotify destroy_func)
+{
+ g_return_if_fail (datalist != NULL);
+ if (!data)
+ g_return_if_fail (destroy_func == NULL);
+ if (!key_id)
+ {
+ if (data)
+ g_return_if_fail (key_id > 0);
+ else
+ return;
+ }
+
+ G_LOCK (g_dataset_global);
+ if (!g_dataset_location_ht)
+ g_data_initialize ();
+
+ g_data_set_internal (datalist, key_id, data, destroy_func, NULL);
+ G_UNLOCK (g_dataset_global);
+}
+
+EXPORT_C gpointer
+g_dataset_id_remove_no_notify (gconstpointer dataset_location,
+ GQuark key_id)
+{
+ gpointer ret_data = NULL;
+
+ g_return_val_if_fail (dataset_location != NULL, NULL);
+
+ G_LOCK (g_dataset_global);
+ if (key_id && g_dataset_location_ht)
+ {
+ GDataset *dataset;
+
+ dataset = g_dataset_lookup (dataset_location);
+ if (dataset)
+ ret_data = g_data_set_internal (&dataset->datalist, key_id, NULL, (GDestroyNotify) 42, dataset);
+ }
+ G_UNLOCK (g_dataset_global);
+
+ return ret_data;
+}
+
+EXPORT_C gpointer
+g_datalist_id_remove_no_notify (GData **datalist,
+ GQuark key_id)
+{
+ gpointer ret_data = NULL;
+
+ g_return_val_if_fail (datalist != NULL, NULL);
+
+ G_LOCK (g_dataset_global);
+ if (key_id && g_dataset_location_ht)
+ ret_data = g_data_set_internal (datalist, key_id, NULL, (GDestroyNotify) 42, NULL);
+ G_UNLOCK (g_dataset_global);
+
+ return ret_data;
+}
+
+EXPORT_C gpointer
+g_dataset_id_get_data (gconstpointer dataset_location,
+ GQuark key_id)
+{
+ g_return_val_if_fail (dataset_location != NULL, NULL);
+
+ G_LOCK (g_dataset_global);
+ if (key_id && g_dataset_location_ht)
+ {
+ register GDataset *dataset;
+
+ dataset = g_dataset_lookup (dataset_location);
+ if (dataset)
+ {
+ register GData *list;
+
+ for (list = dataset->datalist; list; list = list->next)
+ if (list->id == key_id)
+ {
+ G_UNLOCK (g_dataset_global);
+ return list->data;
+ }
+ }
+ }
+ G_UNLOCK (g_dataset_global);
+
+ return NULL;
+}
+
+EXPORT_C gpointer
+g_datalist_id_get_data (GData **datalist,
+ GQuark key_id)
+{
+ gpointer data = NULL;
+ g_return_val_if_fail (datalist != NULL, NULL);
+ if (key_id)
+ {
+ register GData *list;
+ G_LOCK (g_dataset_global);
+ for (list = G_DATALIST_GET_POINTER (datalist); list; list = list->next)
+ if (list->id == key_id)
+ {
+ data = list->data;
+ break;
+ }
+ G_UNLOCK (g_dataset_global);
+ }
+ return data;
+}
+
+EXPORT_C void
+g_dataset_foreach (gconstpointer dataset_location,
+ GDataForeachFunc func,
+ gpointer user_data)
+{
+ register GDataset *dataset;
+
+ g_return_if_fail (dataset_location != NULL);
+ g_return_if_fail (func != NULL);
+
+ G_LOCK (g_dataset_global);
+ if (g_dataset_location_ht)
+ {
+ dataset = g_dataset_lookup (dataset_location);
+ G_UNLOCK (g_dataset_global);
+ if (dataset)
+ {
+ register GData *list, *next;
+
+ for (list = dataset->datalist; list; list = next)
+ {
+ next = list->next;
+ func (list->id, list->data, user_data);
+ }
+ }
+ }
+ else
+ {
+ G_UNLOCK (g_dataset_global);
+ }
+}
+
+EXPORT_C void
+g_datalist_foreach (GData **datalist,
+ GDataForeachFunc func,
+ gpointer user_data)
+{
+ register GData *list, *next;
+
+ g_return_if_fail (datalist != NULL);
+ g_return_if_fail (func != NULL);
+
+ for (list = G_DATALIST_GET_POINTER (datalist); list; list = next)
+ {
+ next = list->next;
+ func (list->id, list->data, user_data);
+ }
+}
+
+EXPORT_C void
+g_datalist_init (GData **datalist)
+{
+ g_return_if_fail (datalist != NULL);
+
+ g_atomic_pointer_set ((gpointer*) datalist, NULL);
+}
+
+/**
+ * g_datalist_set_flags:
+ * @datalist: pointer to the location that holds a list
+ * @flags: the flags to turn on. The values of the flags are
+ * restricted by %G_DATALIST_FLAGS_MASK (currently
+ * 3; giving two possible boolean flags).
+ * A value for @flags that doesn't fit within the mask is
+ * an error.
+ *
+ * Turns on flag values for a data list. This function is used
+ * to keep a small number of boolean flags in an object with
+ * a data list without using any additional space. It is
+ * not generally useful except in circumstances where space
+ * is very tight. (It is used in the base #GObject type, for
+ * example.)
+ *
+ * Since: 2.8
+ **/
+EXPORT_C void
+g_datalist_set_flags (GData **datalist,
+ guint flags)
+{
+ gpointer oldvalue;
+ g_return_if_fail (datalist != NULL);
+ g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
+
+ do
+ {
+ oldvalue = g_atomic_pointer_get (datalist);
+ }
+ while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
+ (gpointer) ((gsize) oldvalue | flags)));
+}
+
+/**
+ * g_datalist_unset_flags:
+ * @datalist: pointer to the location that holds a list
+ * @flags: the flags to turn off. The values of the flags are
+ * restricted by %G_DATALIST_FLAGS_MASK (currently
+ * 3: giving two possible boolean flags).
+ * A value for @flags that doesn't fit within the mask is
+ * an error.
+ *
+ * Turns off flag values for a data list. See g_datalist_unset_flags()
+ *
+ * Since: 2.8
+ **/
+EXPORT_C void
+g_datalist_unset_flags (GData **datalist,
+ guint flags)
+{
+ gpointer oldvalue;
+ g_return_if_fail (datalist != NULL);
+ g_return_if_fail ((flags & ~G_DATALIST_FLAGS_MASK) == 0);
+
+ do
+ {
+ oldvalue = g_atomic_pointer_get (datalist);
+ }
+ while (!g_atomic_pointer_compare_and_exchange ((void**) datalist, oldvalue,
+ (gpointer) ((gsize) oldvalue & ~(gsize) flags)));
+}
+
+/**
+ * g_datalist_get_flags:
+ * @datalist: pointer to the location that holds a list
+ *
+ * Gets flags values packed in together with the datalist.
+ * See g_datalist_set_flags().
+ *
+ * Return value: the flags of the datalist
+ *
+ * Since: 2.8
+ **/
+EXPORT_C guint
+g_datalist_get_flags (GData **datalist)
+{
+ g_return_val_if_fail (datalist != NULL, 0);
+
+ return G_DATALIST_GET_FLAGS (datalist); /* atomic macro */
+}
+
+/* HOLDS: g_dataset_global_lock */
+static void
+g_data_initialize (void)
+{
+ g_return_if_fail (g_dataset_location_ht == NULL);
+
+ g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
+ g_dataset_cached = NULL;
+}
+
+EXPORT_C GQuark
+g_quark_try_string (const gchar *string)
+{
+ GQuark quark = 0;
+ g_return_val_if_fail (string != NULL, 0);
+
+ G_LOCK (g_quark_global);
+ if (g_quark_ht)
+ quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+ G_UNLOCK (g_quark_global);
+
+ return quark;
+}
+
+/* HOLDS: g_quark_global_lock */
+static inline GQuark
+g_quark_from_string_internal (const gchar *string,
+ gboolean duplicate)
+{
+ GQuark quark = 0;
+
+ if (g_quark_ht)
+ quark = GPOINTER_TO_UINT (g_hash_table_lookup (g_quark_ht, string));
+
+ if (!quark)
+ quark = g_quark_new (duplicate ? g_strdup (string) : (gchar *)string);
+
+ return quark;
+}
+
+EXPORT_C GQuark
+g_quark_from_string (const gchar *string)
+{
+ GQuark quark;
+
+ g_return_val_if_fail (string != NULL, 0);
+
+ G_LOCK (g_quark_global);
+ quark = g_quark_from_string_internal (string, TRUE);
+ G_UNLOCK (g_quark_global);
+
+ return quark;
+}
+
+EXPORT_C GQuark
+g_quark_from_static_string (const gchar *string)
+{
+ GQuark quark;
+
+ g_return_val_if_fail (string != NULL, 0);
+
+ G_LOCK (g_quark_global);
+ quark = g_quark_from_string_internal (string, FALSE);
+ G_UNLOCK (g_quark_global);
+
+ return quark;
+}
+
+EXPORT_C G_CONST_RETURN gchar*
+g_quark_to_string (GQuark quark)
+{
+ gchar* result = NULL;
+
+ G_LOCK (g_quark_global);
+ if (quark < g_quark_seq_id)
+ result = g_quarks[quark];
+ G_UNLOCK (g_quark_global);
+
+ return result;
+}
+
+/* HOLDS: g_quark_global_lock */
+static inline GQuark
+g_quark_new (gchar *string)
+{
+ GQuark quark;
+
+ if (g_quark_seq_id % G_QUARK_BLOCK_SIZE == 0)
+ g_quarks = g_renew (gchar*, g_quarks, g_quark_seq_id + G_QUARK_BLOCK_SIZE);
+ if (!g_quark_ht)
+ {
+ g_assert (g_quark_seq_id == 0);
+ g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
+ g_quarks[g_quark_seq_id++] = NULL;
+ }
+
+ quark = g_quark_seq_id++;
+ g_quarks[quark] = string;
+ g_hash_table_insert (g_quark_ht, string, GUINT_TO_POINTER (quark));
+
+ return quark;
+}
+
+/**
+ * g_intern_string:
+ * @string: a string
+ *
+ * Returns a canonical representation for @string. Interned strings can
+ * be compared for equality by comparing the pointers, instead of using strcmp().
+ *
+ * Returns: a canonical representation for the string
+ *
+ * Since: 2.10
+ */
+EXPORT_C G_CONST_RETURN gchar*
+g_intern_string (const gchar *string)
+{
+ const gchar *result;
+ GQuark quark;
+
+ if (!string)
+ return NULL;
+
+ G_LOCK (g_quark_global);
+ quark = g_quark_from_string_internal (string, TRUE);
+ result = g_quarks[quark];
+ G_UNLOCK (g_quark_global);
+
+ return result;
+}
+
+/**
+ * g_intern_static_string:
+ * @string: a static string
+ *
+ * Returns a canonical representation for @string. Interned strings can
+ * be compared for equality by comparing the pointers, instead of using strcmp().
+ * g_intern_static_string() does not copy the string, therefore @string must
+ * not be freed or modified.
+ *
+ * Returns: a canonical representation for the string
+ *
+ * Since: 2.10
+ */
+EXPORT_C G_CONST_RETURN gchar*
+g_intern_static_string (const gchar *string)
+{
+ GQuark quark;
+ const gchar *result;
+
+ if (!string)
+ return NULL;
+
+ G_LOCK (g_quark_global);
+ quark = g_quark_from_string_internal (string, FALSE);
+ result = g_quarks[quark];
+ G_UNLOCK (g_quark_global);
+
+ return result;
+}
+
+
+
+#define __G_DATASET_C__
+#include "galiasdef.c"