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  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652       *
00021  * Boston, MA  02111-1307,  USA       gnu@gnu.org                   *
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;       /* place where object class can hang arbitrary 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   /* XXX We passed redundant info to this routine ... but I think that's
00056         * OK, it might eliminate programming errors. */
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 /* This is a restricted function, should be used only during 
00089  * read from file */
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   /* Compiler should optimize this all away! */
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 /* getters */
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 /* =============================================================== */

Generated on Fri Oct 21 15:49:55 2005 for QOF by  doxygen 1.4.5