Annotation of objc/maptable.m, revision 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.