new function g_dataset_retrive_key. adjusted prealloc sizes, to take up
[platform/upstream/glib.git] / glib / 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        "glib.h"
22
23
24
25 /* --- defines --- */
26 #define G_DATASET_BLOCK_SIZE                    (512)
27 #define G_DATASET_MEM_CHUNK_PREALLOC            (64)
28 #define G_DATASET_DATA_MEM_CHUNK_PREALLOC       (128)
29
30
31 /* --- structures --- */
32 typedef struct _GDatasetData GDatasetData;
33 typedef struct _GDataset GDataset;
34 struct _GDatasetData
35 {
36   GDatasetData *next;
37   guint id;
38   gpointer data;
39   GDestroyNotify destroy_func;
40 };
41
42 struct _GDataset
43 {
44   gconstpointer location;
45   GDatasetData *data_list;
46 };
47
48
49 /* --- prototypes --- */
50 static inline GDataset* g_dataset_lookup        (gconstpointer dataset_location);
51 static inline void      g_dataset_destroy_i     (GDataset     *dataset);
52 static void             g_dataset_initialize    (void);
53 static void             g_dataset_alloc_key     (const gchar    *string,
54                                                  guint          **id,
55                                                  gchar          **key);
56      
57
58 /* --- variables --- */
59 static GHashTable *g_dataset_location_ht = NULL;
60 static GHashTable *g_dataset_key_ht = NULL;
61 static GDataset *g_dataset_cached = NULL;
62 static GMemChunk *g_dataset_mem_chunk = NULL;
63 static GMemChunk *g_dataset_data_mem_chunk = NULL;
64 static gchar   **g_dataset_key_array = NULL;
65 static guint     g_dataset_seq_id = 0;
66
67
68
69 /* --- functions --- */
70 static inline GDataset*
71 g_dataset_lookup (gconstpointer dataset_location)
72 {
73   register GDataset *dataset;
74   
75   if (g_dataset_cached && g_dataset_cached->location == dataset_location)
76     return g_dataset_cached;
77   
78   if (!g_dataset_location_ht)
79     g_dataset_initialize ();
80   
81   dataset = g_hash_table_lookup (g_dataset_location_ht, dataset_location);
82   if (dataset)
83     g_dataset_cached = dataset;
84   
85   return dataset;
86 }
87
88 static inline void
89 g_dataset_destroy_i (GDataset *dataset)
90 {
91   register GDatasetData *list;
92   
93   if (dataset == g_dataset_cached)
94     g_dataset_cached = NULL;
95   g_hash_table_remove (g_dataset_location_ht, dataset->location);
96   
97   list = dataset->data_list;
98   g_mem_chunk_free (g_dataset_mem_chunk, dataset);
99   
100   while (list)
101     {
102       register GDatasetData *prev;
103       
104       prev = list;
105       list = prev->next;
106       
107       if (prev->destroy_func)
108         prev->destroy_func (prev->data);
109       
110       g_mem_chunk_free (g_dataset_data_mem_chunk, prev);
111     }
112 }
113
114 void
115 g_dataset_destroy (gconstpointer  dataset_location)
116 {
117   register GDataset *dataset;
118   
119   g_return_if_fail (dataset_location != NULL);
120   
121   dataset = g_dataset_lookup (dataset_location);
122   if (dataset)
123     g_dataset_destroy_i (dataset);
124 }
125
126 void
127 g_dataset_id_set_destroy (gconstpointer  dataset_location,
128                           guint          key_id,
129                           GDestroyNotify destroy_func)
130 {
131   g_return_if_fail (dataset_location != NULL);
132   
133   if (key_id)
134     {
135       register GDataset *dataset;
136       
137       dataset = g_dataset_lookup (dataset_location);
138       if (dataset)
139         {
140           register GDatasetData *list;
141           
142           list = dataset->data_list;
143           while (list)
144             {
145               if (list->id == key_id)
146                 {
147                   list->destroy_func = destroy_func;
148                   return;
149                 }
150             }
151         }
152     }
153 }
154
155 gpointer
156 g_dataset_id_get_data (gconstpointer  dataset_location,
157                        guint          key_id)
158 {
159   g_return_val_if_fail (dataset_location != NULL, NULL);
160   
161   if (key_id)
162     {
163       register GDataset *dataset;
164       
165       dataset = g_dataset_lookup (dataset_location);
166       if (dataset)
167         {
168           register GDatasetData *list;
169           
170           for (list = dataset->data_list; list; list = list->next)
171             if (list->id == key_id)
172               return list->data;
173         }
174     }
175   
176   return NULL;
177 }
178
179 void
180 g_dataset_id_set_data_full (gconstpointer  dataset_location,
181                             guint          key_id,
182                             gpointer       data,
183                             GDestroyNotify destroy_func)
184 {
185   register GDataset *dataset;
186   register GDatasetData *list;
187   
188   g_return_if_fail (dataset_location != NULL);
189   g_return_if_fail (key_id > 0);
190   
191   dataset = g_dataset_lookup (dataset_location);
192   if (!dataset)
193     {
194       dataset = g_chunk_new (GDataset, g_dataset_mem_chunk);
195       dataset->location = dataset_location;
196       dataset->data_list = NULL;
197       g_hash_table_insert (g_dataset_location_ht, 
198                            (gpointer) dataset->location, /* Yuck */
199                            dataset);
200     }
201   
202   list = dataset->data_list;
203   if (!data)
204     {
205       register GDatasetData *prev;
206       
207       prev = NULL;
208       while (list)
209         {
210           if (list->id == key_id)
211             {
212               if (prev)
213                 prev->next = list->next;
214               else
215                 {
216                   dataset->data_list = list->next;
217                   
218                   if (!dataset->data_list)
219                     g_dataset_destroy_i (dataset);
220                 }
221               
222               /* we need to have unlinked before invoking the destroy function
223                */
224               if (list->destroy_func)
225                 list->destroy_func (list->data);
226               
227               g_mem_chunk_free (g_dataset_data_mem_chunk, list);
228               break;
229             }
230           
231           prev = list;
232           list = list->next;
233         }
234     }
235   else
236     {
237       register GDatasetData *prev;
238       
239       prev = NULL;
240       while (list)
241         {
242           if (list->id == key_id)
243             {
244               if (prev)
245                 prev->next = list->next;
246               else
247                 dataset->data_list = list->next;
248               
249               /* we need to have unlinked before invoking the destroy function
250                */
251               if (list->destroy_func)
252                 list->destroy_func (list->data);
253               
254               break;
255             }
256           
257           prev = list;
258           list = list->next;
259         }
260       
261       if (!list)
262         list = g_chunk_new (GDatasetData, g_dataset_data_mem_chunk);
263       list->next = dataset->data_list;
264       list->id = key_id;
265       list->data = data;
266       list->destroy_func = destroy_func;
267       dataset->data_list = list;
268     }
269 }
270
271 guint
272 g_dataset_try_key (const gchar    *key)
273 {
274   register guint *id;
275   g_return_val_if_fail (key != NULL, 0);
276   
277   if (g_dataset_key_ht)
278     {
279       id = g_hash_table_lookup (g_dataset_key_ht, (gpointer) key);
280       
281       if (id)
282         return *id;
283     }
284   
285   return 0;
286 }
287
288 guint
289 g_dataset_force_id (const gchar    *key)
290 {
291   guint *id;
292   
293   g_return_val_if_fail (key != NULL, 0);
294   
295   if (!g_dataset_key_ht)
296     g_dataset_initialize ();
297   
298   id = g_hash_table_lookup (g_dataset_key_ht, (gpointer) key);
299   if (!id)
300     {
301       gchar *new_key;
302
303       g_dataset_alloc_key (key, &id, &new_key);
304       g_hash_table_insert (g_dataset_key_ht, new_key, id);
305     }
306   
307   return *id;
308 }
309
310 static void
311 g_dataset_initialize (void)
312 {
313   if (!g_dataset_location_ht)
314     {
315       g_dataset_location_ht = g_hash_table_new (g_direct_hash, NULL);
316       g_dataset_key_ht = g_hash_table_new (g_str_hash, g_str_equal);
317       g_dataset_cached = NULL;
318       g_dataset_mem_chunk =
319         g_mem_chunk_new ("GDataset MemChunk",
320                          sizeof (GDataset),
321                          sizeof (GDataset) * G_DATASET_MEM_CHUNK_PREALLOC,
322                          G_ALLOC_AND_FREE);
323       g_dataset_data_mem_chunk =
324         g_mem_chunk_new ("GDatasetData MemChunk",
325                          sizeof (GDatasetData),
326                          sizeof (GDatasetData) * G_DATASET_DATA_MEM_CHUNK_PREALLOC,
327                          G_ALLOC_AND_FREE);
328     }
329 }
330
331 gchar*
332 g_dataset_retrive_key (guint id)
333 {
334   if (id > 0 && id <= g_dataset_seq_id)
335     return g_dataset_key_array[id - 1];
336   return NULL;
337 }
338
339 static void
340 g_dataset_alloc_key (const gchar *string,
341                      guint      **id,
342                      gchar      **key)
343 {
344   if (g_dataset_seq_id % G_DATASET_BLOCK_SIZE == 0)
345     g_dataset_key_array = g_realloc (g_dataset_key_array,
346                                      (g_dataset_seq_id + G_DATASET_BLOCK_SIZE) * sizeof (gchar*));
347   
348   *key = g_new (gchar, sizeof (guint) + strlen (string) + 1);
349   *id = (guint*) *key;
350   *key += sizeof (guint);
351   strcpy (*key, string);
352   g_dataset_key_array[g_dataset_seq_id] = *key;
353   g_dataset_seq_id++;
354   **id = g_dataset_seq_id;
355 }