Annotation of objc/maptable.m, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.0 (the 'License').  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License."
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: /*     maptable.m
                     25:        Copyright 1990 NeXT, Inc.
                     26:        Created by Bertrand Serlet, August 1990
                     27:  */
                     28: 
                     29: #ifdef SHLIB
                     30: #import "shlib.h"
                     31: #endif SHLIB
                     32: 
                     33: #import "objc-private.h"
                     34: #import "maptable.h"
                     35: 
                     36: #import <string.h>
                     37: #import <stdlib.h>
                     38: #import <stdio.h>
                     39: #import "Object.h"
                     40: #import "hashtable.h"
                     41: 
                     42: /******                Macros and utilities    ****************************/
                     43: 
                     44: #if DEBUG
                     45: #define INLINE 
                     46: #else
                     47: #define INLINE inline
                     48: #endif
                     49: 
                     50: typedef struct _MapPair {
                     51:     const void *key;
                     52:     const void *value;
                     53: } MapPair;
                     54: 
                     55: static unsigned log2(unsigned x) { return (x<2) ? 0 : log2(x>>1)+1; };
                     56: 
                     57: static INLINE unsigned exp2m1(unsigned x) { return (1 << x) - 1; };
                     58: 
                     59: /* iff necessary this modulo can be optimized since the nbBuckets is of the form 2**n-1 */
                     60: static INLINE unsigned bucketOf(NXMapTable *table, const void *key) {
                     61:     unsigned   hash = (table->prototype->hash)(table, key);
                     62:     unsigned   xored = (hash & 0xffff) ^ (hash >> 16);
                     63:     return ((xored * 65521) + hash) % table->nbBuckets;
                     64: }
                     65: 
                     66: static INLINE int isEqual(NXMapTable *table, const void *key1, const void *key2) {
                     67:     return (key1 == key2) ? 1 : (table->prototype->isEqual)(table, key1, key2);
                     68: }
                     69: 
                     70: static INLINE unsigned nextIndex(NXMapTable *table, unsigned index) {
                     71:     return (index+1 >= table->nbBuckets) ? 0 : index+1;
                     72: }
                     73: 
                     74: static INLINE void *allocBuckets(NXZone *zone, unsigned nb) {
                     75:     MapPair    *pairs = NXZoneMalloc(zone, (nb * sizeof(MapPair)));
                     76:     MapPair    *pair = pairs;
                     77:     while (nb--) { pair->key = NX_MAPNOTAKEY; pair->value = NULL; pair++; }
                     78:     return pairs;
                     79: }
                     80: 
                     81: /*****         Global data and bootstrap       **********************/
                     82: 
                     83: static unsigned hashPrototype(const void *info, const void *data) {
                     84:     NXMapTablePrototype        *proto = (NXMapTablePrototype *) data;
                     85:     return NXPtrHash(info, proto->hash) ^ NXPtrHash(info, proto->isEqual) ^ NXPtrHash(info, proto->free) ^ (unsigned) proto->style;
                     86: }
                     87: 
                     88: static int isEqualPrototype(const void *info, const void *data1, const void *data2) {
                     89:     NXMapTablePrototype        *proto1 = (NXMapTablePrototype *) data1;
                     90:     NXMapTablePrototype        *proto2 = (NXMapTablePrototype *) data2;
                     91:     return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);
                     92: }
                     93:     
                     94: static NXHashTablePrototype protoPrototype = {
                     95:     hashPrototype, isEqualPrototype, NXNoEffectFree, 0
                     96: };
                     97: 
                     98: static NXHashTable *prototypes = NULL;
                     99:        /* table of all prototypes */
                    100: 
                    101: /****          Fundamentals Operations                 **************/
                    102: 
                    103: NXMapTable *NXCreateMapTableFromZone(NXMapTablePrototype prototype, unsigned capacity, NXZone *zone) {
                    104:     NXMapTable                 *table = NXZoneMalloc(zone, sizeof(NXMapTable));
                    105:     NXMapTablePrototype                *proto;
                    106:     if (! prototypes) prototypes = NXCreateHashTable(protoPrototype, 0, NULL);
                    107:     if (! prototype.hash || ! prototype.isEqual || ! prototype.free || prototype.style) {
                    108:        _NXLogError("*** NXCreateMapTable: invalid creation parameters\n");
                    109:        return NULL;
                    110:     }
                    111:     proto = NXHashGet(prototypes, &prototype); 
                    112:     if (! proto) {
                    113:        proto = malloc(sizeof(NXMapTablePrototype));
                    114:        *proto = prototype;
                    115:        (void)NXHashInsert(prototypes, proto);
                    116:     }
                    117:     table->prototype = proto; table->count = 0;
                    118:     table->nbBuckets = exp2m1(log2(capacity)+1);
                    119:     table->buckets = allocBuckets(zone, table->nbBuckets);
                    120:     return table;
                    121: }
                    122: 
                    123: NXMapTable *NXCreateMapTable(NXMapTablePrototype prototype, unsigned capacity) {
                    124:     return NXCreateMapTableFromZone(prototype, capacity, NXDefaultMallocZone());
                    125: }
                    126: 
                    127: void NXFreeMapTable(NXMapTable *table) {
                    128:     NXResetMapTable(table);
                    129:     free(table->buckets);
                    130:     free(table);
                    131: }
                    132: 
                    133: void NXResetMapTable(NXMapTable *table) {
                    134:     MapPair    *pairs = table->buckets;
                    135:     void       (*freeProc)(struct _NXMapTable *, void *, void *) = table->prototype->free;
                    136:     unsigned   index = table->nbBuckets;
                    137:     while (index--) {
                    138:        if (pairs->key != NX_MAPNOTAKEY) {
                    139:            freeProc(table, (void *)pairs->key, (void *)pairs->value);
                    140:            pairs->key = NX_MAPNOTAKEY; pairs->value = NULL;
                    141:        }
                    142:        pairs++;
                    143:     }
                    144:     table->count = 0;
                    145: }
                    146: 
                    147: BOOL NXCompareMapTables(NXMapTable *table1, NXMapTable *table2) {
                    148:     if (table1 == table2) return YES;
                    149:     if (table1->count != table2->count) return NO;
                    150:     else {
                    151:        void            *key;
                    152:        void            *value;
                    153:        NXMapState      state = NXInitMapState(table1);
                    154:        while (NXNextMapState(table1, &state, &key, &value)) {
                    155:            if (NXMapMember(table2, key, &value) == NX_MAPNOTAKEY) return NO;
                    156:        }
                    157:        return YES;
                    158:     }
                    159: }
                    160: 
                    161: unsigned NXCountMapTable(NXMapTable *table) { return table->count; }
                    162: 
                    163: static int mapSearch = 0;
                    164: static int mapSearchHit = 0;
                    165: static int mapSearchLoop = 0;
                    166: 
                    167: static INLINE void *_NXMapMember(NXMapTable *table, const void *key, void **value) {
                    168:     MapPair    *pairs = table->buckets;
                    169:     unsigned   index = bucketOf(table, key);
                    170:     MapPair    *pair = pairs + index;
                    171:     if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
                    172:     mapSearch ++;
                    173:     if (isEqual(table, pair->key, key)) {
                    174:        *value = (void *)pair->value;
                    175:        mapSearchHit ++;
                    176:        return (void *)pair->key;
                    177:     } else {
                    178:        unsigned        index2 = index;
                    179:        while ((index2 = nextIndex(table, index2)) != index) {
                    180:            mapSearchLoop ++;
                    181:            pair = pairs + index2;
                    182:            if (pair->key == NX_MAPNOTAKEY) return NX_MAPNOTAKEY;
                    183:            if (isEqual(table, pair->key, key)) {
                    184:                *value = (void *)pair->value;
                    185:                return (void *)pair->key;
                    186:            }
                    187:        }
                    188:        return NX_MAPNOTAKEY;
                    189:     }
                    190: }
                    191: 
                    192: void *NXMapMember(NXMapTable *table, const void *key, void **value) {
                    193:     return _NXMapMember(table, key, value);
                    194: }
                    195: 
                    196: void *NXMapGet(NXMapTable *table, const void *key) {
                    197:     void       *value;
                    198:     return (_NXMapMember(table, key, &value) != NX_MAPNOTAKEY) ? value : NULL;
                    199: }
                    200: 
                    201: static int mapRehash = 0;
                    202: static int mapRehashSum = 0;
                    203: 
                    204: static void _NXMapRehash(NXMapTable *table) {
                    205:     MapPair    *pairs = table->buckets;
                    206:     MapPair    *pair = pairs;
                    207:     unsigned   index = table->nbBuckets;
                    208:     unsigned   oldCount = table->count;
                    209:     table->nbBuckets += table->nbBuckets + 1; /* 2 times + 1 */
                    210:     table->count = 0; 
                    211:     table->buckets = allocBuckets(NXZoneFromPtr(table), table->nbBuckets);
                    212:     mapRehash ++;
                    213:     mapRehashSum += table->count;
                    214:     while (index--) {
                    215:        if (pair->key != NX_MAPNOTAKEY) {
                    216:            (void)NXMapInsert(table, pair->key, pair->value);
                    217:        }
                    218:        pair++;
                    219:     }
                    220:     if (oldCount != table->count)
                    221:        _NXLogError("*** maptable: count differs after rehashing; probably indicates a broken invariant: there are x and y such as isEqual(x, y) is TRUE but hash(x) != hash (y)\n");
                    222:     free(pairs); 
                    223: }
                    224: 
                    225: static int mapInsert = 0;
                    226: static int mapInsertHit = 0;
                    227: static int mapInsertLoop = 0;
                    228: 
                    229: void *NXMapInsert(NXMapTable *table, const void *key, const void *value) {
                    230:     MapPair    *pairs = table->buckets;
                    231:     unsigned   index = bucketOf(table, key);
                    232:     MapPair    *pair = pairs + index;
                    233:     if (key == NX_MAPNOTAKEY) {
                    234:        _NXLogError("*** NXMapInsert: invalid key: -1\n");
                    235:        return NULL;
                    236:     }
                    237:     mapInsert ++;
                    238:     if (pair->key == NX_MAPNOTAKEY) {
                    239:        mapInsertHit ++;
                    240:        pair->key = key; pair->value = value;
                    241:        table->count++;
                    242:        return NULL;
                    243:     }
                    244:     if (isEqual(table, pair->key, key)) {
                    245:        const void      *old = pair->value;
                    246:        mapInsertHit ++;
                    247:        if (old != value) pair->value = value;/* avoid writing unless needed! */
                    248:        return (void *)old;
                    249:     } else if (table->count == table->nbBuckets) {
                    250:        /* no room: rehash and retry */
                    251:        _NXMapRehash(table);
                    252:        return NXMapInsert(table, key, value);
                    253:     } else {
                    254:        unsigned        index2 = index;
                    255:        while ((index2 = nextIndex(table, index2)) != index) {
                    256:            mapInsertLoop ++;
                    257:            pair = pairs + index2;
                    258:            if (pair->key == NX_MAPNOTAKEY) {
                    259: #if INSERT_TAIL
                    260:               pair->key = key; pair->value = value;
                    261: #else
                    262:               MapPair         current = {key, value};
                    263:               index2 = index;
                    264:               while (current.key != NX_MAPNOTAKEY) {
                    265:                   MapPair             temp;
                    266:                   pair = pairs + index2;
                    267:                   temp = *pair;
                    268:                   *pair = current;
                    269:                   current = temp;
                    270:                   index2 = nextIndex(table, index2);
                    271:               }
                    272: #endif
                    273:                table->count++;
                    274:                if (table->count * 4 > table->nbBuckets * 3) _NXMapRehash(table);
                    275:                return NULL;
                    276:            }
                    277:            if (isEqual(table, pair->key, key)) {
                    278:                const void      *old = pair->value;
                    279:                if (old != value) pair->value = value;/* avoid writing unless needed! */
                    280:                return (void *)old;
                    281:            }
                    282:        }
                    283:        /* no room: can't happen! */
                    284:        _NXLogError("**** NXMapInsert: bug\n");
                    285:        return NULL;
                    286:     }
                    287: }
                    288: 
                    289: static int mapRemove = 0;
                    290: 
                    291: void *NXMapRemove(NXMapTable *table, const void *key) {
                    292:     MapPair    *pairs = table->buckets;
                    293:     unsigned   index = bucketOf(table, key);
                    294:     MapPair    *pair = pairs + index;
                    295:     unsigned   chain = 1; /* number of non-nil pairs in a row */
                    296:     int                found = 0;
                    297:     const void *old = NULL;
                    298:     if (pair->key == NX_MAPNOTAKEY) return NULL;
                    299:     mapRemove ++;
                    300:     /* compute chain */
                    301:     {
                    302:        unsigned        index2 = index;
                    303:        if (isEqual(table, pair->key, key)) {found ++; old = pair->value; }
                    304:        while ((index2 = nextIndex(table, index2)) != index) {
                    305:            pair = pairs + index2;
                    306:            if (pair->key == NX_MAPNOTAKEY) break;
                    307:            if (isEqual(table, pair->key, key)) {found ++; old = pair->value; }
                    308:            chain++;
                    309:        }
                    310:     }
                    311:     if (! found) return NULL;
                    312:     if (found != 1) _NXLogError("**** NXMapRemove: incorrect table\n");
                    313:     /* remove then reinsert */
                    314:     {
                    315:        MapPair buffer[16];
                    316:        MapPair *aux = (chain > 16) ? malloc(sizeof(MapPair)*(chain-1)) : buffer;
                    317:        int     auxnb = 0;
                    318:        int     nb = chain;
                    319:        unsigned        index2 = index;
                    320:        while (nb--) {
                    321:            pair = pairs + index2;
                    322:            if (! isEqual(table, pair->key, key)) aux[auxnb++] = *pair;
                    323:            pair->key = NX_MAPNOTAKEY; pair->value = NULL;
                    324:            index2 = nextIndex(table, index2);
                    325:        }
                    326:        table->count -= chain;
                    327:        if (auxnb != chain-1) _NXLogError("**** NXMapRemove: bug\n");
                    328:        while (auxnb--) NXMapInsert(table, aux[auxnb].key, aux[auxnb].value);
                    329:        if (chain > 16) free(aux);
                    330:     }
                    331:     return (void *)old;
                    332: }
                    333: 
                    334: NXMapState NXInitMapState(NXMapTable *table) {
                    335:     NXMapState state;
                    336:     state.index = table->nbBuckets;
                    337:     return state;
                    338: }
                    339:     
                    340: int NXNextMapState(NXMapTable *table, NXMapState *state, const void **key, const void **value) {
                    341:     MapPair    *pairs = table->buckets;
                    342:     while (state->index--) {
                    343:        MapPair *pair = pairs + state->index;
                    344:        if (pair->key != NX_MAPNOTAKEY) {
                    345:            *key = pair->key; *value = pair->value;
                    346:            return YES;
                    347:        }
                    348:     }
                    349:     return NO;
                    350: }
                    351: 
                    352: /****          Conveniences            *************************************/
                    353: 
                    354: unsigned _mapPtrHash(NXMapTable *table, const void *key) {
                    355:     return (((unsigned) key) >> 16) ^ ((unsigned) key);
                    356: }
                    357:     
                    358: unsigned _mapStrHash(NXMapTable *table, const void *key) {
                    359:     unsigned           hash = 0;
                    360:     unsigned char      *s = (unsigned char *)key;
                    361:     /* unsigned to avoid a sign-extend */
                    362:     /* unroll the loop */
                    363:     if (s) for (; ; ) { 
                    364:        if (*s == '\0') break;
                    365:        hash ^= *s++;
                    366:        if (*s == '\0') break;
                    367:        hash ^= *s++ << 8;
                    368:        if (*s == '\0') break;
                    369:        hash ^= *s++ << 16;
                    370:        if (*s == '\0') break;
                    371:        hash ^= *s++ << 24;
                    372:     }
                    373:     return hash;
                    374: }
                    375:     
                    376: unsigned _mapObjectHash(NXMapTable *table, const void *key) {
                    377:     return [(id)key hash];
                    378: }
                    379:     
                    380: int _mapPtrIsEqual(NXMapTable *table, const void *key1, const void *key2) {
                    381:     return key1 == key2;
                    382: }
                    383: 
                    384: int _mapStrIsEqual(NXMapTable *table, const void *key1, const void *key2) {
                    385:     if (key1 == key2) return YES;
                    386:     if (! key1) return ! strlen ((char *) key2);
                    387:     if (! key2) return ! strlen ((char *) key1);
                    388:     if (((char *) key1)[0] != ((char *) key2)[0]) return NO;
                    389:     return (strcmp((char *) key1, (char *) key2)) ? NO : YES;
                    390: }
                    391:     
                    392: int _mapObjectIsEqual(NXMapTable *table, const void *key1, const void *key2) {
                    393:     return [(id)key1 isEqual:(id)key2];
                    394: }
                    395:     
                    396: void _mapNoFree(NXMapTable *table, void *key, void *value) {}
                    397: 
                    398: void _mapObjectFree(NXMapTable *table, void *key, void *value) {
                    399:     [(id)key free];
                    400: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.