Annotation of objc/hashtable.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: /*
                     25:        hashtable.m
                     26:        Copyright 1989 NeXT, Inc.
                     27:        Created by Bertrand Serlet, Feb 89
                     28:  */
                     29: 
                     30: #ifdef SHLIB
                     31: #import "shlib.h"
                     32: #endif SHLIB
                     33: 
                     34: #import "hashtable.h"
                     35: #import "objc-private.h"
                     36: 
                     37: #ifdef KERNEL
                     38: 
                     39: #else /* KERNEL */
                     40: 
                     41: #import <mach/mach.h>
                     42: #import <mach/cthreads.h>
                     43: 
                     44: #endif /* KERNEL */
                     45: 
                     46: /* In order to improve efficiency, buckets contain a pointer to an array or directly the data when the array size is 1 */
                     47: typedef union {
                     48:     const void *one;
                     49:     const void **many;
                     50:     } oneOrMany;
                     51:     /* an optimization consists of storing directly data when count = 1 */
                     52:     
                     53: typedef struct {
                     54:     unsigned   count; 
                     55:     oneOrMany  elements;
                     56:     } HashBucket;
                     57:     /* private data structure; may change */
                     58:     
                     59: /*************************************************************************
                     60:  *
                     61:  *     Macros and utilities
                     62:  *     
                     63:  *************************************************************************/
                     64: 
                     65: static unsigned log2 (unsigned x) { return (x<2) ? 0 : log2 (x>>1)+1; };
                     66: 
                     67: static unsigned exp2m1 (unsigned x) { return (1 << x) - 1; };
                     68: 
                     69: #define        PTRSIZE         sizeof(void *)
                     70: 
                     71: #define        ALLOCTABLE(z)   ((NXHashTable *) NXZoneMalloc (z,sizeof (NXHashTable)))
                     72: #define        ALLOCBUCKETS(z,nb)((HashBucket *) NXZoneCalloc (z, nb, sizeof (HashBucket)))
                     73: #define        ALLOCPAIRS(z,nb) ((const void **) NXZoneCalloc (z, nb, sizeof (void *)))
                     74: 
                     75: /* iff necessary this modulo can be optimized since the nbBuckets is of the form 2**n-1 */
                     76: #define        BUCKETOF(table, data) (((HashBucket *)table->buckets)+((*table->prototype->hash)(table->info, data) % table->nbBuckets))
                     77: 
                     78: #define ISEQUAL(table, data1, data2) ((data1 == data2) || (*table->prototype->isEqual)(table->info, data1, data2))
                     79:        /* beware of double evaluation */
                     80:        
                     81: /*************************************************************************
                     82:  *
                     83:  *     Global data and bootstrap
                     84:  *     
                     85:  *************************************************************************/
                     86:  
                     87: static unsigned hashPrototype (const void *info, const void *data) {
                     88:     NXHashTablePrototype       *proto = (NXHashTablePrototype *) data;
                     89:     
                     90:     return NXPtrHash(info, proto->hash) ^ NXPtrHash(info, proto->isEqual) ^ NXPtrHash(info, proto->free) ^ (unsigned) proto->style;
                     91:     };
                     92: 
                     93: static int isEqualPrototype (const void *info, const void *data1, const void *data2) {
                     94:     NXHashTablePrototype       *proto1 = (NXHashTablePrototype *) data1;
                     95:     NXHashTablePrototype       *proto2 = (NXHashTablePrototype *) data2;
                     96:     
                     97:     return (proto1->hash == proto2->hash) && (proto1->isEqual == proto2->isEqual) && (proto1->free == proto2->free) && (proto1->style == proto2->style);
                     98:     };
                     99:     
                    100: static NXHashTablePrototype protoPrototype = {
                    101:     hashPrototype, isEqualPrototype, NXNoEffectFree, 0
                    102:     };
                    103: 
                    104: static NXHashTable *prototypes = NULL;
                    105:        /* table of all prototypes */
                    106: 
                    107: static void bootstrap (void) {
                    108:     free(malloc(8));
                    109:     prototypes = ALLOCTABLE (NXDefaultMallocZone());
                    110:     prototypes->prototype = &protoPrototype; 
                    111:     prototypes->count = 1;
                    112:     prototypes->nbBuckets = 1; /* has to be 1 so that the right bucket is 0 */
                    113:     prototypes->buckets = ALLOCBUCKETS(NXDefaultMallocZone(),  1);
                    114:     prototypes->info = NULL;
                    115:     ((HashBucket *) prototypes->buckets)[0].count = 1;
                    116:     ((HashBucket *) prototypes->buckets)[0].elements.one = &protoPrototype;
                    117:     };
                    118: 
                    119: /*************************************************************************
                    120:  *
                    121:  *     On z'y va
                    122:  *     
                    123:  *************************************************************************/
                    124: 
                    125: NXHashTable *NXCreateHashTable (NXHashTablePrototype prototype, unsigned capacity, const void *info) {
                    126:     return NXCreateHashTableFromZone(prototype, capacity, info, NXDefaultMallocZone());
                    127: }
                    128: 
                    129: NXHashTable *NXCreateHashTableFromZone (NXHashTablePrototype prototype, unsigned capacity, const void *info, NXZone *zone) {
                    130:     NXHashTable                        *table;
                    131:     NXHashTablePrototype       *proto;
                    132:     
                    133:     table = ALLOCTABLE(zone);
                    134:     if (! prototypes) bootstrap ();
                    135:     if (! prototype.hash) prototype.hash = NXPtrHash;
                    136:     if (! prototype.isEqual) prototype.isEqual = NXPtrIsEqual;
                    137:     if (! prototype.free) prototype.free = NXNoEffectFree;
                    138:     if (prototype.style) {
                    139:        _NXLogError ("*** NXCreateHashTable: invalid style\n");
                    140:        return NULL;
                    141:        };
                    142:     proto = NXHashGet (prototypes, &prototype); 
                    143:     if (! proto) {
                    144:        proto
                    145:        = (NXHashTablePrototype *) NXZoneMalloc (NXDefaultMallocZone(),
                    146:                                                 sizeof (NXHashTablePrototype));
                    147:        bcopy (&prototype, proto, sizeof (NXHashTablePrototype));
                    148:        (void) NXHashInsert (prototypes, proto);
                    149:        proto = NXHashGet (prototypes, &prototype);
                    150:        if (! proto) {
                    151:            _NXLogError ("*** NXCreateHashTable: bug\n");
                    152:            return NULL;
                    153:            };
                    154:        };
                    155:     table->prototype = proto; table->count = 0; table->info = info;
                    156:     table->nbBuckets = exp2m1 (log2 (capacity)+1);
                    157:     table->buckets = ALLOCBUCKETS(zone, table->nbBuckets);
                    158:     return table;
                    159:     }
                    160: 
                    161: static void freeBucketPairs (void (*freeProc)(const void *info, void *data), HashBucket bucket, const void *info) {
                    162:     unsigned   j = bucket.count;
                    163:     const void **pairs;
                    164:     
                    165:     if (j == 1) {
                    166:        (*freeProc) (info, (void *) bucket.elements.one);
                    167:        return;
                    168:        };
                    169:     pairs = bucket.elements.many;
                    170:     while (j--) {
                    171:        (*freeProc) (info, (void *) *pairs);
                    172:        pairs ++;
                    173:        };
                    174:     free (bucket.elements.many);
                    175:     };
                    176:     
                    177: static void freeBuckets (NXHashTable *table, int freeObjects) {
                    178:     unsigned           i = table->nbBuckets;
                    179:     HashBucket         *buckets = (HashBucket *) table->buckets;
                    180:     
                    181:     while (i--) {
                    182:        if (buckets->count) {
                    183:            freeBucketPairs ((freeObjects) ? table->prototype->free : NXNoEffectFree, *buckets, table->info);
                    184:            buckets->count = 0;
                    185:            buckets->elements.one = NULL;
                    186:            };
                    187:        buckets++;
                    188:        };
                    189:     };
                    190:     
                    191: void NXFreeHashTable (NXHashTable *table) {
                    192:     freeBuckets (table, YES);
                    193:     free (table->buckets);
                    194:     free (table);
                    195:     };
                    196:     
                    197: void NXEmptyHashTable (NXHashTable *table) {
                    198:     freeBuckets (table, NO);
                    199:     table->count = 0;
                    200:     }
                    201: 
                    202: void NXResetHashTable (NXHashTable *table) {
                    203:     freeBuckets (table, YES);
                    204:     table->count = 0;
                    205: }
                    206: 
                    207: BOOL NXIsEqualHashTable (NXHashTable *table1, NXHashTable *table2) {
                    208:     if (table1 == table2) return YES;
                    209:     if (NXCountHashTable (table1) != NXCountHashTable (table2)) return NO;
                    210:     else {
                    211:        void            *data;
                    212:        NXHashState     state = NXInitHashState (table1);
                    213:        while (NXNextHashState (table1, &state, &data)) {
                    214:            if (! NXHashMember (table2, data)) return NO;
                    215:        }
                    216:        return YES;
                    217:     }
                    218: }
                    219: 
                    220: BOOL NXCompareHashTables (NXHashTable *table1, NXHashTable *table2) {
                    221:     if (table1 == table2) return YES;
                    222:     if (NXCountHashTable (table1) != NXCountHashTable (table2)) return NO;
                    223:     else {
                    224:        void            *data;
                    225:        NXHashState     state = NXInitHashState (table1);
                    226:        while (NXNextHashState (table1, &state, &data)) {
                    227:            if (! NXHashMember (table2, data)) return NO;
                    228:        }
                    229:        return YES;
                    230:     }
                    231: }
                    232: 
                    233: NXHashTable *NXCopyHashTable (NXHashTable *table) {
                    234:     NXHashTable                *new;
                    235:     NXHashState                state = NXInitHashState (table);
                    236:     void               *data;
                    237:     NXZone             *zone = NXZoneFromPtr(table);
                    238:     
                    239:     new = ALLOCTABLE(zone);
                    240:     new->prototype = table->prototype; new->count = 0;
                    241:     new->info = table->info;
                    242:     new->nbBuckets = table->nbBuckets;
                    243:     new->buckets = ALLOCBUCKETS(zone, new->nbBuckets);
                    244:     while (NXNextHashState (table, &state, &data))
                    245:        (void) NXHashInsert (new, data);
                    246:     return new;
                    247:     }
                    248: 
                    249: unsigned NXCountHashTable (NXHashTable *table) {
                    250:     return table->count;
                    251:     }
                    252: 
                    253: int NXHashMember (NXHashTable *table, const void *data) {
                    254:     HashBucket *bucket = BUCKETOF(table, data);
                    255:     unsigned   j = bucket->count;
                    256:     const void **pairs;
                    257:     
                    258:     if (! j) return 0;
                    259:     if (j == 1) {
                    260:        return ISEQUAL(table, data, bucket->elements.one);
                    261:        };
                    262:     pairs = bucket->elements.many;
                    263:     while (j--) {
                    264:        /* we don't cache isEqual because lists are short */
                    265:        if (ISEQUAL(table, data, *pairs)) return 1; 
                    266:        pairs ++;
                    267:        };
                    268:     return 0;
                    269:     }
                    270: 
                    271: void *NXHashGet (NXHashTable *table, const void *data) {
                    272:     HashBucket *bucket = BUCKETOF(table, data);
                    273:     unsigned   j = bucket->count;
                    274:     const void **pairs;
                    275:     
                    276:     if (! j) return NULL;
                    277:     if (j == 1) {
                    278:        return ISEQUAL(table, data, bucket->elements.one)
                    279:            ? (void *) bucket->elements.one : NULL; 
                    280:        };
                    281:     pairs = bucket->elements.many;
                    282:     while (j--) {
                    283:        /* we don't cache isEqual because lists are short */
                    284:        if (ISEQUAL(table, data, *pairs)) return (void *) *pairs; 
                    285:        pairs ++;
                    286:        };
                    287:     return NULL;
                    288:     }
                    289: 
                    290: static void _NXHashRehash (NXHashTable *table) {
                    291:     /* Rehash: we create a pseudo table pointing really to the old guys,
                    292:     extend self, copy the old pairs, and free the pseudo table */
                    293:     NXHashTable        *old;
                    294:     NXHashState        state;
                    295:     void       *aux;
                    296:     NXZone     *zone = NXZoneFromPtr(table);
                    297:     
                    298:     old = ALLOCTABLE(zone);
                    299:     old->prototype = table->prototype; old->count = table->count; 
                    300:     old->nbBuckets = table->nbBuckets; old->buckets = table->buckets;
                    301:     table->nbBuckets += table->nbBuckets + 1; /* 2 times + 1 */
                    302:     table->count = 0; table->buckets = ALLOCBUCKETS(zone, table->nbBuckets);
                    303:     state = NXInitHashState (old);
                    304:     while (NXNextHashState (old, &state, &aux))
                    305:        (void) NXHashInsert (table, aux);
                    306:     freeBuckets (old, NO);
                    307:     if (old->count != table->count)
                    308:        _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");
                    309:     free (old->buckets); 
                    310:     free (old);
                    311:     };
                    312: 
                    313: void *NXHashInsert (NXHashTable *table, const void *data) {
                    314:     HashBucket *bucket = BUCKETOF(table, data);
                    315:     unsigned   j = bucket->count;
                    316:     const void **pairs;
                    317:     const void **new;
                    318:     NXZone     *zone = NXZoneFromPtr(table);
                    319:     
                    320:     if (! j) {
                    321:        bucket->count++; bucket->elements.one = data; 
                    322:        table->count++; 
                    323:        return NULL;
                    324:        };
                    325:     if (j == 1) {
                    326:        if (ISEQUAL(table, data, bucket->elements.one)) {
                    327:            const void  *old = bucket->elements.one;
                    328:            bucket->elements.one = data;
                    329:            return (void *) old;
                    330:            };
                    331:        new = ALLOCPAIRS(zone, 2);
                    332:        new[1] = bucket->elements.one;
                    333:        *new = data;
                    334:        bucket->count++; bucket->elements.many = new; 
                    335:        table->count++; 
                    336:        if (table->count > table->nbBuckets) _NXHashRehash (table);
                    337:        return NULL;
                    338:        };
                    339:     pairs = bucket->elements.many;
                    340:     while (j--) {
                    341:        /* we don't cache isEqual because lists are short */
                    342:        if (ISEQUAL(table, data, *pairs)) {
                    343:            const void  *old = *pairs;
                    344:            *pairs = data;
                    345:            return (void *) old;
                    346:            };
                    347:        pairs ++;
                    348:        };
                    349:     /* we enlarge this bucket; and put new data in front */
                    350:     new = ALLOCPAIRS(zone, bucket->count+1);
                    351:     if (bucket->count) bcopy (bucket->elements.many, new+1, bucket->count * PTRSIZE);
                    352:     *new = data;
                    353:     free (bucket->elements.many);
                    354:     bucket->count++; bucket->elements.many = new; 
                    355:     table->count++; 
                    356:     if (table->count > table->nbBuckets) _NXHashRehash (table);
                    357:     return NULL;
                    358:     }
                    359: 
                    360: void *NXHashInsertIfAbsent (NXHashTable *table, const void *data) {
                    361:     HashBucket *bucket = BUCKETOF(table, data);
                    362:     unsigned   j = bucket->count;
                    363:     const void **pairs;
                    364:     const void **new;
                    365:     NXZone     *zone = NXZoneFromPtr(table);
                    366:     
                    367:     if (! j) {
                    368:        bucket->count++; bucket->elements.one = data; 
                    369:        table->count++; 
                    370:        return (void *) data;
                    371:        };
                    372:     if (j == 1) {
                    373:        if (ISEQUAL(table, data, bucket->elements.one))
                    374:            return (void *) bucket->elements.one;
                    375:        new = ALLOCPAIRS(zone, 2);
                    376:        new[1] = bucket->elements.one;
                    377:        *new = data;
                    378:        bucket->count++; bucket->elements.many = new; 
                    379:        table->count++; 
                    380:        if (table->count > table->nbBuckets) _NXHashRehash (table);
                    381:        return (void *) data;
                    382:        };
                    383:     pairs = bucket->elements.many;
                    384:     while (j--) {
                    385:        /* we don't cache isEqual because lists are short */
                    386:        if (ISEQUAL(table, data, *pairs))
                    387:            return (void *) *pairs;
                    388:        pairs ++;
                    389:        };
                    390:     /* we enlarge this bucket; and put new data in front */
                    391:     new = ALLOCPAIRS(zone, bucket->count+1);
                    392:     if (bucket->count) bcopy (bucket->elements.many, new+1, bucket->count * PTRSIZE);
                    393:     *new = data;
                    394:     free (bucket->elements.many);
                    395:     bucket->count++; bucket->elements.many = new; 
                    396:     table->count++; 
                    397:     if (table->count > table->nbBuckets) _NXHashRehash (table);
                    398:     return (void *) data;
                    399:     }
                    400: 
                    401: void *NXHashRemove (NXHashTable *table, const void *data) {
                    402:     HashBucket *bucket = BUCKETOF(table, data);
                    403:     unsigned   j = bucket->count;
                    404:     const void **pairs;
                    405:     const void **new;
                    406:     NXZone     *zone = NXZoneFromPtr(table);
                    407:     
                    408:     if (! j) return NULL;
                    409:     if (j == 1) {
                    410:        if (! ISEQUAL(table, data, bucket->elements.one)) return NULL;
                    411:        data = bucket->elements.one;
                    412:        table->count--; bucket->count--; bucket->elements.one = NULL;
                    413:        return (void *) data;
                    414:        };
                    415:     pairs = bucket->elements.many;
                    416:     if (j == 2) {
                    417:        if (ISEQUAL(table, data, pairs[0])) {
                    418:            bucket->elements.one = pairs[1]; data = pairs[0];
                    419:            }
                    420:        else if (ISEQUAL(table, data, pairs[1])) {
                    421:            bucket->elements.one = pairs[0]; data = pairs[1];
                    422:            }
                    423:        else return NULL;
                    424:        free (pairs);
                    425:        table->count--; bucket->count--;
                    426:        return (void *) data;
                    427:        };
                    428:     while (j--) {
                    429:        if (ISEQUAL(table, data, *pairs)) {
                    430:            data = *pairs;
                    431:            /* we shrink this bucket */
                    432:            new = (bucket->count-1) 
                    433:                ? ALLOCPAIRS(zone, bucket->count-1) : NULL;
                    434:            if (bucket->count-1 != j)
                    435:                    bcopy (bucket->elements.many, new, PTRSIZE*(bucket->count-j-1));
                    436:            if (j)
                    437:                    bcopy (bucket->elements.many + bucket->count-j, new+bucket->count-j-1, PTRSIZE*j);
                    438:            free (bucket->elements.many);
                    439:            table->count--; bucket->count--; bucket->elements.many = new;
                    440:            return (void *) data;
                    441:            };
                    442:        pairs ++;
                    443:        };
                    444:     return NULL;
                    445:     }
                    446: 
                    447: NXHashState NXInitHashState (NXHashTable *table) {
                    448:     NXHashState        state;
                    449:     
                    450:     state.i = table->nbBuckets;
                    451:     state.j = 0;
                    452:     return state;
                    453:     };
                    454:     
                    455: int NXNextHashState (NXHashTable *table, NXHashState *state, void **data) {
                    456:     HashBucket         *buckets = (HashBucket *) table->buckets;
                    457:     
                    458:     while (state->j == 0) {
                    459:        if (state->i == 0) return NO;
                    460:        state->i--; state->j = buckets[state->i].count;
                    461:        }
                    462:     state->j--;
                    463:     buckets += state->i;
                    464:     *data = (void *) ((buckets->count == 1) 
                    465:                ? buckets->elements.one : buckets->elements.many[state->j]);
                    466:     return YES;
                    467:     };
                    468: 
                    469: /*************************************************************************
                    470:  *
                    471:  *     Conveniences
                    472:  *     
                    473:  *************************************************************************/
                    474: 
                    475: unsigned NXPtrHash (const void *info, const void *data) {
                    476:     return (((unsigned) data) >> 16) ^ ((unsigned) data);
                    477:     };
                    478:     
                    479: unsigned NXStrHash (const void *info, const void *data) {
                    480:     register unsigned          hash = 0;
                    481:     register unsigned char     *s = (unsigned char *) data;
                    482:     /* unsigned to avoid a sign-extend */
                    483:     /* unroll the loop */
                    484:     if (s) for (; ; ) { 
                    485:        if (*s == '\0') break;
                    486:        hash ^= *s++;
                    487:        if (*s == '\0') break;
                    488:        hash ^= *s++ << 8;
                    489:        if (*s == '\0') break;
                    490:        hash ^= *s++ << 16;
                    491:        if (*s == '\0') break;
                    492:        hash ^= *s++ << 24;
                    493:        }
                    494:     return hash;
                    495:     };
                    496:     
                    497: int NXPtrIsEqual (const void *info, const void *data1, const void *data2) {
                    498:     return data1 == data2;
                    499:     };
                    500: 
                    501: int NXStrIsEqual (const void *info, const void *data1, const void *data2) {
                    502:     if (data1 == data2) return YES;
                    503:     if (! data1) return ! strlen ((char *) data2);
                    504:     if (! data2) return ! strlen ((char *) data1);
                    505:     if (((char *) data1)[0] != ((char *) data2)[0]) return NO;
                    506:     return (strcmp ((char *) data1, (char *) data2)) ? NO : YES;
                    507:     };
                    508:     
                    509: void NXNoEffectFree (const void *info, void *data) {};
                    510: 
                    511: void NXReallyFree (const void *info, void *data) {
                    512:     free (data);
                    513:     };
                    514: 
                    515: /* All the following functions are really private, made non-static only for the benefit of shlibs */
                    516: unsigned hashPtrStructKey (const void *info, const void *data) {
                    517:     return NXPtrHash(info, *((void **) data));
                    518:     };
                    519: int isEqualPtrStructKey (const void *info, const void *data1, const void *data2) {
                    520:     return NXPtrIsEqual (info, *((void **) data1), *((void **) data2));
                    521:     };
                    522: unsigned hashStrStructKey (const void *info, const void *data) {
                    523:     return NXStrHash(info, *((char **) data));
                    524:     };
                    525: int isEqualStrStructKey (const void *info, const void *data1, const void *data2) {
                    526:     return NXStrIsEqual (info, *((char **) data1), *((char **) data2));
                    527:     };
                    528: 
                    529: 
                    530: /*************************************************************************
                    531:  *
                    532:  *     Unique strings
                    533:  *     
                    534:  *************************************************************************/
                    535: 
                    536: /* the implementation could be made faster at the expense of memory if the size of the strings were kept around */
                    537: static NXHashTable *uniqueStrings = NULL;
                    538: 
                    539: /* this is based on most apps using a few K of strings, and an average string size of 15 using sqrt(2*dataAlloced*perChunkOverhead) */
                    540: #define CHUNK_SIZE     360
                    541: 
                    542: static int accessUniqueString = 0;
                    543: 
                    544: static char            *zone = NULL;
                    545: static vm_size_t       zoneSize = 0;
                    546: static mutex_t         lock = NULL;
                    547: 
                    548: static const char *CopyIntoReadOnly (const char *str) {
                    549:     unsigned int       len = strlen (str) + 1;
                    550:     char       *new;
                    551:     
                    552:     if (len > CHUNK_SIZE/2) {  /* dont let big strings waste space */
                    553: #ifdef KERNEL
                    554:        new = kalloc (len);
                    555: #else /* KERNEL */
                    556:        new = malloc (len);
                    557: #endif /* KERNEL */
                    558:        bcopy (str, new, len);
                    559:        return new;
                    560:     }
                    561: 
                    562:     if (! lock) {
                    563:        lock = mutex_alloc ();
                    564:        mutex_init (lock);
                    565:        };
                    566: 
                    567:     mutex_lock (lock);
                    568:     if (zoneSize < len) {
                    569:        zoneSize = CHUNK_SIZE *((len + CHUNK_SIZE - 1) / CHUNK_SIZE);
                    570:        /* not enough room, we try to allocate.  If no room left, too bad */
                    571: #ifdef KERNEL
                    572:        zone = kalloc (zoneSize);
                    573: #else /* KERNEL */
                    574:        zone = malloc (zoneSize);
                    575: #endif /* KERNEL */
                    576:        };
                    577:     
                    578:     new = zone;
                    579:     bcopy (str, new, len);
                    580:     zone += len;
                    581:     zoneSize -= len;
                    582:     mutex_unlock (lock);
                    583:     return new;
                    584:     };
                    585:     
                    586: NXAtom NXUniqueString (const char *buffer) {
                    587:     const char *previous;
                    588:     
                    589:     if (! buffer) return buffer;
                    590:     accessUniqueString++;
                    591:     if (! uniqueStrings)
                    592:        uniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);
                    593:     previous = (const char *) NXHashGet (uniqueStrings, buffer);
                    594:     if (previous) return previous;
                    595:     previous = CopyIntoReadOnly (buffer);
                    596:     if (NXHashInsert (uniqueStrings, previous)) {
                    597:        _NXLogError ("*** NXUniqueString: invariant broken\n");
                    598:        return NULL;
                    599:        };
                    600:     return previous;
                    601:     };
                    602: 
                    603: NXAtom NXUniqueStringNoCopy (const char *string) {
                    604:     accessUniqueString++;
                    605:     if (! uniqueStrings)
                    606:        uniqueStrings = NXCreateHashTable (NXStrPrototype, 0, NULL);
                    607:     return (const char *) NXHashInsertIfAbsent (uniqueStrings, string);
                    608:     };
                    609: 
                    610: #define BUF_SIZE       256
                    611: 
                    612: NXAtom NXUniqueStringWithLength (const char *buffer, int length) {
                    613:     NXAtom     atom;
                    614:     char       *nullTermStr;
                    615:     char       stackBuf[BUF_SIZE];
                    616: 
                    617:     if (length+1 > BUF_SIZE)
                    618:        nullTermStr = malloc (length+1);
                    619:     else
                    620:        nullTermStr = stackBuf;
                    621:     bcopy (buffer, nullTermStr, length);
                    622:     nullTermStr[length] = '\0';
                    623:     atom = NXUniqueString (nullTermStr);
                    624:     if (length+1 > BUF_SIZE)
                    625:        free (nullTermStr);
                    626:     return atom;
                    627:     };
                    628: 
                    629: char *NXCopyStringBufferFromZone (const char *str, NXZone *zone) {
                    630:     return strcpy ((char *) NXZoneMalloc (zone, strlen (str) + 1), str);
                    631:     };
                    632:     
                    633: char *NXCopyStringBuffer (const char *str) {
                    634:     return NXCopyStringBufferFromZone(str, NXDefaultMallocZone());
                    635:     };
                    636:     
                    637: #if 0  /* Never used! */
                    638: static void uniqueStringsStatistics (void) {
                    639:     unsigned   i = uniqueStrings->nbBuckets;
                    640:     HashBucket *buckets = (HashBucket *) uniqueStrings->buckets;
                    641:     
                    642:     printf ("Size: %d\tcount: %d\taccesses: %d\n", i, uniqueStrings->count, accessUniqueString);
                    643:     while (i--) {
                    644:        if (buckets->count) {
                    645:            if (buckets->count == 1)
                    646:                printf ("1\t%s\n", (char *) buckets->elements.one);
                    647:            else {
                    648:                int     j = buckets->count;
                    649:                char    **pairs = (char **) buckets->elements.many;
                    650:                printf ("%d\t", buckets->count);
                    651:                while (j--) printf ("%s ", *(pairs++));
                    652:                printf ("\n");
                    653:                };
                    654:            };
                    655:        buckets++;
                    656:        };
                    657:     };
                    658: #endif

unix.superglobalmegacorp.com

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