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))
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 /* =============================================================== */

Generated on Thu Jan 31 22:50:26 2008 for QOF by  doxygen 1.5.4