QOF
0.8.0
|
00001 /********************************************************************\ 00002 * qofid.c -- QOF entity identifier implementation * 00003 * Copyright (C) 2000 Dave Peticolas <dave@krondo.com> * 00004 * Copyright (C) 2003 Linas Vepstas <linas@linas.org> * 00005 * * 00006 * This program is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU General Public License as * 00008 * published by the Free Software Foundation; either version 2 of * 00009 * the License, or (at your option) any later version. * 00010 * * 00011 * This program is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00014 * GNU General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU General Public License* 00017 * along with this program; if not, contact: * 00018 * * 00019 * Free Software Foundation Voice: +1-617-542-5942 * 00020 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 * 00021 * Boston, MA 02110-1301, USA gnu@gnu.org * 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; /* place where object class can hang arbitrary 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 /* XXX We passed redundant info to this routine ... but I think that's 00054 * OK, it might eliminate programming errors. */ 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 /* This is a restricted function, should be used only during 00090 * read from file */ 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 /* Compiler should optimize this all away! */ 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 /* getters */ 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 /* =============================================================== */