qofid.c

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)) 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 /* This is a restricted function, should be used only during 
00087  * read from file */
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   /* Compiler should optimize this all away! */
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 /* getters */
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 /* =============================================================== */

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4