]> Pileus Git - ~andy/gtk/blob - glib/gcache.c
b2fe77910e32c00615764893b1285a7a364ddf49
[~andy/gtk] / glib / gcache.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include "glib.h"
20
21
22 typedef struct _GCacheNode  GCacheNode;
23 typedef struct _GRealCache  GRealCache;
24
25 struct _GCacheNode
26 {
27   /* A reference counted node */
28   gpointer value;
29   gint ref_count;
30 };
31
32 struct _GRealCache
33 {
34   /* Called to create a value from a key */
35   GCacheNewFunc value_new_func;
36
37   /* Called to destroy a value */
38   GCacheDestroyFunc value_destroy_func;
39
40   /* Called to duplicate a key */
41   GCacheDupFunc key_dup_func;
42
43   /* Called to destroy a key */
44   GCacheDestroyFunc key_destroy_func;
45
46   /* Associates keys with nodes */
47   GHashTable *key_table;
48
49   /* Associates nodes with keys */
50   GHashTable *value_table;
51 };
52
53
54 static GCacheNode* g_cache_node_new     (gpointer value);
55 static void        g_cache_node_destroy (GCacheNode *node);
56
57
58 static GMemChunk *node_mem_chunk = NULL;
59
60
61 GCache*
62 g_cache_new (GCacheNewFunc      value_new_func,
63              GCacheDestroyFunc  value_destroy_func,
64              GCacheDupFunc      key_dup_func,
65              GCacheDestroyFunc  key_destroy_func,
66              GHashFunc          hash_key_func,
67              GHashFunc          hash_value_func,
68              GCompareFunc       key_compare_func)
69 {
70   GRealCache *cache;
71
72   g_return_val_if_fail (value_new_func != NULL, NULL);
73   g_return_val_if_fail (value_destroy_func != NULL, NULL);
74   g_return_val_if_fail (key_dup_func != NULL, NULL);
75   g_return_val_if_fail (key_destroy_func != NULL, NULL);
76   g_return_val_if_fail (hash_key_func != NULL, NULL);
77   g_return_val_if_fail (hash_value_func != NULL, NULL);
78   g_return_val_if_fail (key_compare_func != NULL, NULL);
79
80   cache = g_new (GRealCache, 1);
81   cache->value_new_func = value_new_func;
82   cache->value_destroy_func = value_destroy_func;
83   cache->key_dup_func = key_dup_func;
84   cache->key_destroy_func = key_destroy_func;
85   cache->key_table = g_hash_table_new (hash_key_func, key_compare_func);
86   cache->value_table = g_hash_table_new (hash_value_func, NULL);
87
88   return (GCache*) cache;
89 }
90
91 void
92 g_cache_destroy (GCache *cache)
93 {
94   GRealCache *rcache;
95
96   g_return_if_fail (cache != NULL);
97
98   rcache = (GRealCache*) cache;
99   g_hash_table_destroy (rcache->key_table);
100   g_hash_table_destroy (rcache->value_table);
101   g_free (rcache);
102 }
103
104 gpointer
105 g_cache_insert (GCache   *cache,
106                 gpointer  key)
107 {
108   GRealCache *rcache;
109   GCacheNode *node;
110   gpointer value;
111
112   g_return_val_if_fail (cache != NULL, NULL);
113
114   rcache = (GRealCache*) cache;
115
116   node = g_hash_table_lookup (rcache->key_table, key);
117   if (node)
118     {
119       node->ref_count += 1;
120       return node->value;
121     }
122
123   key = (* rcache->key_dup_func) (key);
124   value = (* rcache->value_new_func) (key);
125   node = g_cache_node_new (value);
126
127   g_hash_table_insert (rcache->key_table, key, node);
128   g_hash_table_insert (rcache->value_table, value, key);
129
130   return node->value;
131 }
132
133 void
134 g_cache_remove (GCache   *cache,
135                 gpointer  value)
136 {
137   GRealCache *rcache;
138   GCacheNode *node;
139   gpointer key;
140
141   g_return_if_fail (cache != NULL);
142
143   rcache = (GRealCache*) cache;
144
145   key = g_hash_table_lookup (rcache->value_table, value);
146   node = g_hash_table_lookup (rcache->key_table, key);
147
148   node->ref_count -= 1;
149   if (node->ref_count == 0)
150     {
151       g_hash_table_remove (rcache->value_table, value);
152       g_hash_table_remove (rcache->key_table, key);
153
154       (* rcache->key_destroy_func) (key);
155       (* rcache->value_destroy_func) (node->value);
156       g_cache_node_destroy (node);
157     }
158 }
159
160 void
161 g_cache_key_foreach (GCache   *cache,
162                      GHFunc    func,
163                      gpointer  user_data)
164 {
165   GRealCache *rcache;
166
167   g_return_if_fail (cache != NULL);
168   g_return_if_fail (func != NULL);
169
170   rcache = (GRealCache*) cache;
171
172   g_hash_table_foreach (rcache->value_table, func, user_data);
173 }
174
175 void
176 g_cache_value_foreach (GCache   *cache,
177                        GHFunc    func,
178                        gpointer  user_data)
179 {
180   GRealCache *rcache;
181
182   g_return_if_fail (cache != NULL);
183   g_return_if_fail (func != NULL);
184
185   rcache = (GRealCache*) cache;
186
187   g_hash_table_foreach (rcache->key_table, func, user_data);
188 }
189
190
191 static GCacheNode*
192 g_cache_node_new (gpointer value)
193 {
194   GCacheNode *node;
195
196   if (!node_mem_chunk)
197     node_mem_chunk = g_mem_chunk_new ("cache node mem chunk", sizeof (GCacheNode),
198                                       1024, G_ALLOC_AND_FREE);
199
200   node = g_chunk_new (GCacheNode, node_mem_chunk);
201
202   node->value = value;
203   node->ref_count = 1;
204
205   return node;
206 }
207
208 static void
209 g_cache_node_destroy (GCacheNode *node)
210 {
211   g_mem_chunk_free (node_mem_chunk, node);
212 }