00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026
00027 #include <string.h>
00028 #include <glib.h>
00029
00030 #include "qof.h"
00031 #include "qofid-p.h"
00032
00033 static QofLogModule log_module = QOF_MOD_ENGINE;
00034
00035 struct QofCollection_s
00036 {
00037 QofIdType e_type;
00038 gboolean is_dirty;
00039
00040 GHashTable *hash_of_entities;
00041 gpointer data;
00042 };
00043
00044
00045
00046 static void qof_collection_remove_entity (QofEntity * ent);
00047
00048 void
00049 qof_entity_init (QofEntity * ent, QofIdType type, QofCollection * tab)
00050 {
00051 g_return_if_fail (NULL != tab);
00052
00053
00054
00055 if (safe_strcmp (tab->e_type, type))
00056 {
00057 PERR ("attempt to insert \"%s\" into \"%s\"", type, tab->e_type);
00058 return;
00059 }
00060 ent->e_type = CACHE_INSERT (type);
00061
00062 do
00063 {
00064 guid_new (&ent->guid);
00065
00066 if (NULL == qof_collection_lookup_entity (tab, &ent->guid))
00067 break;
00068
00069 PWARN ("duplicate id created, trying again");
00070 }
00071 while (1);
00072
00073 ent->collection = tab;
00074
00075 qof_collection_insert_entity (tab, ent);
00076 }
00077
00078 void
00079 qof_entity_release (QofEntity * ent)
00080 {
00081 if (!ent->collection)
00082 return;
00083 qof_collection_remove_entity (ent);
00084 CACHE_REMOVE (ent->e_type);
00085 ent->e_type = NULL;
00086 }
00087
00088
00089
00090
00091 void
00092 qof_entity_set_guid (QofEntity * ent, const GUID * guid)
00093 {
00094 QofCollection *col;
00095 if (guid_equal (guid, &ent->guid))
00096 return;
00097
00098 col = ent->collection;
00099 qof_collection_remove_entity (ent);
00100 ent->guid = *guid;
00101 qof_collection_insert_entity (col, ent);
00102 }
00103
00104 const GUID *
00105 qof_entity_get_guid (QofEntity * ent)
00106 {
00107 if (!ent)
00108 return guid_null ();
00109 return &ent->guid;
00110 }
00111
00112
00113
00114 static gboolean
00115 id_compare (gconstpointer key_1, gconstpointer key_2)
00116 {
00117 return guid_equal (key_1, key_2);
00118 }
00119
00120 QofCollection *
00121 qof_collection_new (QofIdType type)
00122 {
00123 QofCollection *col;
00124 col = g_new0 (QofCollection, 1);
00125 col->e_type = CACHE_INSERT (type);
00126 col->hash_of_entities = g_hash_table_new (guid_hash_to_guint, id_compare);
00127 col->data = NULL;
00128 return col;
00129 }
00130
00131 void
00132 qof_collection_destroy (QofCollection * col)
00133 {
00134 CACHE_REMOVE (col->e_type);
00135 g_hash_table_destroy (col->hash_of_entities);
00136 col->e_type = NULL;
00137 col->hash_of_entities = NULL;
00138 col->data = NULL;
00139 g_free (col);
00140 }
00141
00142
00143
00144
00145 QofIdType
00146 qof_collection_get_type (QofCollection * col)
00147 {
00148 return col->e_type;
00149 }
00150
00151
00152
00153 static void
00154 qof_collection_remove_entity (QofEntity * ent)
00155 {
00156 QofCollection *col;
00157 if (!ent)
00158 return;
00159 col = ent->collection;
00160 if (!col)
00161 return;
00162 g_hash_table_remove (col->hash_of_entities, &ent->guid);
00163 qof_collection_mark_dirty (col);
00164 ent->collection = NULL;
00165 }
00166
00167 void
00168 qof_collection_insert_entity (QofCollection * col, QofEntity * ent)
00169 {
00170 if (!col || !ent)
00171 return;
00172 if (guid_equal (&ent->guid, guid_null ()))
00173 return;
00174 g_return_if_fail (col->e_type == ent->e_type);
00175 qof_collection_remove_entity (ent);
00176 g_hash_table_insert (col->hash_of_entities, &ent->guid, ent);
00177 qof_collection_mark_dirty (col);
00178 ent->collection = col;
00179 }
00180
00181 gboolean
00182 qof_collection_add_entity (QofCollection * coll, QofEntity * ent)
00183 {
00184 QofEntity *e;
00185
00186 e = NULL;
00187 if (!coll || !ent)
00188 {
00189 return FALSE;
00190 }
00191 if (guid_equal (&ent->guid, guid_null ()))
00192 {
00193 return FALSE;
00194 }
00195 g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
00196 e = qof_collection_lookup_entity (coll, &ent->guid);
00197 if (e != NULL)
00198 {
00199 return FALSE;
00200 }
00201 g_hash_table_insert (coll->hash_of_entities, &ent->guid, ent);
00202 qof_collection_mark_dirty (coll);
00203 return TRUE;
00204 }
00205
00206 static void
00207 collection_merge_cb (QofEntity * ent, gpointer data)
00208 {
00209 QofCollection *target;
00210
00211 target = (QofCollection *) data;
00212 qof_collection_add_entity (target, ent);
00213 }
00214
00215 gboolean
00216 qof_collection_merge (QofCollection * target, QofCollection * merge)
00217 {
00218 if (!target || !merge)
00219 {
00220 return FALSE;
00221 }
00222 g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
00223 qof_collection_foreach (merge, collection_merge_cb, target);
00224 return TRUE;
00225 }
00226
00227 static void
00228 collection_compare_cb (QofEntity * ent, gpointer user_data)
00229 {
00230 QofCollection *target;
00231 QofEntity *e;
00232 gint value;
00233
00234 e = NULL;
00235 target = (QofCollection *) user_data;
00236 if (!target || !ent)
00237 {
00238 return;
00239 }
00240 value = *(gint *) qof_collection_get_data (target);
00241 if (value != 0)
00242 {
00243 return;
00244 }
00245 if (guid_equal (&ent->guid, guid_null ()))
00246 {
00247 value = -1;
00248 qof_collection_set_data (target, &value);
00249 return;
00250 }
00251 g_return_if_fail (target->e_type == ent->e_type);
00252 e = qof_collection_lookup_entity (target, &ent->guid);
00253 if (e == NULL)
00254 {
00255 value = 1;
00256 qof_collection_set_data (target, &value);
00257 return;
00258 }
00259 value = 0;
00260 qof_collection_set_data (target, &value);
00261 }
00262
00263 gint
00264 qof_collection_compare (QofCollection * target, QofCollection * merge)
00265 {
00266 gint value;
00267
00268 value = 0;
00269 if (!target && !merge)
00270 return 0;
00271 if (target == merge)
00272 return 0;
00273 if (!target && merge)
00274 return -1;
00275 if (target && !merge)
00276 return 1;
00277 if (target->e_type != merge->e_type)
00278 return -1;
00279 qof_collection_set_data (target, &value);
00280 qof_collection_foreach (merge, collection_compare_cb, target);
00281 value = *(gint *) qof_collection_get_data (target);
00282 if (value == 0)
00283 {
00284 qof_collection_set_data (merge, &value);
00285 qof_collection_foreach (target, collection_compare_cb, merge);
00286 value = *(gint *) qof_collection_get_data (merge);
00287 }
00288 return value;
00289 }
00290
00291 QofEntity *
00292 qof_collection_lookup_entity (QofCollection * col, const GUID * guid)
00293 {
00294 QofEntity *ent;
00295 g_return_val_if_fail (col, NULL);
00296 if (guid == NULL)
00297 return NULL;
00298 ent = g_hash_table_lookup (col->hash_of_entities, guid);
00299 return ent;
00300 }
00301
00302 QofCollection *
00303 qof_collection_from_glist (QofIdType type, GList * glist)
00304 {
00305 QofCollection *coll;
00306 QofEntity *ent;
00307 GList *list;
00308
00309 coll = qof_collection_new (type);
00310 for (list = glist; list != NULL; list = list->next)
00311 {
00312 ent = (QofEntity *) list->data;
00313 if (FALSE == qof_collection_add_entity (coll, ent))
00314 {
00315 return NULL;
00316 }
00317 }
00318 return coll;
00319 }
00320
00321 guint
00322 qof_collection_count (QofCollection * col)
00323 {
00324 guint c;
00325
00326 c = g_hash_table_size (col->hash_of_entities);
00327 return c;
00328 }
00329
00330
00331
00332 gboolean
00333 qof_collection_is_dirty (QofCollection * col)
00334 {
00335 return col ? col->is_dirty : FALSE;
00336 }
00337
00338 void
00339 qof_collection_mark_clean (QofCollection * col)
00340 {
00341 if (col)
00342 {
00343 col->is_dirty = FALSE;
00344 }
00345 }
00346
00347 void
00348 qof_collection_mark_dirty (QofCollection * col)
00349 {
00350 if (col)
00351 {
00352 col->is_dirty = TRUE;
00353 }
00354 }
00355
00356
00357
00358 gpointer
00359 qof_collection_get_data (QofCollection * col)
00360 {
00361 return col ? col->data : NULL;
00362 }
00363
00364 void
00365 qof_collection_set_data (QofCollection * col, gpointer user_data)
00366 {
00367 if (col)
00368 {
00369 col->data = user_data;
00370 }
00371 }
00372
00373
00374
00375 struct _iterate
00376 {
00377 QofEntityForeachCB fcn;
00378 gpointer data;
00379 };
00380
00381 static void
00382 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item,
00383 gpointer arg)
00384 {
00385 struct _iterate *qiter = arg;
00386 QofEntity *ent = item;
00387
00388 qiter->fcn (ent, qiter->data);
00389 }
00390
00391 void
00392 qof_collection_foreach (QofCollection * col, QofEntityForeachCB cb_func,
00393 gpointer user_data)
00394 {
00395 struct _iterate qiter;
00396
00397 g_return_if_fail (col);
00398 g_return_if_fail (cb_func);
00399
00400 qiter.fcn = cb_func;
00401 qiter.data = user_data;
00402
00403 g_hash_table_foreach (col->hash_of_entities, foreach_cb, &qiter);
00404 }
00405
00406