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)) break;
00067
00068 PWARN("duplicate id created, trying again");
00069 } while(1);
00070
00071 ent->collection = tab;
00072
00073 qof_collection_insert_entity (tab, ent);
00074 }
00075
00076 void
00077 qof_entity_release (QofEntity *ent)
00078 {
00079 if (!ent->collection) return;
00080 qof_collection_remove_entity (ent);
00081 CACHE_REMOVE (ent->e_type);
00082 ent->e_type = NULL;
00083 }
00084
00085
00086
00087
00088 void
00089 qof_entity_set_guid (QofEntity *ent, const GUID *guid)
00090 {
00091 QofCollection *col;
00092 if (guid_equal (guid, &ent->guid)) return;
00093
00094 col = ent->collection;
00095 qof_collection_remove_entity (ent);
00096 ent->guid = *guid;
00097 qof_collection_insert_entity (col, ent);
00098 }
00099
00100 const GUID *
00101 qof_entity_get_guid (QofEntity *ent)
00102 {
00103 if (!ent) return guid_null();
00104 return &ent->guid;
00105 }
00106
00107
00108
00109 static guint
00110 id_hash (gconstpointer key)
00111 {
00112 const GUID *guid = key;
00113
00114 if (key == NULL)
00115 return 0;
00116
00117
00118 if (sizeof(guint) <= 16)
00119 return *((guint *) guid->data);
00120 else
00121 {
00122 guint hash = 0;
00123 unsigned int i, j;
00124
00125 for (i = 0, j = 0; i < sizeof(guint); i++, j++)
00126 {
00127 if (j == 16)
00128 j = 0;
00129
00130 hash <<= 4;
00131 hash |= guid->data[j];
00132 }
00133
00134 return hash;
00135 }
00136 }
00137
00138 static gboolean
00139 id_compare(gconstpointer key_1, gconstpointer key_2)
00140 {
00141 return guid_equal (key_1, key_2);
00142 }
00143
00144 QofCollection *
00145 qof_collection_new (QofIdType type)
00146 {
00147 QofCollection *col;
00148 col = g_new0(QofCollection, 1);
00149 col->e_type = CACHE_INSERT (type);
00150 col->hash_of_entities = g_hash_table_new (id_hash, id_compare);
00151 col->data = NULL;
00152 return col;
00153 }
00154
00155 void
00156 qof_collection_destroy (QofCollection *col)
00157 {
00158 CACHE_REMOVE (col->e_type);
00159 g_hash_table_destroy(col->hash_of_entities);
00160 col->e_type = NULL;
00161 col->hash_of_entities = NULL;
00162 col->data = NULL;
00163 g_free (col);
00164 }
00165
00166
00167
00168
00169 QofIdType
00170 qof_collection_get_type (QofCollection *col)
00171 {
00172 return col->e_type;
00173 }
00174
00175
00176
00177 static void
00178 qof_collection_remove_entity (QofEntity *ent)
00179 {
00180 QofCollection *col;
00181 if (!ent) return;
00182 col = ent->collection;
00183 if (!col) return;
00184 g_hash_table_remove (col->hash_of_entities, &ent->guid);
00185 qof_collection_mark_dirty(col);
00186 ent->collection = NULL;
00187 }
00188
00189 void
00190 qof_collection_insert_entity (QofCollection *col, QofEntity *ent)
00191 {
00192 if (!col || !ent) return;
00193 if (guid_equal(&ent->guid, guid_null())) return;
00194 g_return_if_fail (col->e_type == ent->e_type);
00195 qof_collection_remove_entity (ent);
00196 g_hash_table_insert (col->hash_of_entities, &ent->guid, ent);
00197 qof_collection_mark_dirty(col);
00198 ent->collection = col;
00199 }
00200
00201 gboolean
00202 qof_collection_add_entity (QofCollection *coll, QofEntity *ent)
00203 {
00204 QofEntity *e;
00205
00206 e = NULL;
00207 if (!coll || !ent) { return FALSE; }
00208 if (guid_equal(&ent->guid, guid_null())) { return FALSE; }
00209 g_return_val_if_fail (coll->e_type == ent->e_type, FALSE);
00210 e = qof_collection_lookup_entity(coll, &ent->guid);
00211 if ( e != NULL ) { return FALSE; }
00212 g_hash_table_insert (coll->hash_of_entities, &ent->guid, ent);
00213 qof_collection_mark_dirty(coll);
00214 return TRUE;
00215 }
00216
00217 static void
00218 collection_merge_cb (QofEntity *ent, gpointer data)
00219 {
00220 QofCollection *target;
00221
00222 target = (QofCollection*)data;
00223 qof_collection_add_entity(target, ent);
00224 }
00225
00226 gboolean
00227 qof_collection_merge (QofCollection *target, QofCollection *merge)
00228 {
00229 if(!target || !merge) { return FALSE; }
00230 g_return_val_if_fail (target->e_type == merge->e_type, FALSE);
00231 qof_collection_foreach(merge, collection_merge_cb, target);
00232 return TRUE;
00233 }
00234
00235 static void
00236 collection_compare_cb (QofEntity *ent, gpointer user_data)
00237 {
00238 QofCollection *target;
00239 QofEntity *e;
00240 gint value;
00241
00242 e = NULL;
00243 target = (QofCollection*)user_data;
00244 if (!target || !ent) { return; }
00245 value = *(gint*)qof_collection_get_data(target);
00246 if (value != 0) { return; }
00247 if (guid_equal(&ent->guid, guid_null()))
00248 {
00249 value = -1;
00250 qof_collection_set_data(target, &value);
00251 return;
00252 }
00253 g_return_if_fail (target->e_type == ent->e_type);
00254 e = qof_collection_lookup_entity(target, &ent->guid);
00255 if ( e == NULL )
00256 {
00257 value = 1;
00258 qof_collection_set_data(target, &value);
00259 return;
00260 }
00261 value = 0;
00262 qof_collection_set_data(target, &value);
00263 }
00264
00265 gint
00266 qof_collection_compare (QofCollection *target, QofCollection *merge)
00267 {
00268 gint value;
00269
00270 value = 0;
00271 if (!target && !merge) { return 0; }
00272 if (target == merge) { return 0; }
00273 if (!target && merge) { return -1; }
00274 if (target && !merge) { return 1; }
00275 if(target->e_type != merge->e_type) { return -1; }
00276 qof_collection_set_data(target, &value);
00277 qof_collection_foreach(merge, collection_compare_cb, target);
00278 value = *(gint*)qof_collection_get_data(target);
00279 if(value == 0) {
00280 qof_collection_set_data(merge, &value);
00281 qof_collection_foreach(target, collection_compare_cb, merge);
00282 value = *(gint*)qof_collection_get_data(merge);
00283 }
00284 return value;
00285 }
00286
00287 QofEntity *
00288 qof_collection_lookup_entity (QofCollection *col, const GUID * guid)
00289 {
00290 QofEntity *ent;
00291 g_return_val_if_fail (col, NULL);
00292 if (guid == NULL) return NULL;
00293 ent = g_hash_table_lookup (col->hash_of_entities, guid);
00294 return ent;
00295 }
00296
00297 QofCollection *
00298 qof_collection_from_glist (QofIdType type, GList *glist)
00299 {
00300 QofCollection *coll;
00301 QofEntity *ent;
00302 GList *list;
00303
00304 coll = qof_collection_new(type);
00305 for(list = glist; list != NULL; list = list->next)
00306 {
00307 ent = (QofEntity*)list->data;
00308 if(FALSE == qof_collection_add_entity(coll, ent))
00309 {
00310 return NULL;
00311 }
00312 }
00313 return coll;
00314 }
00315
00316 guint
00317 qof_collection_count (QofCollection *col)
00318 {
00319 guint c;
00320
00321 c = g_hash_table_size(col->hash_of_entities);
00322 return c;
00323 }
00324
00325
00326
00327 gboolean
00328 qof_collection_is_dirty (QofCollection *col)
00329 {
00330 return col ? col->is_dirty : FALSE;
00331 }
00332
00333 void
00334 qof_collection_mark_clean (QofCollection *col)
00335 {
00336 if (col) { col->is_dirty = FALSE; }
00337 }
00338
00339 void
00340 qof_collection_mark_dirty (QofCollection *col)
00341 {
00342 if (col) { col->is_dirty = TRUE; }
00343 }
00344
00345
00346
00347 gpointer
00348 qof_collection_get_data (QofCollection *col)
00349 {
00350 return col ? col->data : NULL;
00351 }
00352
00353 void
00354 qof_collection_set_data (QofCollection *col, gpointer user_data)
00355 {
00356 if (col) { col->data = user_data; }
00357 }
00358
00359
00360
00361 struct _iterate {
00362 QofEntityForeachCB fcn;
00363 gpointer data;
00364 };
00365
00366 static void foreach_cb (gpointer key, gpointer item, gpointer arg)
00367 {
00368 struct _iterate *iter = arg;
00369 QofEntity *ent = item;
00370
00371 iter->fcn (ent, iter->data);
00372 }
00373
00374 void
00375 qof_collection_foreach (QofCollection *col, QofEntityForeachCB cb_func,
00376 gpointer user_data)
00377 {
00378 struct _iterate iter;
00379
00380 g_return_if_fail (col);
00381 g_return_if_fail (cb_func);
00382
00383 iter.fcn = cb_func;
00384 iter.data = user_data;
00385
00386 g_hash_table_foreach (col->hash_of_entities, foreach_cb, &iter);
00387 }
00388
00389