[BACK]Return to compat_ohash.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/compat_ohash.c, Revision 1.2

1.1       kristaps    1: #ifdef HAVE_CONFIG_H
                      2: #include "config.h"
                      3: #endif
                      4:
                      5: #ifdef HAVE_OHASH
                      6:
                      7: int dummy;
                      8:
                      9: #else
                     10:
                     11: /*     $OpenBSD: ohash_int.h,v 1.3 2006/01/16 15:52:25 espie Exp $     */
                     12:
                     13: #include <stddef.h>
                     14: #include <stdint.h>
                     15: #include <stdlib.h>
                     16: #include <string.h>
                     17: #include "compat_ohash.h"
                     18:
                     19: struct _ohash_record {
1.2     ! schwarze   20:        uint32_t        hv;
1.1       kristaps   21:        const char      *p;
                     22: };
                     23:
                     24: #define DELETED                ((const char *)h)
                     25: #define NONE           (h->size)
                     26:
                     27: /* Don't bother changing the hash table if the change is small enough.  */
                     28: #define MINSIZE                (1UL << 4)
                     29: #define MINDELETED     4
                     30: /* $OpenBSD: ohash_create_entry.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
                     31: /* ex:ts=8 sw=4:
                     32:  */
                     33:
                     34: /* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
                     35:  *
                     36:  * Permission to use, copy, modify, and distribute this software for any
                     37:  * purpose with or without fee is hereby granted, provided that the above
                     38:  * copyright notice and this permission notice appear in all copies.
                     39:  *
                     40:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     41:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     42:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     43:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     44:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     45:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     46:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     47:  */
                     48:
                     49: /* This handles the common case of variable length keys, where the
                     50:  * key is stored at the end of the record.
                     51:  */
                     52: void *
                     53: ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
                     54: {
                     55:        char *p;
                     56:
                     57:        if (!*end)
                     58:                *end = start + strlen(start);
                     59:        p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
                     60:        if (p) {
                     61:            memcpy(p+i->key_offset, start, *end-start);
                     62:            p[i->key_offset + (*end - start)] = '\0';
                     63:        }
                     64:        return (void *)p;
                     65: }
                     66:
                     67: /* hash_delete only frees the hash structure. Use hash_first/hash_next
                     68:  * to free entries as well.  */
                     69: void
                     70: ohash_delete(struct ohash *h)
                     71: {
                     72:        (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
                     73:                h->info.data);
                     74: #ifndef NDEBUG
                     75:        h->t = NULL;
                     76: #endif
                     77: }
                     78:
                     79: static void ohash_resize(struct ohash *);
                     80:
                     81: static void
                     82: ohash_resize(struct ohash *h)
                     83: {
                     84:        struct _ohash_record *n;
                     85:        unsigned int    ns, j;
                     86:        unsigned int    i, incr;
                     87:
                     88:        if (4 * h->deleted < h->total)
                     89:                ns = h->size << 1;
                     90:        else if (3 * h->deleted > 2 * h->total)
                     91:                ns = h->size >> 1;
                     92:        else
                     93:                ns = h->size;
                     94:        if (ns < MINSIZE)
                     95:                ns = MINSIZE;
                     96: #ifdef STATS_HASH
                     97:        STAT_HASH_EXPAND++;
                     98:        STAT_HASH_SIZE += ns - h->size;
                     99: #endif
                    100:        n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data);
                    101:        if (!n)
                    102:                return;
                    103:
                    104:        for (j = 0; j < h->size; j++) {
                    105:                if (h->t[j].p != NULL && h->t[j].p != DELETED) {
                    106:                        i = h->t[j].hv % ns;
                    107:                        incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
                    108:                        while (n[i].p != NULL) {
                    109:                                i += incr;
                    110:                                if (i >= ns)
                    111:                                        i -= ns;
                    112:                        }
                    113:                        n[i].hv = h->t[j].hv;
                    114:                        n[i].p = h->t[j].p;
                    115:                }
                    116:        }
                    117:        (h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
                    118:                h->info.data);
                    119:        h->t = n;
                    120:        h->size = ns;
                    121:        h->total -= h->deleted;
                    122:        h->deleted = 0;
                    123: }
                    124:
                    125: void *
                    126: ohash_remove(struct ohash *h, unsigned int i)
                    127: {
                    128:        void            *result = (void *)h->t[i].p;
                    129:
                    130:        if (result == NULL || result == DELETED)
                    131:                return NULL;
                    132:
                    133: #ifdef STATS_HASH
                    134:        STAT_HASH_ENTRIES--;
                    135: #endif
                    136:        h->t[i].p = DELETED;
                    137:        h->deleted++;
                    138:        if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
                    139:                ohash_resize(h);
                    140:        return result;
                    141: }
                    142:
                    143: void *
                    144: ohash_find(struct ohash *h, unsigned int i)
                    145: {
                    146:        if (h->t[i].p == DELETED)
                    147:                return NULL;
                    148:        else
                    149:                return (void *)h->t[i].p;
                    150: }
                    151:
                    152: void *
                    153: ohash_insert(struct ohash *h, unsigned int i, void *p)
                    154: {
                    155: #ifdef STATS_HASH
                    156:        STAT_HASH_ENTRIES++;
                    157: #endif
                    158:        if (h->t[i].p == DELETED) {
                    159:                h->deleted--;
                    160:                h->t[i].p = p;
                    161:        } else {
                    162:                h->t[i].p = p;
                    163:        /* Arbitrary resize boundary.  Tweak if not efficient enough.  */
                    164:                if (++h->total * 4 > h->size * 3)
                    165:                        ohash_resize(h);
                    166:        }
                    167:        return p;
                    168: }
                    169:
                    170: unsigned int
                    171: ohash_entries(struct ohash *h)
                    172: {
                    173:        return h->total - h->deleted;
                    174: }
                    175:
                    176: void *
                    177: ohash_first(struct ohash *h, unsigned int *pos)
                    178: {
                    179:        *pos = 0;
                    180:        return ohash_next(h, pos);
                    181: }
                    182:
                    183: void *
                    184: ohash_next(struct ohash *h, unsigned int *pos)
                    185: {
                    186:        for (; *pos < h->size; (*pos)++)
                    187:                if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
                    188:                        return (void *)h->t[(*pos)++].p;
                    189:        return NULL;
                    190: }
                    191:
                    192: void
                    193: ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
                    194: {
                    195:        h->size = 1UL << size;
                    196:        if (h->size < MINSIZE)
                    197:                h->size = MINSIZE;
                    198: #ifdef STATS_HASH
                    199:        STAT_HASH_CREATION++;
                    200:        STAT_HASH_SIZE += h->size;
                    201: #endif
                    202:        /* Copy info so that caller may free it.  */
                    203:        h->info.key_offset = info->key_offset;
                    204:        h->info.halloc = info->halloc;
                    205:        h->info.hfree = info->hfree;
                    206:        h->info.alloc = info->alloc;
                    207:        h->info.data = info->data;
                    208:        h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size,
                    209:            h->info.data);
                    210:        h->total = h->deleted = 0;
                    211: }
                    212:
                    213: uint32_t
                    214: ohash_interval(const char *s, const char **e)
                    215: {
                    216:        uint32_t k;
                    217:
                    218:        if (!*e)
                    219:                *e = s + strlen(s);
                    220:        if (s == *e)
                    221:                k = 0;
                    222:        else
                    223:                k = *s++;
                    224:        while (s != *e)
                    225:                k =  ((k << 2) | (k >> 30)) ^ *s++;
                    226:        return k;
                    227: }
                    228:
                    229: unsigned int
                    230: ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
                    231:     uint32_t hv)
                    232: {
                    233:        unsigned int    i, incr;
                    234:        unsigned int    empty;
                    235:
                    236: #ifdef STATS_HASH
                    237:        STAT_HASH_LOOKUP++;
                    238: #endif
                    239:        empty = NONE;
                    240:        i = hv % h->size;
                    241:        incr = ((hv % (h->size-2)) & ~1) + 1;
                    242:        while (h->t[i].p != NULL) {
                    243: #ifdef STATS_HASH
                    244:                STAT_HASH_LENGTH++;
                    245: #endif
                    246:                if (h->t[i].p == DELETED) {
                    247:                        if (empty == NONE)
                    248:                                empty = i;
                    249:                } else if (h->t[i].hv == hv &&
                    250:                    strncmp(h->t[i].p+h->info.key_offset, start,
                    251:                        end - start) == 0 &&
                    252:                    (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
                    253:                        if (empty != NONE) {
                    254:                                h->t[empty].hv = hv;
                    255:                                h->t[empty].p = h->t[i].p;
                    256:                                h->t[i].p = DELETED;
                    257:                                return empty;
                    258:                        } else {
                    259: #ifdef STATS_HASH
                    260:                                STAT_HASH_POSITIVE++;
                    261: #endif
                    262:                                return i;
                    263:                        }
                    264:                }
                    265:                i += incr;
                    266:                if (i >= h->size)
                    267:                        i -= h->size;
                    268:        }
                    269:
                    270:        /* Found an empty position.  */
                    271:        if (empty != NONE)
                    272:                i = empty;
                    273:        h->t[i].hv = hv;
                    274:        return i;
                    275: }
                    276:
                    277: unsigned int
                    278: ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
                    279: {
                    280:        unsigned int    i, incr;
                    281:        unsigned int    empty;
                    282:
                    283: #ifdef STATS_HASH
                    284:        STAT_HASH_LOOKUP++;
                    285: #endif
                    286:        empty = NONE;
                    287:        i = hv % h->size;
                    288:        incr = ((hv % (h->size-2)) & ~1) + 1;
                    289:        while (h->t[i].p != NULL) {
                    290: #ifdef STATS_HASH
                    291:                STAT_HASH_LENGTH++;
                    292: #endif
                    293:                if (h->t[i].p == DELETED) {
                    294:                        if (empty == NONE)
                    295:                                empty = i;
                    296:                } else if (h->t[i].hv == hv &&
                    297:                    memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
                    298:                        if (empty != NONE) {
                    299:                                h->t[empty].hv = hv;
                    300:                                h->t[empty].p = h->t[i].p;
                    301:                                h->t[i].p = DELETED;
                    302:                                return empty;
                    303:                        } else {
                    304: #ifdef STATS_HASH
                    305:                                STAT_HASH_POSITIVE++;
                    306: #endif
                    307:                        }       return i;
                    308:                }
                    309:                i += incr;
                    310:                if (i >= h->size)
                    311:                        i -= h->size;
                    312:        }
                    313:
                    314:        /* Found an empty position.  */
                    315:        if (empty != NONE)
                    316:                i = empty;
                    317:        h->t[i].hv = hv;
                    318:        return i;
                    319: }
                    320:
                    321: unsigned int
                    322: ohash_qlookup(struct ohash *h, const char *s)
                    323: {
                    324:        const char *e = NULL;
                    325:        return ohash_qlookupi(h, s, &e);
                    326: }
                    327:
                    328: unsigned int
                    329: ohash_qlookupi(struct ohash *h, const char *s, const char **e)
                    330: {
1.2     ! schwarze  331:        uint32_t hv;
1.1       kristaps  332:
                    333:        hv = ohash_interval(s, e);
                    334:        return ohash_lookup_interval(h, s, *e, hv);
                    335: }
                    336:
                    337: #endif /*!HAVE_OHASH*/

CVSweb