QOF: qofid.c Source File

QOF 0.7.5

qofid.c
1 /********************************************************************\
2 * qofid.c -- QOF entity identifier implementation *
3 * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> *
4 * Copyright (C) 2003 Linas Vepstas <linas@linas.org> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License*
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22 * *
23 \********************************************************************/
24
25 #include "config.h"
26
27 #include <string.h>
28 #include <glib.h>
29
30 #include "qof.h"
31 #include "qofid-p.h"
32
33 static QofLogModule log_module = QOF_MOD_ENGINE;
34
35 struct QofCollection_s
36 {
37 QofIdType e_type;
38 gboolean is_dirty;
39
40 GHashTable *hash_of_entities;
41 gpointer data; /* place where object class can hang arbitrary data */
42 };
43
44 /* =============================================================== */
45
46 static void qof_collection_remove_entity (QofEntity * ent);
47
48 void
49 qof_entity_init (QofEntity * ent, QofIdType type, QofCollection * tab)
50 {
51 g_return_if_fail (NULL != tab);
52
53 /* XXX We passed redundant info to this routine ... but I think that's
54 * OK, it might eliminate programming errors. */
55 if (safe_strcmp (tab->e_type, type))
56 {
57 PERR ("attempt to insert \"%s\" into \"%s\"", type, tab->e_type);
58 return;
59 }
60 ent->e_type = CACHE_INSERT (type);
61
62 do
63 {
64 guid_new (&ent->guid);
65
66 if (NULL == qof_collection_lookup_entity (tab, &ent->guid))
67 break;
68
69 PWARN ("duplicate id created, trying again");
70 }
71 while (1);
72
73 ent->collection = tab;
74
75 qof_collection_insert_entity (tab, ent);
76 }
77
78 void
79 qof_entity_release (QofEntity * ent)
80 {
81 if (!ent->collection)
82 return;
83 qof_collection_remove_entity (ent);
84 CACHE_REMOVE (ent->e_type);
85 ent->e_type = NULL;
86 }
87
88
89 /* This is a restricted function, should be used only during
90 * read from file */
91 void
92 qof_entity_set_guid (QofEntity * ent, const GUID * guid)
93 {
94 QofCollection *col;
95 if (guid_equal (guid, &ent->guid))
96 return;
97
98 col = ent->collection;
99 qof_collection_remove_entity (ent);
100 ent->guid = *guid;
101 qof_collection_insert_entity (col, ent);
102 }
103
104 const GUID *
105 qof_entity_get_guid (QofEntity * ent)
106 {
107 if (!ent)
108 return guid_null ();
109 return &ent->guid;
110 }
111
112 /* =============================================================== */
113
114 static guint
115 id_hash (gconstpointer key)
116 {
117 const GUID *guid = key;
118
119 if (key == NULL)
120 return 0;
121
122 /* Compiler should optimize this all away! */
123 if (sizeof (guint) <= 16)
124 return *((guint *) guid->data);
125 else
126 {
127 guint hash = 0;
128 guint i, j;
129
130 for (i = 0, j = 0; i < sizeof (guint); i++, j++)
131 {
132 if (j == 16)
133 j = 0;
134
135 hash <<= 4;
136 hash |= guid->data[j];
137 }
138
139 return hash;
140 }
141 }
142
143 static gboolean
144 id_compare (gconstpointer key_1, gconstpointer key_2)
145 {
146 return guid_equal (key_1, key_2);
147 }
148
149 QofCollection *
150 qof_collection_new (QofIdType type)
151 {
152 QofCollection *col;
153 col = g_new0 (QofCollection, 1);
154 col->e_type = CACHE_INSERT (type);
155 col->hash_of_entities = g_hash_table_new (id_hash, id_compare);
156 col->data = NULL;
157 return col;
158 }
159
160 void
161 qof_collection_destroy (QofCollection * col)
162 {
163 CACHE_REMOVE (col->e_type);
164 g_hash_table_destroy (col->hash_of_entities);
165 col->e_type = NULL;
166 col->hash_of_entities = NULL;
167 col->data = NULL;
168 g_free (col);
169 }
170
171 /* =============================================================== */
172 /* getters */
173
174 QofIdType
175 qof_collection_get_type (QofCollection * col)
176 {
177 return col->e_type;
178 }
179
180 /* =============================================================== */
181
182 static void
183 qof_collection_remove_entity (QofEntity * ent)
184 {
185 QofCollection *col;
186 if (!ent)
187 return;
188 col = ent->collection;
189 if (!col)
190 return;
191 g_hash_table_remove (col->hash_of_entities, &ent->guid);
192 qof_collection_mark_dirty (col);
193 ent->collection = NULL;
194 }
195
196 void
197 qof_collection_insert_entity (QofCollection * col, QofEntity * ent)
198 {
199 if (!col || !ent)
200 return;
201 if (guid_equal (&ent->guid, guid_null ()))
202 return;
203 g_return_if_fail (col->e_type == ent->e_type);
204 qof_collection_remove_entity (ent);
205 g_hash_table_insert (col->hash_of_entities, &ent->guid, ent);
206 qof_collection_mark_dirty (col);
207 ent->collection = col;
208 }
209
210 gboolean
211 qof_collection_add_entity (QofCollection * coll, QofEntity * ent)
212 {
213 QofEntity *e;
214
215 e = NULL;
216 if (!coll || !ent)
217 {
218 return FALSE;
219 }
220 if (guid_equal (&ent->guid, guid_null ()))
221 {
222 return FALSE;
223 }
224 g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
225 e = qof_collection_lookup_entity (coll, &ent->guid);
226 if (e != NULL)
227 {
228 return FALSE;
229 }
230 g_hash_table_insert (coll->hash_of_entities, &ent->guid, ent);
231 qof_collection_mark_dirty (coll);
232 return TRUE;
233 }
234
235 static void
236 collection_merge_cb (QofEntity * ent, gpointer data)
237 {
238 QofCollection *target;
239
240 target = (QofCollection *) data;
241 qof_collection_add_entity (target, ent);
242 }
243
244 gboolean
245 qof_collection_merge (QofCollection * target, QofCollection * merge)
246 {
247 if (!target || !merge)
248 {
249 return FALSE;
250 }
251 g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
252 qof_collection_foreach (merge, collection_merge_cb, target);
253 return TRUE;
254 }
255
256 static void
257 collection_compare_cb (QofEntity * ent, gpointer user_data)
258 {
259 QofCollection *target;
260 QofEntity *e;
261 gint value;
262
263 e = NULL;
264 target = (QofCollection *) user_data;
265 if (!target || !ent)
266 {
267 return;
268 }
269 value = *(gint *) qof_collection_get_data (target);
270 if (value != 0)
271 {
272 return;
273 }
274 if (guid_equal (&ent->guid, guid_null ()))
275 {
276 value = -1;
277 qof_collection_set_data (target, &value);
278 return;
279 }
280 g_return_if_fail (target->e_type == ent->e_type);
281 e = qof_collection_lookup_entity (target, &ent->guid);
282 if (e == NULL)
283 {
284 value = 1;
285 qof_collection_set_data (target, &value);
286 return;
287 }
288 value = 0;
289 qof_collection_set_data (target, &value);
290 }
291
292 gint
293 qof_collection_compare (QofCollection * target, QofCollection * merge)
294 {
295 gint value;
296
297 value = 0;
298 if (!target && !merge)
299 return 0;
300 if (target == merge)
301 return 0;
302 if (!target && merge)
303 return -1;
304 if (target && !merge)
305 return 1;
306 if (target->e_type != merge->e_type)
307 return -1;
308 qof_collection_set_data (target, &value);
309 qof_collection_foreach (merge, collection_compare_cb, target);
310 value = *(gint *) qof_collection_get_data (target);
311 if (value == 0)
312 {
313 qof_collection_set_data (merge, &value);
314 qof_collection_foreach (target, collection_compare_cb, merge);
315 value = *(gint *) qof_collection_get_data (merge);
316 }
317 return value;
318 }
319
320 QofEntity *
321 qof_collection_lookup_entity (QofCollection * col, const GUID * guid)
322 {
323 QofEntity *ent;
324 g_return_val_if_fail (col, NULL);
325 if (guid == NULL)
326 return NULL;
327 ent = g_hash_table_lookup (col->hash_of_entities, guid);
328 return ent;
329 }
330
331 QofCollection *
332 qof_collection_from_glist (QofIdType type, GList * glist)
333 {
334 QofCollection *coll;
335 QofEntity *ent;
336 GList *list;
337
338 coll = qof_collection_new (type);
339 for (list = glist; list != NULL; list = list->next)
340 {
341 ent = (QofEntity *) list->data;
342 if (FALSE == qof_collection_add_entity (coll, ent))
343 {
344 return NULL;
345 }
346 }
347 return coll;
348 }
349
350 guint
351 qof_collection_count (QofCollection * col)
352 {
353 guint c;
354
355 c = g_hash_table_size (col->hash_of_entities);
356 return c;
357 }
358
359 /* =============================================================== */
360
361 gboolean
362 qof_collection_is_dirty (QofCollection * col)
363 {
364 return col ? col->is_dirty : FALSE;
365 }
366
367 void
368 qof_collection_mark_clean (QofCollection * col)
369 {
370 if (col)
371 {
372 col->is_dirty = FALSE;
373 }
374 }
375
376 void
377 qof_collection_mark_dirty (QofCollection * col)
378 {
379 if (col)
380 {
381 col->is_dirty = TRUE;
382 }
383 }
384
385 /* =============================================================== */
386
387 gpointer
388 qof_collection_get_data (QofCollection * col)
389 {
390 return col ? col->data : NULL;
391 }
392
393 void
394 qof_collection_set_data (QofCollection * col, gpointer user_data)
395 {
396 if (col)
397 {
398 col->data = user_data;
399 }
400 }
401
402 /* =============================================================== */
403
404 struct _iterate
405 {
406 QofEntityForeachCB fcn;
407 gpointer data;
408 };
409
410 static void
411 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item,
412 gpointer arg)
413 {
414 struct _iterate *qiter = arg;
415 QofEntity *ent = item;
416
417 qiter->fcn (ent, qiter->data);
418 }
419
420 void
421 qof_collection_foreach (QofCollection * col, QofEntityForeachCB cb_func,
422 gpointer user_data)
423 {
424 struct _iterate qiter;
425
426 g_return_if_fail (col);
427 g_return_if_fail (cb_func);
428
429 qiter.fcn = cb_func;
430 qiter.data = user_data;
431
432 g_hash_table_foreach (col->hash_of_entities, foreach_cb, &qiter);
433 }
434
435 /* =============================================================== */
qof_collection_add_entity
gboolean qof_collection_add_entity(QofCollection *coll, QofEntity *ent)
Add an entity to a QOF_TYPE_COLLECT.
Definition: qofid.c:211
guid_equal
gboolean guid_equal(const GUID *guid_1, const GUID *guid_2)
Definition: guid.c:652
PERR
#define PERR(format, args...)
Definition: qoflog.h:183
qof_collection_compare
gint qof_collection_compare(QofCollection *target, QofCollection *merge)
Compare two secondary collections.
Definition: qofid.c:293
QofIdType
const gchar * QofIdType
Definition: qofid.h:81
guid_null
const GUID * guid_null(void)
Definition: guid.c:119
qof_collection_is_dirty
gboolean qof_collection_is_dirty(QofCollection *col)
Definition: qofid.c:362
QofEntity_s
Definition: qofid.h:147
QofEntityForeachCB
void(* QofEntityForeachCB)(QofEntity *, gpointer user_data)
Definition: qofid.h:187
QofCollection
struct QofCollection_s QofCollection
Definition: qofid.h:138
qof_collection_from_glist
QofCollection * qof_collection_from_glist(QofIdType type, GList *glist)
Create a secondary collection from a GList.
Definition: qofid.c:332
qof_collection_count
guint qof_collection_count(QofCollection *col)
Definition: qofid.c:351
qof_collection_lookup_entity
QofEntity * qof_collection_lookup_entity(QofCollection *col, const GUID *guid)
Definition: qofid.c:321
qof_collection_foreach
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:421
qof_collection_set_data
void qof_collection_set_data(QofCollection *col, gpointer user_data)
Definition: qofid.c:394
qof_entity_release
void qof_entity_release(QofEntity *ent)
Definition: qofid.c:79
qof_collection_mark_clean
void qof_collection_mark_clean(QofCollection *col)
Definition: qofid.c:368
qof_collection_get_type
QofIdType qof_collection_get_type(QofCollection *col)
Definition: qofid.c:175
_GUID
Definition: guid.h:53
guid_new
void guid_new(GUID *guid)
Definition: guid.c:487
qof_collection_get_data
gpointer qof_collection_get_data(QofCollection *col)
Definition: qofid.c:388
PWARN
#define PWARN(format, args...)
Definition: qoflog.h:191
qof_collection_destroy
void qof_collection_destroy(QofCollection *col)
Definition: qofid.c:161
qof_entity_get_guid
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
qof_collection_new
QofCollection * qof_collection_new(QofIdType type)
Definition: qofid.c:150
qof_collection_merge
gboolean qof_collection_merge(QofCollection *target, QofCollection *merge)
Merge two QOF_TYPE_COLLECT of the same type.
Definition: qofid.c:245
qof_entity_set_guid
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
safe_strcmp
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:72
qof_entity_init
void qof_entity_init(QofEntity *ent, QofIdType type, QofCollection *tab)
Definition: qofid.c:49
QofLogModule
const gchar * QofLogModule
Definition: qofid.h:85
qof_collection_insert_entity
void qof_collection_insert_entity(QofCollection *col, QofEntity *ent)
Definition: qofid.c:197