symtab.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2011-2013  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 1996-2001  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /* $Id$ */
00019 
00020 /*! \file */
00021 
00022 #include <config.h>
00023 
00024 #include <ctype.h>
00025 
00026 #include <isc/magic.h>
00027 #include <isc/mem.h>
00028 #include <isc/string.h>
00029 #include <isc/symtab.h>
00030 #include <isc/util.h>
00031 
00032 typedef struct elt {
00033         char *                          key;
00034         unsigned int                    type;
00035         isc_symvalue_t                  value;
00036         LINK(struct elt)                link;
00037 } elt_t;
00038 
00039 typedef LIST(elt_t)                     eltlist_t;
00040 
00041 #define SYMTAB_MAGIC                    ISC_MAGIC('S', 'y', 'm', 'T')
00042 #define VALID_SYMTAB(st)                ISC_MAGIC_VALID(st, SYMTAB_MAGIC)
00043 
00044 struct isc_symtab {
00045         /* Unlocked. */
00046         unsigned int                    magic;
00047         isc_mem_t *                     mctx;
00048         unsigned int                    size;
00049         unsigned int                    count;
00050         unsigned int                    maxload;
00051         eltlist_t *                     table;
00052         isc_symtabaction_t              undefine_action;
00053         void *                          undefine_arg;
00054         isc_boolean_t                   case_sensitive;
00055 };
00056 
00057 isc_result_t
00058 isc_symtab_create(isc_mem_t *mctx, unsigned int size,
00059                   isc_symtabaction_t undefine_action,
00060                   void *undefine_arg,
00061                   isc_boolean_t case_sensitive,
00062                   isc_symtab_t **symtabp)
00063 {
00064         isc_symtab_t *symtab;
00065         unsigned int i;
00066 
00067         REQUIRE(mctx != NULL);
00068         REQUIRE(symtabp != NULL && *symtabp == NULL);
00069         REQUIRE(size > 0);      /* Should be prime. */
00070 
00071         symtab = (isc_symtab_t *)isc_mem_get(mctx, sizeof(*symtab));
00072         if (symtab == NULL)
00073                 return (ISC_R_NOMEMORY);
00074 
00075         symtab->mctx = NULL;
00076         isc_mem_attach(mctx, &symtab->mctx);
00077         symtab->table = (eltlist_t *)isc_mem_get(mctx,
00078                                                  size * sizeof(eltlist_t));
00079         if (symtab->table == NULL) {
00080                 isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
00081                 return (ISC_R_NOMEMORY);
00082         }
00083         for (i = 0; i < size; i++)
00084                 INIT_LIST(symtab->table[i]);
00085         symtab->size = size;
00086         symtab->count = 0;
00087         symtab->maxload = size * 3 / 4;
00088         symtab->undefine_action = undefine_action;
00089         symtab->undefine_arg = undefine_arg;
00090         symtab->case_sensitive = case_sensitive;
00091         symtab->magic = SYMTAB_MAGIC;
00092 
00093         *symtabp = symtab;
00094 
00095         return (ISC_R_SUCCESS);
00096 }
00097 
00098 void
00099 isc_symtab_destroy(isc_symtab_t **symtabp) {
00100         isc_symtab_t *symtab;
00101         unsigned int i;
00102         elt_t *elt, *nelt;
00103 
00104         REQUIRE(symtabp != NULL);
00105         symtab = *symtabp;
00106         REQUIRE(VALID_SYMTAB(symtab));
00107 
00108         for (i = 0; i < symtab->size; i++) {
00109                 for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
00110                         nelt = NEXT(elt, link);
00111                         if (symtab->undefine_action != NULL)
00112                                (symtab->undefine_action)(elt->key,
00113                                                          elt->type,
00114                                                          elt->value,
00115                                                          symtab->undefine_arg);
00116                         isc_mem_put(symtab->mctx, elt, sizeof(*elt));
00117                 }
00118         }
00119         isc_mem_put(symtab->mctx, symtab->table,
00120                     symtab->size * sizeof(eltlist_t));
00121         symtab->magic = 0;
00122         isc_mem_putanddetach(&symtab->mctx, symtab, sizeof(*symtab));
00123 
00124         *symtabp = NULL;
00125 }
00126 
00127 static inline unsigned int
00128 hash(const char *key, isc_boolean_t case_sensitive) {
00129         const char *s;
00130         unsigned int h = 0;
00131         int c;
00132 
00133         /*
00134          * This hash function is similar to the one Ousterhout
00135          * uses in Tcl.
00136          */
00137 
00138         if (case_sensitive) {
00139                 for (s = key; *s != '\0'; s++) {
00140                         h += (h << 3) + *s;
00141                 }
00142         } else {
00143                 for (s = key; *s != '\0'; s++) {
00144                         c = *s;
00145                         c = tolower((unsigned char)c);
00146                         h += (h << 3) + c;
00147                 }
00148         }
00149 
00150         return (h);
00151 }
00152 
00153 #define FIND(s, k, t, b, e) \
00154         b = hash((k), (s)->case_sensitive) % (s)->size; \
00155         if ((s)->case_sensitive) { \
00156                 for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
00157                         if (((t) == 0 || e->type == (t)) && \
00158                             strcmp(e->key, (k)) == 0) \
00159                                 break; \
00160                 } \
00161         } else { \
00162                 for (e = HEAD((s)->table[b]); e != NULL; e = NEXT(e, link)) { \
00163                         if (((t) == 0 || e->type == (t)) && \
00164                             strcasecmp(e->key, (k)) == 0) \
00165                                 break; \
00166                 } \
00167         }
00168 
00169 isc_result_t
00170 isc_symtab_lookup(isc_symtab_t *symtab, const char *key, unsigned int type,
00171                   isc_symvalue_t *value)
00172 {
00173         unsigned int bucket;
00174         elt_t *elt;
00175 
00176         REQUIRE(VALID_SYMTAB(symtab));
00177         REQUIRE(key != NULL);
00178 
00179         FIND(symtab, key, type, bucket, elt);
00180 
00181         if (elt == NULL)
00182                 return (ISC_R_NOTFOUND);
00183 
00184         if (value != NULL)
00185                 *value = elt->value;
00186 
00187         return (ISC_R_SUCCESS);
00188 }
00189 
00190 static void
00191 grow_table(isc_symtab_t *symtab) {
00192         eltlist_t *newtable;
00193         unsigned int i, newsize, newmax;
00194 
00195         REQUIRE(symtab != NULL);
00196 
00197         newsize = symtab->size * 2;
00198         newmax = newsize * 3 / 4;
00199         INSIST(newsize > 0U && newmax > 0U);
00200 
00201         newtable = isc_mem_get(symtab->mctx, newsize * sizeof(eltlist_t));
00202         if (newtable == NULL)
00203                 return;
00204 
00205         for (i = 0; i < newsize; i++)
00206                 INIT_LIST(newtable[i]);
00207 
00208         for (i = 0; i < symtab->size; i++) {
00209                 elt_t *elt, *nelt;
00210 
00211                 for (elt = HEAD(symtab->table[i]); elt != NULL; elt = nelt) {
00212                         unsigned int hv;
00213 
00214                         nelt = NEXT(elt, link);
00215 
00216                         UNLINK(symtab->table[i], elt, link);
00217                         hv = hash(elt->key, symtab->case_sensitive);
00218                         APPEND(newtable[hv % newsize], elt, link);
00219                 }
00220         }
00221 
00222         isc_mem_put(symtab->mctx, symtab->table,
00223                     symtab->size * sizeof(eltlist_t));
00224 
00225         symtab->table = newtable;
00226         symtab->size = newsize;
00227         symtab->maxload = newmax;
00228 }
00229 
00230 isc_result_t
00231 isc_symtab_define(isc_symtab_t *symtab, const char *key, unsigned int type,
00232                   isc_symvalue_t value, isc_symexists_t exists_policy)
00233 {
00234         unsigned int bucket;
00235         elt_t *elt;
00236 
00237         REQUIRE(VALID_SYMTAB(symtab));
00238         REQUIRE(key != NULL);
00239         REQUIRE(type != 0);
00240 
00241         FIND(symtab, key, type, bucket, elt);
00242 
00243         if (exists_policy != isc_symexists_add && elt != NULL) {
00244                 if (exists_policy == isc_symexists_reject)
00245                         return (ISC_R_EXISTS);
00246                 INSIST(exists_policy == isc_symexists_replace);
00247                 UNLINK(symtab->table[bucket], elt, link);
00248                 if (symtab->undefine_action != NULL)
00249                         (symtab->undefine_action)(elt->key, elt->type,
00250                                                   elt->value,
00251                                                   symtab->undefine_arg);
00252         } else {
00253                 elt = (elt_t *)isc_mem_get(symtab->mctx, sizeof(*elt));
00254                 if (elt == NULL)
00255                         return (ISC_R_NOMEMORY);
00256                 ISC_LINK_INIT(elt, link);
00257                 symtab->count++;
00258         }
00259 
00260         /*
00261          * Though the "key" can be const coming in, it is not stored as const
00262          * so that the calling program can easily have writable access to
00263          * it in its undefine_action function.  In the event that it *was*
00264          * truly const coming in and then the caller modified it anyway ...
00265          * well, don't do that!
00266          */
00267         DE_CONST(key, elt->key);
00268         elt->type = type;
00269         elt->value = value;
00270 
00271         /*
00272          * We prepend so that the most recent definition will be found.
00273          */
00274         PREPEND(symtab->table[bucket], elt, link);
00275 
00276         if (symtab->count > symtab->maxload)
00277                 grow_table(symtab);
00278 
00279         return (ISC_R_SUCCESS);
00280 }
00281 
00282 isc_result_t
00283 isc_symtab_undefine(isc_symtab_t *symtab, const char *key, unsigned int type) {
00284         unsigned int bucket;
00285         elt_t *elt;
00286 
00287         REQUIRE(VALID_SYMTAB(symtab));
00288         REQUIRE(key != NULL);
00289 
00290         FIND(symtab, key, type, bucket, elt);
00291 
00292         if (elt == NULL)
00293                 return (ISC_R_NOTFOUND);
00294 
00295         if (symtab->undefine_action != NULL)
00296                 (symtab->undefine_action)(elt->key, elt->type,
00297                                           elt->value, symtab->undefine_arg);
00298         UNLINK(symtab->table[bucket], elt, link);
00299         isc_mem_put(symtab->mctx, elt, sizeof(*elt));
00300         symtab->count--;
00301 
00302         return (ISC_R_SUCCESS);
00303 }
00304 
00305 unsigned int
00306 isc_symtab_count(isc_symtab_t *symtab) {
00307         REQUIRE(VALID_SYMTAB(symtab));
00308         return (symtab->count);
00309 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha