[BACK]Return to hcreate.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / stdlib

Annotation of src/lib/libc/stdlib/hcreate.c, Revision 1.8

1.8     ! christos    1: /* $NetBSD: hcreate.c,v 1.7 2011/09/14 23:33:51 christos Exp $ */
1.1       cgd         2:
                      3: /*
                      4:  * Copyright (c) 2001 Christopher G. Demetriou
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
1.8     ! christos   15:  * 3. The name of the author may not be used to endorse or promote products
1.1       cgd        16:  *    derived from this software without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     19:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     20:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     21:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     22:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     23:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     24:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     25:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     26:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     27:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     28:  *
                     29:  * <<Id: LICENSE,v 1.2 2000/06/14 15:57:33 cgd Exp>>
                     30:  */
                     31:
                     32: /*
                     33:  * hcreate() / hsearch() / hdestroy()
                     34:  *
                     35:  * SysV/XPG4 hash table functions.
                     36:  *
                     37:  * Implementation done based on NetBSD manual page and Solaris manual page,
                     38:  * plus my own personal experience about how they're supposed to work.
                     39:  *
                     40:  * I tried to look at Knuth (as cited by the Solaris manual page), but
                     41:  * nobody had a copy in the office, so...
                     42:  */
                     43:
                     44: #include <sys/cdefs.h>
                     45: #if defined(LIBC_SCCS) && !defined(lint)
1.8     ! christos   46: __RCSID("$NetBSD: hcreate.c,v 1.7 2011/09/14 23:33:51 christos Exp $");
1.1       cgd        47: #endif /* LIBC_SCCS and not lint */
                     48:
                     49: #if !defined(lint)
1.6       lukem      50: __COPYRIGHT("@(#) Copyright (c) 2001\
                     51:  Christopher G. Demetriou.  All rights reserved.");
1.1       cgd        52: #endif /* not lint */
                     53:
                     54: #include "namespace.h"
                     55: #include <assert.h>
                     56: #include <errno.h>
                     57: #include <inttypes.h>
                     58: #include <search.h>
                     59: #include <stdlib.h>
                     60: #include <string.h>
                     61: #include <sys/queue.h>
                     62:
                     63: /*
                     64:  * DO NOT MAKE THIS STRUCTURE LARGER THAN 32 BYTES (4 ptrs on 64-bit
                     65:  * ptr machine) without adjusting MAX_BUCKETS_LG2 below.
                     66:  */
                     67: struct internal_entry {
                     68:        SLIST_ENTRY(internal_entry) link;
                     69:        ENTRY ent;
                     70: };
                     71: SLIST_HEAD(internal_head, internal_entry);
                     72:
                     73: #define        MIN_BUCKETS_LG2 4
                     74: #define        MIN_BUCKETS     (1 << MIN_BUCKETS_LG2)
                     75:
                     76: /*
                     77:  * max * sizeof internal_entry must fit into size_t.
                     78:  * assumes internal_entry is <= 32 (2^5) bytes.
                     79:  */
                     80: #define        MAX_BUCKETS_LG2 (sizeof (size_t) * 8 - 1 - 5)
1.2       ross       81: #define        MAX_BUCKETS     ((size_t)1 << MAX_BUCKETS_LG2)
1.1       cgd        82:
                     83: /* Default hash function, from db/hash/hash_func.c */
                     84: extern u_int32_t (*__default_hash)(const void *, size_t);
                     85:
1.7       christos   86: static struct hsearch_data htable;
1.1       cgd        87:
                     88: int
                     89: hcreate(size_t nel)
                     90: {
1.7       christos   91:        _DIAGASSERT(htable.table == NULL);
1.1       cgd        92:
1.5       simonb     93:        /* Make sure this isn't called when a table already exists. */
1.7       christos   94:        if (htable.table != NULL) {
1.1       cgd        95:                errno = EINVAL;
                     96:                return 0;
                     97:        }
1.7       christos   98:        return hcreate_r(nel, &htable);
                     99: }
                    100:
                    101: int
                    102: hcreate_r(size_t nel, struct hsearch_data *head)
                    103: {
                    104:        struct internal_head *table;
                    105:        size_t idx;
                    106:        unsigned int p2;
                    107:        void *p;
1.1       cgd       108:
                    109:        /* If nel is too small, make it min sized. */
                    110:        if (nel < MIN_BUCKETS)
                    111:                nel = MIN_BUCKETS;
                    112:
                    113:        /* If it's too large, cap it. */
                    114:        if (nel > MAX_BUCKETS)
                    115:                nel = MAX_BUCKETS;
                    116:
                    117:        /* If it's is not a power of two in size, round up. */
                    118:        if ((nel & (nel - 1)) != 0) {
                    119:                for (p2 = 0; nel != 0; p2++)
                    120:                        nel >>= 1;
                    121:                _DIAGASSERT(p2 <= MAX_BUCKETS_LG2);
                    122:                nel = 1 << p2;
                    123:        }
                    124:
                    125:        /* Allocate the table. */
1.7       christos  126:        head->size = nel;
                    127:        head->filled = 0;
                    128:        p = malloc(nel * sizeof table[0]);
                    129:        if (p == NULL) {
1.1       cgd       130:                errno = ENOMEM;
                    131:                return 0;
                    132:        }
1.7       christos  133:        head->table = p;
                    134:        table = p;
1.1       cgd       135:
                    136:        /* Initialize it. */
1.7       christos  137:        for (idx = 0; idx < nel; idx++)
                    138:                SLIST_INIT(&table[idx]);
1.1       cgd       139:
                    140:        return 1;
                    141: }
                    142:
                    143: void
                    144: hdestroy(void)
                    145: {
1.7       christos  146:        _DIAGASSERT(htable.table != NULL);
                    147:        hdestroy_r(&htable);
                    148: }
                    149:
                    150: void
                    151: hdestroy_r(struct hsearch_data *head)
                    152: {
1.1       cgd       153:        struct internal_entry *ie;
                    154:        size_t idx;
1.7       christos  155:        void *p;
                    156:        struct internal_head *table;
1.1       cgd       157:
1.7       christos  158:        if (head == NULL)
1.1       cgd       159:                return;
                    160:
1.7       christos  161:        p = head->table;
                    162:        head->table = NULL;
                    163:        table = p;
                    164:
                    165:        for (idx = 0; idx < head->size; idx++) {
                    166:                while (!SLIST_EMPTY(&table[idx])) {
                    167:                        ie = SLIST_FIRST(&table[idx]);
                    168:                        SLIST_REMOVE_HEAD(&table[idx], link);
1.1       cgd       169:                        free(ie->ent.key);
                    170:                        free(ie);
                    171:                }
                    172:        }
1.7       christos  173:        free(table);
1.1       cgd       174: }
                    175:
                    176: ENTRY *
                    177: hsearch(ENTRY item, ACTION action)
                    178: {
1.7       christos  179:        ENTRY *ep;
                    180:        _DIAGASSERT(htable.table != NULL);
                    181:        (void)hsearch_r(item, action, &ep, &htable);
                    182:        return ep;
                    183: }
                    184:
                    185: int
                    186: hsearch_r(ENTRY item, ACTION action, ENTRY **itemp, struct hsearch_data *head)
                    187: {
                    188:        struct internal_head *table, *chain;
1.1       cgd       189:        struct internal_entry *ie;
                    190:        uint32_t hashval;
                    191:        size_t len;
1.7       christos  192:        void *p;
1.1       cgd       193:
1.3       lukem     194:        _DIAGASSERT(item.key != NULL);
                    195:        _DIAGASSERT(action == ENTER || action == FIND);
1.1       cgd       196:
1.7       christos  197:        p = head->table;
                    198:        table = p;
                    199:
1.1       cgd       200:        len = strlen(item.key);
                    201:        hashval = (*__default_hash)(item.key, len);
                    202:
1.7       christos  203:        chain = &table[hashval & (head->size - 1)];
                    204:        ie = SLIST_FIRST(chain);
1.1       cgd       205:        while (ie != NULL) {
                    206:                if (strcmp(ie->ent.key, item.key) == 0)
                    207:                        break;
                    208:                ie = SLIST_NEXT(ie, link);
                    209:        }
                    210:
1.7       christos  211:        if (ie != NULL) {
                    212:                *itemp = &ie->ent;
                    213:                return 1;
                    214:        } else if (action == FIND) {
                    215:                *itemp = NULL;
                    216:                errno = ESRCH;
                    217:                return 1;
                    218:        }
1.1       cgd       219:
                    220:        ie = malloc(sizeof *ie);
                    221:        if (ie == NULL)
1.7       christos  222:                return 0;
1.1       cgd       223:        ie->ent.key = item.key;
                    224:        ie->ent.data = item.data;
                    225:
1.7       christos  226:        SLIST_INSERT_HEAD(chain, ie, link);
                    227:        *itemp = &ie->ent;
                    228:        head->filled++;
                    229:        return 1;
1.1       cgd       230: }

CVSweb <webmaster@jp.NetBSD.org>