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 guint
00115 id_hash (gconstpointer key)
00116 {
00117 const GUID *guid = key;
00118
00119 if (key == NULL)
00120 return 0;
00121
00122
00123 if (sizeof (guint) <= 16)
00124 return *((guint *) guid->data);
00125 else
00126 {
00127 guint hash = 0;
00128 guint i, j;
00129
00130 for (i = 0, j = 0; i < sizeof (guint); i++, j++)
00131 {
00132 if (j == 16)
00133 j = 0;
00134
00135 hash <<= 4;
00136 hash |= guid->data[j];
00137 }
00138
00139 return hash;
00140 }
00141 }
00142
00143 static gboolean
00144 id_compare (gconstpointer key_1, gconstpointer key_2)
00145 {
00146 return guid_equal (key_1, key_2);
00147 }
00148
00149 QofCollection *
00150 qof_collection_new (QofIdType type)
00151 {
00152 QofCollection *col;
00153 col = g_new0 (QofCollection, 1);
00154 col->e_type = CACHE_INSERT (type);
00155 col->hash_of_entities = g_hash_table_new (id_hash, id_compare);
00156 col->data = NULL;
00157 return col;
00158 }
00159
00160 void
00161 qof_collection_destroy (QofCollection * col)
00162 {
00163 CACHE_REMOVE (col->e_type);
00164 g_hash_table_destroy (col->hash_of_entities);
00165 col->e_type = NULL;
00166 col->hash_of_entities = NULL;
00167 col->data = NULL;
00168 g_free (col);
00169 }
00170
00171
00172
00173
00174 QofIdType
00175 qof_collection_get_type (QofCollection * col)
00176 {
00177 return col->e_type;
00178 }
00179
00180
00181
00182 static void
00183 qof_collection_remove_entity (QofEntity * ent)
00184 {
00185 QofCollection *col;
00186 if (!ent)
00187 return;
00188 col = ent->collection;
00189 if (!col)
00190 return;
00191 g_hash_table_remove (col->hash_of_entities, &ent->guid);
00192 qof_collection_mark_dirty (col);
00193 ent->collection = NULL;
00194 }
00195
00196 void
00197 qof_collection_insert_entity (QofCollection * col, QofEntity * ent)
00198 {
00199 if (!col || !ent)
00200 return;
00201 if (guid_equal (&ent->guid, guid_null ()))
00202 return;
00203 g_return_if_fail (col->e_type == ent->e_type);
00204 qof_collection_remove_entity (ent);
00205 g_hash_table_insert (col->hash_of_entities, &ent->guid, ent);
00206 qof_collection_mark_dirty (col);
00207 ent->collection = col;
00208 }
00209
00210 gboolean
00211 qof_collection_add_entity (QofCollection * coll, QofEntity * ent)
00212 {
00213 QofEntity *e;
00214
00215 e = NULL;
00216 if (!coll || !ent)
00217 {
00218 return FALSE;
00219 }
00220 if (guid_equal (&ent->guid, guid_null ()))
00221 {
00222 return FALSE;
00223 }
00224 g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
00225 e = qof_collection_lookup_entity (coll, &ent->guid);
00226 if (e != NULL)
00227 {
00228 return FALSE;
00229 }
00230 g_hash_table_insert (coll->hash_of_entities, &ent->guid, ent);
00231 qof_collection_mark_dirty (coll);
00232 return TRUE;
00233 }
00234
00235 static void
00236 collection_merge_cb (QofEntity * ent, gpointer data)
00237 {
00238 QofCollection *target;
00239
00240 target = (QofCollection *) data;
00241 qof_collection_add_entity (target, ent);
00242 }
00243
00244 gboolean
00245 qof_collection_merge (QofCollection * target, QofCollection * merge)
00246 {
00247 if (!target || !merge)
00248 {
00249 return FALSE;
00250 }
00251 g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
00252 qof_collection_foreach (merge, collection_merge_cb, target);
00253 return TRUE;
00254 }
00255
00256 static void
00257 collection_compare_cb (QofEntity * ent, gpointer user_data)
00258 {
00259 QofCollection *target;
00260 QofEntity *e;
00261 gint value;
00262
00263 e = NULL;
00264 target = (QofCollection *) user_data;
00265 if (!target || !ent)
00266 {
00267 return;
00268 }
00269 value = *(gint *) qof_collection_get_data (target);
00270 if (value != 0)
00271 {
00272 return;
00273 }
00274 if (guid_equal (&ent->guid, guid_null ()))
00275 {
00276 value = -1;
00277 qof_collection_set_data (target, &value);
00278 return;
00279 }
00280 g_return_if_fail (target->e_type == ent->e_type);
00281 e = qof_collection_lookup_entity (target, &ent->guid);
00282 if (e == NULL)
00283 {
00284 value = 1;
00285 qof_collection_set_data (target, &value);
00286 return;
00287 }
00288 value = 0;
00289 qof_collection_set_data (target, &value);
00290 }
00291
00292 gint
00293 qof_collection_compare (QofCollection * target, QofCollection * merge)
00294 {
00295 gint value;
00296
00297 value = 0;
00298 if (!target && !merge)
00299 return 0;
00300 if (target == merge)
00301 return 0;
00302 if (!target && merge)
00303 return -1;
00304 if (target && !merge)
00305 return 1;
00306 if (target->e_type != merge->e_type)
00307 return -1;
00308 qof_collection_set_data (target, &value);
00309 qof_collection_foreach (merge, collection_compare_cb, target);
00310 value = *(gint *) qof_collection_get_data (target);
00311 if (value == 0)
00312 {
00313 qof_collection_set_data (merge, &value);
00314 qof_collection_foreach (target, collection_compare_cb, merge);
00315 value = *(gint *) qof_collection_get_data (merge);
00316 }
00317 return value;
00318 }
00319
00320 QofEntity *
00321 qof_collection_lookup_entity (QofCollection * col, const GUID * guid)
00322 {
00323 QofEntity *ent;
00324 g_return_val_if_fail (col, NULL);
00325 if (guid == NULL)
00326 return NULL;
00327 ent = g_hash_table_lookup (col->hash_of_entities, guid);
00328 return ent;
00329 }
00330
00331 QofCollection *
00332 qof_collection_from_glist (QofIdType type, GList * glist)
00333 {
00334 QofCollection *coll;
00335 QofEntity *ent;
00336 GList *list;
00337
00338 coll = qof_collection_new (type);
00339 for (list = glist; list != NULL; list = list->next)
00340 {
00341 ent = (QofEntity *) list->data;
00342 if (FALSE == qof_collection_add_entity (coll, ent))
00343 {
00344 return NULL;
00345 }
00346 }
00347 return coll;
00348 }
00349
00350 guint
00351 qof_collection_count (QofCollection * col)
00352 {
00353 guint c;
00354
00355 c = g_hash_table_size (col->hash_of_entities);
00356 return c;
00357 }
00358
00359
00360
00361 gboolean
00362 qof_collection_is_dirty (QofCollection * col)
00363 {
00364 return col ? col->is_dirty : FALSE;
00365 }
00366
00367 void
00368 qof_collection_mark_clean (QofCollection * col)
00369 {
00370 if (col)
00371 {
00372 col->is_dirty = FALSE;
00373 }
00374 }
00375
00376 void
00377 qof_collection_mark_dirty (QofCollection * col)
00378 {
00379 if (col)
00380 {
00381 col->is_dirty = TRUE;
00382 }
00383 }
00384
00385
00386
00387 gpointer
00388 qof_collection_get_data (QofCollection * col)
00389 {
00390 return col ? col->data : NULL;
00391 }
00392
00393 void
00394 qof_collection_set_data (QofCollection * col, gpointer user_data)
00395 {
00396 if (col)
00397 {
00398 col->data = user_data;
00399 }
00400 }
00401
00402
00403
00404 struct _iterate
00405 {
00406 QofEntityForeachCB fcn;
00407 gpointer data;
00408 };
00409
00410 static void
00411 foreach_cb (gpointer key __attribute__ ((unused)), gpointer item,
00412 gpointer arg)
00413 {
00414 struct _iterate *qiter = arg;
00415 QofEntity *ent = item;
00416
00417 qiter->fcn (ent, qiter->data);
00418 }
00419
00420 void
00421 qof_collection_foreach (QofCollection * col, QofEntityForeachCB cb_func,
00422 gpointer user_data)
00423 {
00424 struct _iterate qiter;
00425
00426 g_return_if_fail (col);
00427 g_return_if_fail (cb_func);
00428
00429 qiter.fcn = cb_func;
00430 qiter.data = user_data;
00431
00432 g_hash_table_foreach (col->hash_of_entities, foreach_cb, &qiter);
00433 }
00434
00435