1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpidtable.c
5 * Copyright (C) 2011 Martin Nordholts <martinn@src.gnome.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program 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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gio/gio.h>
24 #include <gegl.h>
25
26 #include "core-types.h"
27
28 #include "gimp-memsize.h"
29 #include "gimpidtable.h"
30
31
32 #define GIMP_ID_TABLE_START_ID 1
33 #define GIMP_ID_TABLE_END_ID G_MAXINT
34
35
36 struct _GimpIdTablePrivate
37 {
38 GHashTable *id_table;
39 gint next_id;
40 };
41
42
43 static void gimp_id_table_finalize (GObject *object);
44 static gint64 gimp_id_table_get_memsize (GimpObject *object,
45 gint64 *gui_size);
46
47
G_DEFINE_TYPE_WITH_PRIVATE(GimpIdTable,gimp_id_table,GIMP_TYPE_OBJECT)48 G_DEFINE_TYPE_WITH_PRIVATE (GimpIdTable, gimp_id_table, GIMP_TYPE_OBJECT)
49
50 #define parent_class gimp_id_table_parent_class
51
52
53 static void
54 gimp_id_table_class_init (GimpIdTableClass *klass)
55 {
56 GObjectClass *object_class = G_OBJECT_CLASS (klass);
57 GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass);
58
59 object_class->finalize = gimp_id_table_finalize;
60
61 gimp_object_class->get_memsize = gimp_id_table_get_memsize;
62 }
63
64 static void
gimp_id_table_init(GimpIdTable * id_table)65 gimp_id_table_init (GimpIdTable *id_table)
66 {
67 id_table->priv = gimp_id_table_get_instance_private (id_table);
68
69 id_table->priv->id_table = g_hash_table_new (g_direct_hash, NULL);
70 id_table->priv->next_id = GIMP_ID_TABLE_START_ID;
71 }
72
73 static void
gimp_id_table_finalize(GObject * object)74 gimp_id_table_finalize (GObject *object)
75 {
76 GimpIdTable *id_table = GIMP_ID_TABLE (object);
77
78 g_clear_pointer (&id_table->priv->id_table, g_hash_table_unref);
79
80 G_OBJECT_CLASS (parent_class)->finalize (object);
81 }
82
83 static gint64
gimp_id_table_get_memsize(GimpObject * object,gint64 * gui_size)84 gimp_id_table_get_memsize (GimpObject *object,
85 gint64 *gui_size)
86 {
87 GimpIdTable *id_table = GIMP_ID_TABLE (object);
88 gint64 memsize = 0;
89
90 memsize += gimp_g_hash_table_get_memsize (id_table->priv->id_table, 0);
91
92 return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object,
93 gui_size);
94 }
95
96 /**
97 * gimp_id_table_new:
98 *
99 * Returns: A new #GimpIdTable.
100 **/
101 GimpIdTable *
gimp_id_table_new(void)102 gimp_id_table_new (void)
103 {
104 return g_object_new (GIMP_TYPE_ID_TABLE, NULL);
105 }
106
107 /**
108 * gimp_id_table_insert:
109 * @id_table: A #GimpIdTable
110 * @data: Data to insert and assign an id to
111 *
112 * Insert data in the id table. The data will get an, in this table,
113 * unused ID assigned to it that can be used to later lookup the data.
114 *
115 * Returns: The assigned ID.
116 **/
117 gint
gimp_id_table_insert(GimpIdTable * id_table,gpointer data)118 gimp_id_table_insert (GimpIdTable *id_table, gpointer data)
119 {
120 gint new_id;
121 gint start_id;
122
123 g_return_val_if_fail (GIMP_IS_ID_TABLE (id_table), 0);
124
125 start_id = id_table->priv->next_id;
126
127 do
128 {
129 new_id = id_table->priv->next_id++;
130
131 if (id_table->priv->next_id == GIMP_ID_TABLE_END_ID)
132 id_table->priv->next_id = GIMP_ID_TABLE_START_ID;
133
134 if (start_id == id_table->priv->next_id)
135 {
136 /* We looped once over all used ids. Very unlikely to happen.
137 And if it does, there is probably not much to be done.
138 It is just good design not to allow a theoretical infinite loop. */
139 g_error ("%s: out of ids!", G_STRFUNC);
140 break;
141 }
142 }
143 while (gimp_id_table_lookup (id_table, new_id));
144
145 return gimp_id_table_insert_with_id (id_table, new_id, data);
146 }
147
148 /**
149 * gimp_id_table_insert_with_id:
150 * @id_table: An #GimpIdTable
151 * @id: The ID to use. Must be greater than 0.
152 * @data: The data to associate with the id
153 *
154 * Insert data in the id table with a specific ID. If data already
155 * exsts with the given ID, this function fails.
156 *
157 * Returns: The used ID if successful, -1 if it was already in use.
158 **/
159 gint
gimp_id_table_insert_with_id(GimpIdTable * id_table,gint id,gpointer data)160 gimp_id_table_insert_with_id (GimpIdTable *id_table, gint id, gpointer data)
161 {
162 g_return_val_if_fail (GIMP_IS_ID_TABLE (id_table), 0);
163 g_return_val_if_fail (id > 0, 0);
164
165 if (gimp_id_table_lookup (id_table, id))
166 return -1;
167
168 g_hash_table_insert (id_table->priv->id_table, GINT_TO_POINTER (id), data);
169
170 return id;
171 }
172
173 /**
174 * gimp_id_table_replace:
175 * @id_table: An #GimpIdTable
176 * @id: The ID to use. Must be greater than 0.
177 * @data: The data to insert/replace
178 *
179 * Replaces (if an item with the given ID exists) or inserts a new
180 * entry in the id table.
181 **/
182 void
gimp_id_table_replace(GimpIdTable * id_table,gint id,gpointer data)183 gimp_id_table_replace (GimpIdTable *id_table, gint id, gpointer data)
184 {
185 g_return_if_fail (GIMP_IS_ID_TABLE (id_table));
186 g_return_if_fail (id > 0);
187
188 g_hash_table_replace (id_table->priv->id_table, GINT_TO_POINTER (id), data);
189 }
190
191 /**
192 * gimp_id_table_lookup:
193 * @id_table: An #GimpIdTable
194 * @id: The ID of the data to lookup
195 *
196 * Lookup data based on ID.
197 *
198 * Returns: The data, or NULL if no data with the given ID was found.
199 **/
200 gpointer
gimp_id_table_lookup(GimpIdTable * id_table,gint id)201 gimp_id_table_lookup (GimpIdTable *id_table, gint id)
202 {
203 g_return_val_if_fail (GIMP_IS_ID_TABLE (id_table), NULL);
204
205 return g_hash_table_lookup (id_table->priv->id_table, GINT_TO_POINTER (id));
206 }
207
208
209 /**
210 * gimp_id_table_remove:
211 * @id_table: An #GimpIdTable
212 * @id: The ID of the data to remove.
213 *
214 * Remove the data from the table with the given ID.
215 *
216 * Returns: %TRUE if data with the ID existed and was successfully
217 * removed, %FALSE otherwise.
218 **/
219 gboolean
gimp_id_table_remove(GimpIdTable * id_table,gint id)220 gimp_id_table_remove (GimpIdTable *id_table, gint id)
221 {
222 g_return_val_if_fail (GIMP_IS_ID_TABLE (id_table), FALSE);
223
224 g_return_val_if_fail (id_table != NULL, FALSE);
225
226 return g_hash_table_remove (id_table->priv->id_table, GINT_TO_POINTER (id));
227 }
228