summaryrefslogtreecommitdiff
path: root/protocols/Sametime/src/glib/gcache.c
blob: 1b2533eb44d47f98bb92339453d33cb5d4baf573 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * 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
 */

#include "config.h"

#include "gcache.h"

#include "ghash.h"
#include "gtestutils.h"

/**
 * SECTION: caches
 * @title: Caches
 * @short_description: caches allow sharing of complex data structures
 *                     to save resources
 *
 * A #GCache allows sharing of complex data structures, in order to
 * save system resources.
 *
 * GTK+ uses caches for #GtkStyles and #GdkGCs. These consume a lot of
 * resources, so a #GCache is used to see if a #GtkStyle or #GdkGC with
 * the required properties already exists. If it does, then the
 * existing object is used instead of creating a new one.
 *
 * #GCache uses keys and values. A #GCache key describes the properties
 * of a particular resource. A #GCache value is the actual resource.
 **/

typedef struct _GCacheNode  GCacheNode;

struct _GCacheNode
{
  /* A reference counted node */
  gpointer value;
  gint ref_count;
};

/**
 * GCache:
 *
 * The #GCache struct is an opaque data structure containing
 * information about a #GCache. It should only be accessed via the
 * following functions.
 **/
struct _GCache
{
  /* Called to create a value from a key */
  GCacheNewFunc value_new_func;

  /* Called to destroy a value */
  GCacheDestroyFunc value_destroy_func;

  /* Called to duplicate a key */
  GCacheDupFunc key_dup_func;

  /* Called to destroy a key */
  GCacheDestroyFunc key_destroy_func;

  /* Associates keys with nodes */
  GHashTable *key_table;

  /* Associates nodes with keys */
  GHashTable *value_table;
};

static inline GCacheNode*
g_cache_node_new (gpointer value)
{
  GCacheNode *node = g_slice_new (GCacheNode);
  node->value = value;
  node->ref_count = 1;
  return node;
}

static inline void
g_cache_node_destroy (GCacheNode *node)
{
  g_slice_free (GCacheNode, node);
}

/**
 * g_cache_new:
 * @value_new_func: a function to create a new object given a key.
 *                  This is called by g_cache_insert() if an object
 *                  with the given key does not already exist.
 * @value_destroy_func: a function to destroy an object. It is called
 *                      by g_cache_remove() when the object is no
 *                      longer needed (i.e. its reference count drops
 *                      to 0).
 * @key_dup_func: a function to copy a key. It is called by
 *                g_cache_insert() if the key does not already exist in
 *                the #GCache.
 * @key_destroy_func: a function to destroy a key. It is called by
 *                    g_cache_remove() when the object is no longer
 *                    needed (i.e. its reference count drops to 0).
 * @hash_key_func: a function to create a hash value from a key.
 * @hash_value_func: a function to create a hash value from a value.
 * @key_equal_func: a function to compare two keys. It should return
 *                  %TRUE if the two keys are equivalent.
 * @Returns: a new #GCache.
 *
 * Creates a new #GCache.
 **/
/**
 * GCacheNewFunc:
 * @key: a #GCache key.
 * @Returns: a new #GCache value corresponding to the key.
 *
 * Specifies the type of the @value_new_func function passed to
 * g_cache_new(). It is passed a #GCache key and should create the
 * value corresponding to the key.
 **/
/**
 * GCacheDestroyFunc:
 * @value: the #GCache value to destroy.
 *
 * Specifies the type of the @value_destroy_func and @key_destroy_func
 * functions passed to g_cache_new(). The functions are passed a
 * pointer to the #GCache key or #GCache value and should free any
 * memory and other resources associated with it.
 **/
/**
 * GCacheDupFunc:
 * @value: the #GCache key to destroy (<emphasis>not</emphasis> a
 *         #GCache value as it seems).
 * @Returns: a copy of the #GCache key.
 *
 * Specifies the type of the @key_dup_func function passed to
 * g_cache_new(). The function is passed a key
 * (<emphasis>not</emphasis> a value as the prototype implies) and
 * should return a duplicate of the key.
 **/
GCache*
g_cache_new (GCacheNewFunc      value_new_func,
             GCacheDestroyFunc  value_destroy_func,
             GCacheDupFunc      key_dup_func,
             GCacheDestroyFunc  key_destroy_func,
             GHashFunc          hash_key_func,
             GHashFunc          hash_value_func,
             GEqualFunc         key_equal_func)
{
  GCache *cache;

  g_return_val_if_fail (value_new_func != NULL, NULL);
  g_return_val_if_fail (value_destroy_func != NULL, NULL);
  g_return_val_if_fail (key_dup_func != NULL, NULL);
  g_return_val_if_fail (key_destroy_func != NULL, NULL);
  g_return_val_if_fail (hash_key_func != NULL, NULL);
  g_return_val_if_fail (hash_value_func != NULL, NULL);
  g_return_val_if_fail (key_equal_func != NULL, NULL);

  cache = g_slice_new (GCache);
  cache->value_new_func = value_new_func;
  cache->value_destroy_func = value_destroy_func;
  cache->key_dup_func = key_dup_func;
  cache->key_destroy_func = key_destroy_func;
  cache->key_table = g_hash_table_new (hash_key_func, key_equal_func);
  cache->value_table = g_hash_table_new (hash_value_func, NULL);

  return cache;
}

/**
 * g_cache_destroy:
 * @cache: a #GCache.
 *
 * Frees the memory allocated for the #GCache.
 *
 * Note that it does not destroy the keys and values which were
 * contained in the #GCache.
 **/
void
g_cache_destroy (GCache *cache)
{
  g_return_if_fail (cache != NULL);

  g_hash_table_destroy (cache->key_table);
  g_hash_table_destroy (cache->value_table);
  g_slice_free (GCache, cache);
}

/**
 * g_cache_insert:
 * @cache: a #GCache.
 * @key: a key describing a #GCache object.
 * @Returns: a pointer to a #GCache value.
 *
 * Gets the value corresponding to the given key, creating it if
 * necessary. It first checks if the value already exists in the
 * #GCache, by using the @key_equal_func function passed to
 * g_cache_new(). If it does already exist it is returned, and its
 * reference count is increased by one. If the value does not currently
 * exist, if is created by calling the @value_new_func. The key is
 * duplicated by calling @key_dup_func and the duplicated key and value
 * are inserted into the #GCache.
 **/
gpointer
g_cache_insert (GCache   *cache,
                gpointer  key)
{
  GCacheNode *node;
  gpointer value;

  g_return_val_if_fail (cache != NULL, NULL);

  node = g_hash_table_lookup (cache->key_table, key);
  if (node)
    {
      node->ref_count += 1;
      return node->value;
    }

  key = (* cache->key_dup_func) (key);
  value = (* cache->value_new_func) (key);
  node = g_cache_node_new (value);

  g_hash_table_insert (cache->key_table, key, node);
  g_hash_table_insert (cache->value_table, value, key);

  return node->value;
}

/**
 * g_cache_remove:
 * @cache: a #GCache.
 * @value: the value to remove.
 *
 * Decreases the reference count of the given value. If it drops to 0
 * then the value and its corresponding key are destroyed, using the
 * @value_destroy_func and @key_destroy_func passed to g_cache_new().
 **/
void
g_cache_remove (GCache        *cache,
                gconstpointer  value)
{
  GCacheNode *node;
  gpointer key;

  g_return_if_fail (cache != NULL);

  key = g_hash_table_lookup (cache->value_table, value);
  node = g_hash_table_lookup (cache->key_table, key);

  g_return_if_fail (node != NULL);

  node->ref_count -= 1;
  if (node->ref_count == 0)
    {
      g_hash_table_remove (cache->value_table, value);
      g_hash_table_remove (cache->key_table, key);

      (* cache->key_destroy_func) (key);
      (* cache->value_destroy_func) (node->value);
      g_cache_node_destroy (node);
    }
}

/**
 * g_cache_key_foreach:
 * @cache: a #GCache.
 * @func: the function to call with each #GCache key.
 * @user_data: user data to pass to the function.
 *
 * Calls the given function for each of the keys in the #GCache.
 *
 * NOTE @func is passed three parameters, the value and key of a cache
 * entry and the @user_data. The order of value and key is different
 * from the order in which g_hash_table_foreach() passes key-value
 * pairs to its callback function !
 **/
void
g_cache_key_foreach (GCache   *cache,
                     GHFunc    func,
                     gpointer  user_data)
{
  g_return_if_fail (cache != NULL);
  g_return_if_fail (func != NULL);

  g_hash_table_foreach (cache->value_table, func, user_data);
}

/**
 * g_cache_value_foreach:
 * @cache: a #GCache.
 * @func: the function to call with each #GCache value.
 * @user_data: user data to pass to the function.
 *
 * Calls the given function for each of the values in the #GCache.
 *
 * Deprecated:2.10: The reason is that it passes pointers to internal
 *                  data structures to @func; use g_cache_key_foreach()
 *                  instead
 **/
void
g_cache_value_foreach (GCache   *cache,
                       GHFunc    func,
                       gpointer  user_data)
{
  g_return_if_fail (cache != NULL);
  g_return_if_fail (func != NULL);

  g_hash_table_foreach (cache->key_table, func, user_data);
}