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