Annotation of objc/HashTable.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: /*
        !            25:        HashTable.m
        !            26:        Copyright 1988, 1989 NeXT, Inc.
        !            27:        Written by Bertrand Serlet, Dec 88
        !            28:        Responsibility: Bertrand Serlet
        !            29: */
        !            30: 
        !            31: #ifdef SHLIB
        !            32: #import "shlib.h"
        !            33: #endif SHLIB
        !            34: 
        !            35: #import <stdlib.h>
        !            36: #import <stdio.h>
        !            37: #import <string.h>
        !            38: #import "HashTable.h"
        !            39: #import "NXStringTable.h"
        !            40: #import "objc-private.h"
        !            41: 
        !            42: typedef struct {const void *key; void *value;} Pair;
        !            43: typedef        Pair    *Pairs;
        !            44: typedef struct {unsigned count; Pairs pairs;} Bucket;
        !            45: typedef        Bucket  *Buckets;
        !            46: 
        !            47: #define INITCAPA       1       /* _nbBuckets has to be a 2**N-1, and at least 1 */
        !            48: #define PAIRSSIZE(count) ((count) * sizeof(Pair))
        !            49: #define HASHSTR(str) (_objc_strhash (str))
        !            50: #define HASHINT(x) ((((unsigned) x) >> 16) ^ ((unsigned) x))
        !            51: 
        !            52: static unsigned log2 (unsigned x) { return (x<2) ? 0 : log2 (x>>1)+1; };
        !            53: 
        !            54: static unsigned exp2m1 (unsigned x) { return (1 << x) - 1; };
        !            55: 
        !            56: static unsigned hash (const char *keyDesc, const void *aKey, unsigned mod) {
        !            57:     switch (keyDesc[0]) {
        !            58:        case '@': return [(id) aKey hash] % mod;
        !            59:        case '%':
        !            60:        case '*': return aKey ? HASHSTR (aKey) % mod : 0;
        !            61:        default: return HASHINT (aKey) % mod;
        !            62:        };
        !            63:     };  
        !            64:     
        !            65: static unsigned isEqual (const char *keyDesc, const void *key1, const void *key2) {
        !            66:     if (key1 == key2) return YES;
        !            67:     switch (keyDesc[0]) {
        !            68:        case '@': return [(id) key1 isEqual: (id) key2];
        !            69:        case '%':
        !            70:        case '*':
        !            71:                if (! key1) return (strlen (key2) == 0);
        !            72:                if (! key2) return (strlen (key1) == 0);
        !            73:                if (((char *) key1)[0] != ((char *) key2)[0]) return NO;
        !            74:                return (strcmp (key1, key2) == 0);
        !            75:        default: return NO;
        !            76:        };
        !            77:     };
        !            78:     
        !            79: static void freeObject (void *item) {
        !            80:     [(id) item free];
        !            81:     };
        !            82:     
        !            83: static void noFree (void *item) {
        !            84:     };
        !            85:     
        !            86: @implementation  HashTable
        !            87: 
        !            88: + initialize
        !            89: {
        !            90:     [self setVersion: 1];
        !            91:     return self;
        !            92: }
        !            93: 
        !            94: - _initBare: (const char *) aKeyDesc : (const char *) aValueDesc : (unsigned) capacity
        !            95: /* used for efficient implementation of rehashing: does create a semi ok table */
        !            96: {
        !            97:     count = 0; _nbBuckets = capacity;
        !            98:     keyDesc = (aKeyDesc) ? aKeyDesc : "@"; 
        !            99:     valueDesc = (aValueDesc) ? aValueDesc : "@";
        !           100:     _buckets = nil;
        !           101:     return self;
        !           102: }
        !           103: 
        !           104: + _newBare: (const char *) aKeyDesc : (const char *) aValueDesc : (unsigned) capacity
        !           105: /* used for efficient implementation of rehashing: does create a semi ok table */
        !           106: {
        !           107:     return [[self allocFromZone: NXDefaultMallocZone()] 
        !           108:                _initBare:aKeyDesc:aValueDesc:capacity];
        !           109: }
        !           110: 
        !           111: - initKeyDesc: (const char *) aKeyDesc valueDesc: (const char *) aValueDesc
        !           112: {
        !           113:     return [self initKeyDesc: aKeyDesc valueDesc: aValueDesc capacity: INITCAPA];
        !           114: }
        !           115: 
        !           116: - initKeyDesc: (const char *) aKeyDesc
        !           117: {
        !           118:     return [self initKeyDesc: aKeyDesc valueDesc: NULL];
        !           119: }
        !           120: 
        !           121: - init
        !           122: {
        !           123:     return [self initKeyDesc: NULL];
        !           124: }
        !           125: - initKeyDesc: (const char *) aKeyDesc valueDesc: (const char *) aValueDesc capacity: (unsigned) aCapacity
        !           126: {
        !           127:     [self _initBare: aKeyDesc: aValueDesc: exp2m1 (log2 (aCapacity)+1)];
        !           128:     _buckets = NXZoneCalloc ([self zone], _nbBuckets, sizeof(Bucket));
        !           129:     return self;
        !           130: }
        !           131: 
        !           132: + newKeyDesc: (const char *) aKeyDesc valueDesc: (const char *) aValueDesc capacity: (unsigned) aCapacity
        !           133: {
        !           134:     return [[self allocFromZone: NXDefaultMallocZone()]
        !           135:        initKeyDesc:aKeyDesc valueDesc:aValueDesc capacity:aCapacity];
        !           136: }
        !           137: 
        !           138: + newKeyDesc: (const char *) aKeyDesc valueDesc: (const char *) aValueDesc
        !           139: {
        !           140:     return [self newKeyDesc: aKeyDesc valueDesc: aValueDesc capacity: INITCAPA];
        !           141: }
        !           142: 
        !           143: + newKeyDesc: (const char *) aKeyDesc
        !           144: {
        !           145:     return [self newKeyDesc: aKeyDesc valueDesc: NULL];
        !           146: }
        !           147: 
        !           148: + new
        !           149: {
        !           150:     return [self newKeyDesc: NULL];
        !           151: }
        !           152: 
        !           153: - free {
        !           154:     [self freeKeys: noFree values: noFree];
        !           155:     free(_buckets);
        !           156:     return [super free];
        !           157:     }
        !           158: 
        !           159: - freeObjects {
        !           160:     return [self 
        !           161:        freeKeys: (keyDesc[0] == '@') ? freeObject : noFree 
        !           162:        values: (valueDesc[0] == '@') ? freeObject : noFree 
        !           163:        ];
        !           164:     }
        !           165: 
        !           166: - freeKeys: (void (*) (void *)) keyFunc values: (void (*) (void *)) valueFunc {
        !           167:     unsigned   i = _nbBuckets;
        !           168:     Buckets    buckets = (Buckets) _buckets;
        !           169:     while (i--) {
        !           170:        if (buckets->count) {
        !           171:            unsigned    j = buckets->count;
        !           172:            Pairs       pairs = buckets->pairs;
        !           173:            while (j--) {
        !           174:                (*keyFunc) ((void *) pairs->key);
        !           175:                (*valueFunc) (pairs->value);
        !           176:                pairs++;
        !           177:                };
        !           178:            free(buckets->pairs);
        !           179:            buckets->count = 0;
        !           180:            buckets->pairs = (Pairs) nil;
        !           181:            };
        !           182:        buckets++;
        !           183:        };
        !           184:     count = 0;
        !           185:     return self;
        !           186:     };
        !           187:     
        !           188: - empty
        !           189: {
        !           190:     unsigned   i = _nbBuckets;
        !           191:     Buckets    buckets = (Buckets) _buckets;
        !           192:     while (i--) {
        !           193:        if (buckets->count) free(buckets->pairs);
        !           194:        buckets->count = 0;
        !           195:        buckets->pairs = NULL;
        !           196:        buckets++;
        !           197:        };
        !           198:     count = 0;
        !           199:     return self;
        !           200: }
        !           201: 
        !           202: 
        !           203: - copyFromZone:(NXZone *)zone
        !           204: /* we enumerate the table instead of blind copy to create a hash table of the right size */
        !           205: {
        !           206:     HashTable  *new = [[[self class] allocFromZone: zone] 
        !           207:                                           initKeyDesc: keyDesc
        !           208:                                                                            valueDesc: valueDesc
        !           209:                                                                             capacity: count];
        !           210:     NXHashState        state = [self initState];
        !           211:     const void *key;
        !           212:     void       *value;
        !           213:     while ([self nextState: &state key: &key value: &value])
        !           214:        [new insertKey: key value: value];
        !           215:     return new;
        !           216: }
        !           217: 
        !           218: - (unsigned) count
        !           219: {
        !           220:     return count;
        !           221: }
        !           222: 
        !           223: - (BOOL) isKey: (const void *) aKey
        !           224: {
        !           225:     Buckets    buckets = (Buckets) _buckets;
        !           226:     unsigned   index = hash (keyDesc, aKey, _nbBuckets);
        !           227:     Bucket     bucket = buckets[index];
        !           228:     unsigned   j = bucket.count;
        !           229:     Pairs      pairs;
        !           230:     if (j == 0) return NO;
        !           231:     pairs = bucket.pairs;
        !           232:     while (j--) {
        !           233:        if (isEqual (keyDesc, aKey, pairs->key)) return YES; 
        !           234:        pairs++;
        !           235:        };
        !           236:     return NO;
        !           237: }
        !           238: 
        !           239: - (void *) valueForKey: (const void *) aKey
        !           240: {
        !           241:     Buckets    buckets = (Buckets) _buckets;
        !           242:     unsigned   index = hash (keyDesc, aKey, _nbBuckets);
        !           243:     Bucket     bucket = buckets[index];
        !           244:     unsigned   j = bucket.count;
        !           245:     Pairs      pairs;
        !           246:     if (j == 0) return nil;
        !           247:     pairs = bucket.pairs;
        !           248:     while (j--) {
        !           249:        if (isEqual (keyDesc, aKey, pairs->key)) return pairs->value; 
        !           250:        pairs++;
        !           251:        };
        !           252:     return nil;
        !           253: }
        !           254: 
        !           255: - (void *) _insertKeyNoRehash: (const void *) aKey value: (void *) aValue
        !           256: {
        !           257:     Buckets    buckets = (Buckets) _buckets;
        !           258:     unsigned   index = hash (keyDesc, aKey, _nbBuckets);
        !           259:     Bucket     bucket = buckets[index];
        !           260:     unsigned   j = bucket.count;
        !           261:     Pairs      pairs = bucket.pairs;
        !           262:     Pairs      new;
        !           263:     while (j--) {
        !           264:        if (isEqual (keyDesc, aKey, pairs->key)) {
        !           265:                void    *old = pairs->value;
        !           266:                pairs->key = aKey;
        !           267:                pairs->value = aValue;
        !           268:                return old;
        !           269:                };
        !           270:        pairs++;
        !           271:        };
        !           272:     /* we enlarge this bucket; this could be optimized by using realloc */
        !           273:     new = (Pairs) NXZoneMalloc ([self zone], PAIRSSIZE(bucket.count+1));
        !           274:     if (bucket.count) bcopy (bucket.pairs, new+1, PAIRSSIZE(bucket.count));
        !           275:     new->key = aKey; new->value = aValue;
        !           276:     if (bucket.count) free (bucket.pairs);
        !           277:     buckets[index].count++; buckets[index].pairs = new; count++; 
        !           278:     return nil;
        !           279: }
        !           280: 
        !           281: - (void *) insertKey: (const void *) aKey value: (void *) aValue
        !           282: {
        !           283:     void       *result = [self _insertKeyNoRehash: aKey value: aValue];
        !           284:     if (result) return result; /* it was a replace */
        !           285:     if (count > _nbBuckets) {
        !           286:        /* Rehash: we create a pseudo table pointing really to the old guys,
        !           287:        extend self, copy the old pairs, and free the pseudo table */
        !           288:        HashTable       * old = [[HashTable allocFromZone: [self zone]]
        !           289:                             _initBare: keyDesc: valueDesc: _nbBuckets];
        !           290:         NXHashState    state;
        !           291:         const void     *key;
        !           292:        void            *value;
        !           293:        
        !           294:        old->count = count; old->_buckets = _buckets;
        !           295:        _nbBuckets += _nbBuckets + 1;
        !           296:        count = 0;
        !           297:        _buckets = NXZoneCalloc ([self zone], _nbBuckets, sizeof(Bucket));
        !           298:        state = [old initState];
        !           299:        while ([old nextState: &state key: &key value: &value])
        !           300:            [self insertKey: key value: value];
        !           301: #ifndef        KERNEL
        !           302:        if (old->count != count)
        !           303:            _NXLogError("*** HashTable: 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");
        !           304: #endif /* KERNEL */
        !           305:        [old free];
        !           306:        };
        !           307:     return nil;
        !           308: }
        !           309: 
        !           310: - (void *) removeKey: (const void *) aKey
        !           311: {
        !           312:     Buckets    buckets = (Buckets) _buckets;
        !           313:     unsigned   index = hash (keyDesc, aKey, _nbBuckets);
        !           314:     Bucket     bucket = buckets[index];
        !           315:     unsigned   j = bucket.count;
        !           316:     Pairs      pairs = bucket.pairs;
        !           317:     Pairs      new;
        !           318:     while (j--) {
        !           319:        if (isEqual (keyDesc, aKey, pairs->key)) {
        !           320:                /* we shrink this bucket; this could be optimized by using realloc */
        !           321:                void    *oldValue = pairs->value;
        !           322:                new = (bucket.count-1) ? (Pairs) NXZoneMalloc (
        !           323:                    [self zone], PAIRSSIZE(bucket.count-1)) : 0;
        !           324:                if (bucket.count-1 != j)
        !           325:                        bcopy (bucket.pairs, new, PAIRSSIZE(bucket.count-j-1));
        !           326:                if (j)
        !           327:                        bcopy (bucket.pairs+bucket.count-j, new+bucket.count-j-1,PAIRSSIZE (j));
        !           328:                free (bucket.pairs); 
        !           329:                count--; buckets[index].count--; buckets[index].pairs = new;
        !           330:                return oldValue;
        !           331:                };
        !           332:        pairs++;
        !           333:        };
        !           334:     return nil;
        !           335: }
        !           336: 
        !           337: - (NXHashState) initState {
        !           338:     NXHashState        state;
        !           339:     state.i = _nbBuckets;
        !           340:     state.j = 0;
        !           341:     return state;
        !           342:     };
        !           343:     
        !           344: - (BOOL) nextState: (NXHashState *) aState key: (const void **) aKey value: (void **) aValue
        !           345: {
        !           346:     Buckets    buckets = (Buckets) _buckets;
        !           347:     Pair       pair;
        !           348:     while (aState->j == 0) {
        !           349:        if (aState->i == 0)
        !           350:          {
        !           351:            *aKey = NULL; *aValue = NULL;
        !           352:            return NO;
        !           353:          }
        !           354:        aState->i--; aState->j = buckets[aState->i].count;
        !           355:        }
        !           356:     aState->j--;
        !           357:     pair = buckets[aState->i].pairs[aState->j];
        !           358:     *aKey = pair.key; *aValue = pair.value;
        !           359:     return YES;
        !           360: }
        !           361: 
        !           362: #ifndef        KERNEL
        !           363: - write:(NXTypedStream *) stream
        !           364: {
        !           365:     NXHashState                state = [self initState];
        !           366:     const void *key;
        !           367:     void       *value;
        !           368:     [super write: stream];
        !           369:     NXWriteTypes (stream, "i%%", &count, &keyDesc, &valueDesc);
        !           370:     while ([self nextState: &state key: &key value: &value]) {
        !           371:        NXWriteType (stream, keyDesc, &key);
        !           372:        NXWriteType (stream, valueDesc, &value);
        !           373:        };
        !           374:     return self;
        !           375:     }
        !           376: 
        !           377: - read:(NXTypedStream *) stream
        !           378: {
        !           379:     unsigned   nb; /* we set count as 0 but read nb elements */
        !           380:     if (NXTypedStreamClassVersion (stream, "HashTable") == 0) {
        !           381:         NXReadTypes (stream, "i**", &nb, &keyDesc, &valueDesc);
        !           382:     } else {
        !           383:        [super read: stream];
        !           384:         NXReadTypes (stream, "i%%", &nb, &keyDesc, &valueDesc);
        !           385:     }
        !           386:     if (! keyDesc) exit (1);
        !           387:     if (! valueDesc) exit (2);
        !           388:     count = 0;
        !           389:     _nbBuckets = exp2m1 (log2 (nb)+1);
        !           390:     _buckets = NXZoneCalloc ([self zone], _nbBuckets, sizeof(Bucket));
        !           391:     while (nb--) {
        !           392:        const void      *key;
        !           393:        void    *value;
        !           394:        NXReadType (stream, keyDesc, &key);
        !           395:        NXReadType (stream, valueDesc, &value);
        !           396:        [self _insertKeyNoRehash: key value: value];
        !           397:         };
        !           398:     return self;
        !           399:     }
        !           400: #else  /* KERNEL */
        !           401: - write:(NXTypedStream *) stream
        !           402: {
        !           403:     return nil;
        !           404: }
        !           405: - read:(NXTypedStream *) stream
        !           406: {
        !           407:     return nil;
        !           408: }
        !           409: #endif /* KERNEL */
        !           410: 
        !           411: static void DebugPrint (NXStream *stream, const char *desc, const void *data) {
        !           412:     switch (desc[0]) {
        !           413:        case '@': 
        !           414:            NXPrintf (stream, "%s[0x%x]", [(id) data name], (int) data);
        !           415:            return;
        !           416:        case 'i':
        !           417:            NXPrintf (stream, "%d[0x%x]", (int) data, (int) data);
        !           418:            return;
        !           419:        case '%':
        !           420:        case '*': 
        !           421:            NXPrintf (stream, "\"%s\"", (char *) data);
        !           422:            return;
        !           423:        default: 
        !           424:            NXPrintf (stream, "0x%x", (int) data);
        !           425:            return;
        !           426:        };
        !           427:     };  
        !           428: 
        !           429: - (void) printForDebugger:(NXStream *)stream
        !           430: {
        !           431:     unsigned   i = _nbBuckets;
        !           432:     Buckets    buckets = (Buckets) _buckets;
        !           433: 
        !           434:     NXPrintf (stream, "Table [%s -> %s]: \tcount: %d\tcapacity: %d\n", 
        !           435:        keyDesc, valueDesc, count, _nbBuckets);
        !           436:     while (i--) {
        !           437:        if (buckets->count) {
        !           438:            unsigned    j = buckets->count;
        !           439:            Pairs       pairs = buckets->pairs;
        !           440: 
        !           441:            NXPrintf (stream, "%d\t", j);
        !           442:            while (j--) {
        !           443:                DebugPrint (stream, keyDesc, pairs->key);
        !           444:                NXPrintf (stream, ": ");
        !           445:                DebugPrint (stream, valueDesc, pairs->value);
        !           446:                NXPrintf (stream, "\t");
        !           447:                pairs++;
        !           448:                };
        !           449:            NXPrintf (stream, "\n");
        !           450:            };
        !           451:        buckets++;
        !           452:        };
        !           453:     NXPrintf (stream, "\n");
        !           454:     NXFlush (stream);
        !           455: }
        !           456: 
        !           457: /* Obsolete (for binary compatibility only). */
        !           458: 
        !           459: - _debugPrint: (NXStream *) stream
        !           460: {
        !           461:   [self printForDebugger: stream];
        !           462:   return self;
        !           463: }
        !           464: 
        !           465: @end

unix.superglobalmegacorp.com

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