Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

dict.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  * dict.c - lookup data structure using octet strings as keys
00059  *
00060  * The Dict is implemented as a simple hash table. In the future, it 
00061  * might be interesting to use a trie instead.
00062  *
00063  * Lars Wirzenius, based on code by Tuomas Luttinen
00064  */
00065 
00066 
00067 #include "gwlib.h"
00068 
00069 
00070 /*
00071  * The hash table stores key/value -pairs in a List.
00072  */
00073 
00074 typedef struct Item Item;
00075 struct Item {
00076     Octstr *key;
00077     void *value;
00078 };
00079 
00080 
00081 static Item *item_create(Octstr *key, void *value)
00082 {
00083     Item *item;
00084     
00085     item = gw_malloc(sizeof(*item));
00086     item->key = octstr_duplicate(key);
00087     item->value = value;
00088     return item;
00089 }
00090 
00091 static void item_destroy(void *item)
00092 {
00093     Item *p;
00094     
00095     p = item;
00096     octstr_destroy(p->key);
00097     gw_free(p);
00098 }
00099 
00100 
00101 static int item_has_key(void *item, void *key)
00102 {
00103     return octstr_compare(key, ((Item *) item)->key) == 0;
00104 }
00105 
00106 
00107 /*
00108  * The dictionary itself is a very simple hash table.
00109  * `tab' is an array of Lists of Items, in which empty Lists may be
00110  * represented as NULL.  `size' is the number of elements allocated
00111  * for the array, and `key_count' is the number of Items currently
00112  * in the table.  `key_count' is kept up to date by the put and remove
00113  * functions, and is used to make dict_key_count() faster.
00114  */
00115 
00116 struct Dict {
00117     List **tab;
00118     long size;
00119     long key_count;
00120     void (*destroy_value)(void *);
00121     Mutex *lock;
00122 };
00123 
00124 
00125 static void lock(Dict *dict)
00126 {
00127     mutex_lock(dict->lock);
00128 }
00129 
00130 
00131 static void unlock(Dict *dict)
00132 {
00133     mutex_unlock(dict->lock);
00134 }
00135 
00136 
00137 static long key_to_index(Dict *dict, Octstr *key)
00138 {
00139     return octstr_hash_key(key) % dict->size;
00140 }
00141 
00142 static int handle_null_value(Dict *dict, Octstr *key, void *value)
00143 {
00144     if (value == NULL) {
00145         value = dict_remove(dict, key);
00146     if (dict->destroy_value != NULL)
00147         dict->destroy_value(value);
00148         return 1;
00149     }
00150 
00151     return 0;
00152 }
00153 
00154 static int dict_put_true(Dict *dict, Octstr *key, void *value)
00155 {
00156     Item *p;
00157     long i;
00158     int item_unique;
00159 
00160     item_unique = 0;
00161     lock(dict);
00162     i = key_to_index(dict, key);
00163 
00164     if (dict->tab[i] == NULL) {
00165     dict->tab[i] = gwlist_create();
00166     p = NULL;
00167     } else {
00168     p = gwlist_search(dict->tab[i], key, item_has_key);
00169     }
00170 
00171     if (p == NULL) {
00172         p = item_create(key, value);
00173     gwlist_append(dict->tab[i], p);
00174         dict->key_count++;
00175         item_unique = 1;
00176     } else {
00177         if (dict->destroy_value != NULL)
00178             dict->destroy_value(value);
00179         item_unique = 0;
00180     }
00181 
00182     unlock(dict);
00183 
00184     return item_unique;
00185 }
00186 
00187 /*
00188  * And finally, the public functions.
00189  */
00190 
00191 
00192 Dict *dict_create(long size_hint, void (*destroy_value)(void *))
00193 {
00194     Dict *dict;
00195     long i;
00196     
00197     dict = gw_malloc(sizeof(*dict));
00198 
00199     /*
00200      * Hash tables tend to work well until they are fill to about 50%.
00201      */
00202     dict->size = size_hint * 2;
00203 
00204     dict->tab = gw_malloc(sizeof(dict->tab[0]) * dict->size);
00205     for (i = 0; i < dict->size; ++i)
00206         dict->tab[i] = NULL;
00207     dict->lock = mutex_create();
00208     dict->destroy_value = destroy_value;
00209     dict->key_count = 0;
00210     
00211     return dict;
00212 }
00213 
00214 
00215 void dict_destroy(Dict *dict)
00216 {
00217     long i;
00218     Item *p;
00219     
00220     if (dict == NULL)
00221         return;
00222 
00223     for (i = 0; i < dict->size; ++i) {
00224         if (dict->tab[i] == NULL)
00225         continue;
00226 
00227     while ((p = gwlist_extract_first(dict->tab[i])) != NULL) {
00228         if (dict->destroy_value != NULL)
00229             dict->destroy_value(p->value);
00230         item_destroy(p);
00231     }
00232     gwlist_destroy(dict->tab[i], NULL);
00233     }
00234     mutex_destroy(dict->lock);
00235     gw_free(dict->tab);
00236     gw_free(dict);
00237 }
00238 
00239 
00240 void dict_put(Dict *dict, Octstr *key, void *value)
00241 {
00242     long i;
00243     Item *p;
00244 
00245     if (value == NULL) {
00246         value = dict_remove(dict, key);
00247     if (dict->destroy_value != NULL)
00248         dict->destroy_value(value);
00249         return;
00250     }
00251 
00252     lock(dict);
00253     i = key_to_index(dict, key);
00254     if (dict->tab[i] == NULL) {
00255     dict->tab[i] = gwlist_create();
00256     p = NULL;
00257     } else
00258     p = gwlist_search(dict->tab[i], key, item_has_key);
00259     if (p == NULL) {
00260         p = item_create(key, value);
00261     gwlist_append(dict->tab[i], p);
00262         dict->key_count++;
00263     } else {
00264     if (dict->destroy_value != NULL)
00265         dict->destroy_value(p->value);
00266     p->value = value;
00267     }
00268     unlock(dict);
00269 }
00270 
00271 int dict_put_once(Dict *dict, Octstr *key, void *value)
00272 {
00273     int ret;
00274 
00275     ret = 1;
00276     if (handle_null_value(dict, key, value))
00277         return 1;
00278     if (dict_put_true(dict, key, value)) {
00279         ret = 1;
00280     } else {
00281         ret = 0;
00282     }
00283     return ret;
00284 }
00285 
00286 void *dict_get(Dict *dict, Octstr *key)
00287 {
00288     long i;
00289     Item *p;
00290     void *value;
00291 
00292     lock(dict);
00293     i = key_to_index(dict, key);
00294     if (dict->tab[i] == NULL)
00295     p = NULL;
00296     else
00297         p = gwlist_search(dict->tab[i], key, item_has_key);
00298     if (p == NULL)
00299         value = NULL;
00300     else
00301         value = p->value;
00302     unlock(dict);
00303     return value;
00304 }
00305 
00306 
00307 void *dict_remove(Dict *dict, Octstr *key)
00308 {
00309     long i;
00310     Item *p;
00311     void *value;
00312     List *list;
00313 
00314     lock(dict);
00315     i = key_to_index(dict, key);
00316     if (dict->tab[i] == NULL)
00317         list = NULL;
00318     else
00319         list = gwlist_extract_matching(dict->tab[i], key, item_has_key);
00320     gw_assert(list == NULL || gwlist_len(list) == 1);
00321     if (list == NULL)
00322         value = NULL;
00323     else {
00324     p = gwlist_get(list, 0);
00325     gwlist_destroy(list, NULL);
00326         value = p->value;
00327     item_destroy(p);
00328     dict->key_count--;
00329     }
00330     unlock(dict);
00331     return value;
00332 }
00333 
00334 
00335 long dict_key_count(Dict *dict)
00336 {
00337     long result;
00338 
00339     lock(dict);
00340     result = dict->key_count;
00341     unlock(dict);
00342 
00343     return result;
00344 }
00345 
00346 
00347 List *dict_keys(Dict *dict)
00348 {
00349     List *list;
00350     Item *item;
00351     long i, j;
00352     
00353     list = gwlist_create();
00354 
00355     lock(dict);
00356     for (i = 0; i < dict->size; ++i) {
00357     if (dict->tab[i] == NULL)
00358         continue;
00359     for (j = 0; j < gwlist_len(dict->tab[i]); ++j) {
00360         item = gwlist_get(dict->tab[i], j);
00361         gwlist_append(list, octstr_duplicate(item->key));
00362     }
00363     }
00364     unlock(dict);
00365     
00366     return list;
00367 }
00368 
00369 
00370 
00371 
00372 
00373 
00374 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.