QOF 0.8.2
|
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 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 /* getters */ 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 /* =============================================================== */