changelog updates
[platform/upstream/glib.git] / gdataset.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gdataset.c: Generic dataset mechanism, similar to GtkObject data.
5  * Copyright (C) 1998 Tim Janik
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
20  */
21 #include        <string.h>
22 #include        "glib.h"
23
24
25
26 /* --- defines --- */
27 #define G_DATASET_BLOCK_SIZE                    (512)
28 #define G_DATASET_MEM_CHUNK_PREALLOC            (64)
29 #define G_DATASET_DATA_MEM_CHUNK_PREALLOC       (128)
30
31
32 /* --- structures --- */
33 typedef struct _GDatasetData GDatasetData;
34 typedef struct _GDataset GDataset;
35 struct _GDatasetData
36 {
37   GDatasetData *next;
38   guint id;
39   gpointer data;
40   GDestroyNotify destroy_func;
41 };
42
43 struct _GDataset
44 {
45   gconstpointer location;
46   GDatasetData *data_list;
47 };
48
49
50 /* --- prototypes --- */
51 static inline GDataset* g_dataset_lookup        (gconstpointer dataset_location);
52 static inline void      g_dataset_destroy_i     (GDataset     *dataset);
53 static void             g_dataset_initialize    (void);
54 static inline GQuark    g_quark_new             (const gchar  *string);
55
56
57 /* --- variables --- */
58 static GHashTable   *g_quark_ht = NULL;
59 static gchar       **g_quarks = NULL;
60 static GQuark        g_quark_seq_id = 0;
61 static GHashTable   *g_dataset_location_ht = NULL;
62 static GDataset     *g_dataset_cached = NULL;
63 static GMemChunk    *g_dataset_mem_chunk = NULL;
64 static GMemChunk    *g_dataset_data_mem_chunk = NULL;
65
66
67
68 /* --- functions --- */
69 static inline GDataset*
70 g_dataset_lookup (gconstpointer dataset_location)
71 {
72   register GDataset *dataset;
73   
74   if (g_dataset_cached && g_dataset_cached->location == dataset_location)
75     return g_dataset_cached;
76   
77   if (!g_dataset_location_ht)
78     g_dataset_initialize ();
79   
80   dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
81   if (dataset)
82     g_dataset_cached = dataset;
83   
84   return dataset;
85 }
86
87 static inline void
88 g_dataset_destroy_i (GDataset *dataset)
89 {
90   register GDatasetData *list;
91   
92   if (dataset == g_dataset_cached)
93     g_dataset_cached = NULL;
94   g_hash_table_remove (g_dataset_location_ht, dataset->location);
95   
96   list = dataset->data_list;
97   g_mem_chunk_free (g_dataset_mem_chunk, dataset);
98   
99   while (list)
100     {
101       register GDatasetData *prev;
102       
103       prev = list;
104       list = prev->next;
105       
106       if (prev->destroy_func)
107         prev->destroy_func (prev->data);
108       
109       g_mem_chunk_free (g_dataset_data_mem_chunk, prev);
110     }
111 }
112
113 void
114 g_dataset_destroy (gconstpointer  dataset_location)
115 {
116   register GDataset *dataset;
117   
118   g_return_if_fail (dataset_location != NULL);
119   
120   dataset = g_dataset_lookup (dataset_location);
121   if (dataset)
122     g_dataset_destroy_i (dataset);
123 }
124
125 void
126 g_dataset_id_set_destroy (gconstpointer  dataset_location,
127                           GQuark         key_id,
128                           GDestroyNotify destroy_func)
129 {
130   g_return_if_fail (dataset_location != NULL);
131   
132   if (key_id)
133     {
134       register GDataset *dataset;
135       
136       dataset = g_dataset_lookup (dataset_location);
137       if (dataset)
138         {
139           register GDatasetData *list;
140           
141           list = dataset->data_list;
142           while (list)
143             {
144               if (list->id == key_id)
145                 {
146                   list->destroy_func = destroy_func;
147                   return;
148                 }
149             }
150         }
151     }
152 }
153
154 gpointer
155 g_dataset_id_get_data (gconstpointer  dataset_location,
156                        GQuark         key_id)
157 {
158   g_return_val_if_fail (dataset_location != NULL, NULL);
159   
160   if (key_id)
161     {
162       register GDataset *dataset;
163       
164       dataset = g_dataset_lookup (dataset_location);
165       if (dataset)
166         {
167           register GDatasetData *list;
168           
169           for (list = dataset->data_list; list; list = list->next)
170             if (list->id == key_id)
171               return list->data;
172         }
173     }
174   
175   return NULL;
176 }
177
178 void
179 g_dataset_id_set_data_full (gconstpointer  dataset_location,
180                             GQuark         key_id,
181                             gpointer       data,
182                             GDestroyNotify destroy_func)
183 {
184   register GDataset *dataset;
185   register GDatasetData *list;
186   
187   g_return_if_fail (dataset_location != NULL);
188   g_return_if_fail (key_id > 0);
189   
190   dataset = g_dataset_lookup (dataset_location);
191   if (!dataset)
192     {
193       dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
194       dataset->location = dataset_location;
195       dataset->data_list = NULL;
196       g_hash_table_insert (g_dataset_location_ht, 
197                            (gpointer) dataset->location, /* Yuck */
198                            dataset);
199     }
200   
201   list = dataset->data_list;
202   if (!data)
203     {
204       register GDatasetData *prev;
205       
206       prev = NULL;
207       while (list)
208         {
209           if (list->id == key_id)
210             {
211               if (prev)
212                 prev->next = list->next;
213               else
214                 {
215                   dataset->data_list = list->next;
216                   
217                   if (!dataset->data_list)
218                     g_dataset_destroy_i (dataset);
219                 }
220               
221               /* we need to have unlinked before invoking the destroy function
222                */
223               if (list->destroy_func)
224                 list->destroy_func (list->data);
225               
226               g_mem_chunk_free (g_dataset_data_mem_chunk, list);
227
228               return;
229             }
230           
231           prev = list;
232           list = list->next;
233         }
234     }
235   else
236     {
237       while (list)
238         {
239           if (list->id == key_id)
240             {
241               register GDestroyNotify dfunc;
242               register gpointer ddata;
243               
244               dfunc = list->destroy_func;
245               ddata = list->data;
246               list->data = data;
247               list->destroy_func = destroy_func;
248               
249               /* we need to have updated all structures prior to
250                * invokation of the destroy function
251                */
252               if (dfunc)
253                 dfunc (ddata);
254
255               return;
256             }
257           
258           list = list->next;
259         }
260       
261       list = g_chunk_new (GDatasetData, g_dataset_data_mem_chunk);
262       list->next = dataset->data_list;
263       list->id = key_id;
264       list->data = data;
265       list->destroy_func = destroy_func;
266       dataset->data_list = list;
267     }
268 }
269
270 static void
271 g_dataset_initialize (void)
272 {
273   if (!g_dataset_location_ht)
274     {
275       g_quark_ht = g_hash_table_new (g_str_hash, g_str_equal);
276       g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
277       g_dataset_cached = NULL;
278       g_dataset_mem_chunk =
279         g_mem_chunk_new ("GDataset MemChunk",
280                          sizeof (GDataset),
281                          sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
282                          G_ALLOC_AND_FREE);
283       g_dataset_data_mem_chunk =
284         g_mem_chunk_new ("GDatasetData MemChunk",
285                          sizeof (GDatasetData),
286                          sizeof (GDatasetData) * G_DATASET_DATA_MEM_CHUNK_PREALLOC,
287                          G_ALLOC_AND_FREE);
288     }
289 }
290
291 GQuark
292 g_quark_try_string (const gchar *string)
293 {
294   g_return_val_if_fail (string != NULL, 0);
295   
296   if (g_quark_ht)
297     return (gulong) g_hash_table_lookup (g_quark_ht, string);
298   else
299     return 0;
300 }
301
302 GQuark
303 g_quark_from_string (const gchar *string)
304 {
305   GQuark quark;
306   
307   g_return_val_if_fail (string != NULL, 0);
308   
309   if (!g_quark_ht)
310     g_dataset_initialize ();
311   
312   quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
313   if (!quark)
314     quark = g_quark_new (g_strdup (string));
315   
316   return quark;
317 }
318
319 GQuark
320 g_quark_from_static_string (const gchar *string)
321 {
322   GQuark quark;
323   
324   g_return_val_if_fail (string != NULL, 0);
325   
326   if (!g_quark_ht)
327     g_dataset_initialize ();
328   
329   quark = (gulong) g_hash_table_lookup (g_quark_ht, string);
330   if (!quark)
331     quark = g_quark_new (string);
332   
333   return quark;
334 }
335
336 gchar*
337 g_quark_to_string (GQuark quark)
338 {
339   if (quark > 0 && quark <= g_quark_seq_id)
340     return g_quarks[quark - 1];
341   else
342     return NULL;
343 }
344
345 static inline GQuark
346 g_quark_new (const gchar *string)
347 {
348   GQuark quark;
349   
350   if (g_quark_seq_id % G_DATASET_BLOCK_SIZE == 0)
351     g_quarks = g_realloc (g_quarks,
352                           (g_quark_seq_id + G_DATASET_BLOCK_SIZE) * sizeof (gchar*));
353   
354   
355   g_quarks[g_quark_seq_id] = (gchar*) string;
356   g_quark_seq_id++;
357   quark = g_quark_seq_id;
358   g_hash_table_insert (g_quark_ht, (gchar*) string, GUINT_TO_POINTER (quark));
359   
360   return quark;
361 }