Annotation of XML/hash.c, revision 1.6

1.1       veillard    1: /*
                      2:  * hash.c: chained hash tables
                      3:  *
                      4:  * Reference: Your favorite introductory book on algorithms
                      5:  *
                      6:  * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
                      7:  *
                      8:  * Permission to use, copy, modify, and distribute this software for any
                      9:  * purpose with or without fee is hereby granted, provided that the above
                     10:  * copyright notice and this permission notice appear in all copies.
                     11:  *
                     12:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     13:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     14:  * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
                     15:  * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
                     16:  *
                     17:  * Author: bjorn.reese@systematic.dk
                     18:  */
                     19: 
                     20: #include <libxml/hash.h>
                     21: #include <libxml/xmlmemory.h>
                     22: #include <libxml/parser.h>
                     23: 
                     24: /*
                     25:  * xmlHashComputeKey:
                     26:  * Calculate the hash key
                     27:  */
                     28: static unsigned long
                     29: xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *string) {
                     30:     unsigned long value = 0L;
                     31:     char ch;
                     32:     
                     33:     while ((ch = *string++) != 0) {
                     34:         /* value *= 31; */
                     35:         value += (unsigned long)ch;
                     36:     }
                     37:     return (value % table->size);
                     38: }
                     39: 
                     40: /**
                     41:  * xmlHashCreate:
                     42:  * @size: the size of the hash table
                     43:  *
                     44:  * Create a new xmlHashTablePtr.
                     45:  *
                     46:  * Returns the newly created object, or NULL if an error occured.
                     47:  */
                     48: xmlHashTablePtr
                     49: xmlHashCreate(int size) {
                     50:     xmlHashTablePtr table;
                     51:   
                     52:     if (size <= 0)
                     53:         size = 256;
                     54:   
                     55:     table = xmlMalloc(sizeof(xmlHashTable));
                     56:     if (table) {
                     57:         table->size = size;
                     58:         table->table = xmlMalloc(size * sizeof(xmlHashEntry));
                     59:         if (table->table) {
                     60:            memset(table->table, 0, size * sizeof(xmlHashEntry));
                     61:            return(table);
                     62:         }
                     63:         xmlFree(table);
                     64:     }
                     65:     return(NULL);
                     66: }
                     67: 
                     68: /**
                     69:  * xmlHashFree:
                     70:  * @table: the hash table
                     71:  * @f:  the deallocator function for items in the hash
                     72:  *
                     73:  * Free the hash table and its contents. The userdata is
                     74:  * deallocated with f if provided.
                     75:  */
                     76: void
                     77: xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
                     78:     int i;
                     79:     xmlHashEntryPtr iter;
                     80:     xmlHashEntryPtr next;
                     81: 
                     82:     if (table == NULL)
                     83:        return;
                     84:     if (table->table) {
                     85:        for(i = 0; i < table->size; i++) {
                     86:            iter = table->table[i];
                     87:            while (iter) {
                     88:                next = iter->next;
                     89:                if (iter->name)
                     90:                    xmlFree(iter->name);
1.5       veillard   91:                if (iter->name2)
                     92:                    xmlFree(iter->name2);
                     93:                if (iter->name3)
                     94:                    xmlFree(iter->name3);
1.1       veillard   95:                if (f)
1.6     ! veillard   96:                    f(iter->payload, iter->name);
1.1       veillard   97:                iter->payload = NULL;
                     98:                xmlFree(iter);
                     99:                iter = next;
                    100:            }
                    101:            table->table[i] = NULL;
                    102:        }
                    103:        xmlFree(table->table);
                    104:     }
                    105:     xmlFree(table);
                    106: }
                    107: 
                    108: /**
                    109:  * xmlHashAddEntry:
                    110:  * @table: the hash table
                    111:  * @name: the name of the userdata
                    112:  * @userdata: a pointer to the userdata
                    113:  *
                    114:  * Add the userdata to the hash table. This can later be retrieved
                    115:  * by using the name. Duplicate names generate errors.
                    116:  *
                    117:  * Returns 0 the addition succeeded and -1 in case of error.
                    118:  */
                    119: int
                    120: xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
1.3       veillard  121:     return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
                    122: }
                    123: 
                    124: /**
                    125:  * xmlHashAddEntry2:
                    126:  * @table: the hash table
                    127:  * @name: the name of the userdata
                    128:  * @name2: a second name of the userdata
                    129:  * @userdata: a pointer to the userdata
                    130:  *
                    131:  * Add the userdata to the hash table. This can later be retrieved
                    132:  * by using the (name, name2) tuple. Duplicate tuples generate errors.
                    133:  *
                    134:  * Returns 0 the addition succeeded and -1 in case of error.
                    135:  */
                    136: int
                    137: xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
                    138:                const xmlChar *name2, void *userdata) {
                    139:     return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
                    140: }
                    141: 
                    142: /**
                    143:  * xmlHashUpdateEntry:
                    144:  * @table: the hash table
                    145:  * @name: the name of the userdata
                    146:  * @userdata: a pointer to the userdata
                    147:  * @f: the deallocator function for replaced item (if any)
                    148:  *
                    149:  * Add the userdata to the hash table. This can later be retrieved
                    150:  * by using the name. Existing entry for this name will be removed
                    151:  * and freed with @f if found.
                    152:  *
                    153:  * Returns 0 the addition succeeded and -1 in case of error.
                    154:  */
                    155: int
                    156: xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
                    157:                   void *userdata, xmlHashDeallocator f) {
                    158:     return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
                    159: }
                    160: 
                    161: /**
                    162:  * xmlHashUpdateEntry2:
                    163:  * @table: the hash table
                    164:  * @name: the name of the userdata
                    165:  * @name2: a second name of the userdata
                    166:  * @userdata: a pointer to the userdata
                    167:  * @f: the deallocator function for replaced item (if any)
                    168:  *
                    169:  * Add the userdata to the hash table. This can later be retrieved
                    170:  * by using the (name, name2) tuple. Existing entry for this tuple will
                    171:  * be removed and freed with @f if found.
                    172:  *
                    173:  * Returns 0 the addition succeeded and -1 in case of error.
                    174:  */
                    175: int
                    176: xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
                    177:                   const xmlChar *name2, void *userdata,
                    178:                   xmlHashDeallocator f) {
                    179:     return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
                    180: }
                    181: 
                    182: /**
                    183:  * xmlHashLookup:
                    184:  * @table: the hash table
                    185:  * @name: the name of the userdata
                    186:  *
                    187:  * Find the userdata specified by the name.
                    188:  *
                    189:  * Returns the a pointer to the userdata
                    190:  */
                    191: void *
                    192: xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
                    193:     return(xmlHashLookup3(table, name, NULL, NULL));
                    194: }
                    195: 
                    196: /**
                    197:  * xmlHashLookup2:
                    198:  * @table: the hash table
                    199:  * @name: the name of the userdata
                    200:  * @name2: a second name of the userdata
                    201:  *
                    202:  * Find the userdata specified by the (name, name2) tuple.
                    203:  *
                    204:  * Returns the a pointer to the userdata
                    205:  */
                    206: void *
                    207: xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
                    208:              const xmlChar *name2) {
                    209:     return(xmlHashLookup3(table, name, name2, NULL));
                    210: }
                    211: 
                    212: /**
                    213:  * xmlHashAddEntry3:
                    214:  * @table: the hash table
                    215:  * @name: the name of the userdata
                    216:  * @name2: a second name of the userdata
                    217:  * @name3: a third name of the userdata
                    218:  * @userdata: a pointer to the userdata
                    219:  *
                    220:  * Add the userdata to the hash table. This can later be retrieved
                    221:  * by using the tuple (name, name2, name3). Duplicate entries generate
                    222:  * errors.
                    223:  *
                    224:  * Returns 0 the addition succeeded and -1 in case of error.
                    225:  */
                    226: int
                    227: xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
1.4       veillard  228:                 const xmlChar *name2, const xmlChar *name3,
                    229:                 void *userdata) {
1.1       veillard  230:     unsigned long key;
                    231:     xmlHashEntryPtr entry;
                    232:     xmlHashEntryPtr insert;
                    233: 
                    234:     if ((table == NULL) || name == NULL)
                    235:        return(-1);
                    236: 
                    237:     /*
                    238:      * Check for duplicate and insertion location.
                    239:      */
                    240:     key = xmlHashComputeKey(table, name);
                    241:     if (table->table[key] == NULL) {
                    242:        insert = NULL;
                    243:     } else {
                    244:        for (insert = table->table[key]; insert->next != NULL;
                    245:             insert = insert->next) {
1.3       veillard  246:            if ((xmlStrEqual(insert->name, name)) &&
                    247:                (xmlStrEqual(insert->name2, name2)) &&
                    248:                (xmlStrEqual(insert->name3, name3)))
1.1       veillard  249:                return(-1);
                    250:        }
1.3       veillard  251:        if ((xmlStrEqual(insert->name, name)) &&
                    252:            (xmlStrEqual(insert->name2, name2)) &&
                    253:            (xmlStrEqual(insert->name3, name3)))
1.1       veillard  254:            return(-1);
                    255:     }
                    256: 
                    257:     entry = xmlMalloc(sizeof(xmlHashEntry));
                    258:     if (entry == NULL)
                    259:        return(-1);
                    260:     entry->name = xmlStrdup(name);
1.3       veillard  261:     entry->name2 = xmlStrdup(name2);
                    262:     entry->name3 = xmlStrdup(name3);
1.1       veillard  263:     entry->payload = userdata;
                    264:     entry->next = NULL;
                    265: 
                    266: 
                    267:     if (insert == NULL) {
                    268:        table->table[key] = entry;
                    269:     } else {
                    270:        insert->next = entry;
                    271:     }
                    272:     return(0);
                    273: }
                    274: 
                    275: /**
1.3       veillard  276:  * xmlHashUpdateEntry3:
1.1       veillard  277:  * @table: the hash table
                    278:  * @name: the name of the userdata
1.3       veillard  279:  * @name2: a second name of the userdata
                    280:  * @name3: a third name of the userdata
1.1       veillard  281:  * @userdata: a pointer to the userdata
                    282:  * @f: the deallocator function for replaced item (if any)
                    283:  *
                    284:  * Add the userdata to the hash table. This can later be retrieved
1.3       veillard  285:  * by using the tuple (name, name2, name3). Existing entry for this tuple
                    286:  * will be removed and freed with @f if found.
1.1       veillard  287:  *
                    288:  * Returns 0 the addition succeeded and -1 in case of error.
                    289:  */
                    290: int
1.4       veillard  291: xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
1.3       veillard  292:                   const xmlChar *name2, const xmlChar *name3,
                    293:                   void *userdata, xmlHashDeallocator f) {
1.1       veillard  294:     unsigned long key;
                    295:     xmlHashEntryPtr entry;
                    296:     xmlHashEntryPtr insert;
                    297: 
                    298:     if ((table == NULL) || name == NULL)
                    299:        return(-1);
                    300: 
                    301:     /*
                    302:      * Check for duplicate and insertion location.
                    303:      */
                    304:     key = xmlHashComputeKey(table, name);
                    305:     if (table->table[key] == NULL) {
                    306:        insert = NULL;
                    307:     } else {
                    308:        for (insert = table->table[key]; insert->next != NULL;
                    309:             insert = insert->next) {
1.3       veillard  310:            if ((xmlStrEqual(insert->name, name)) &&
                    311:                (xmlStrEqual(insert->name2, name2)) &&
                    312:                (xmlStrEqual(insert->name3, name3))) {
1.1       veillard  313:                if (f)
1.6     ! veillard  314:                    f(insert->payload, insert->name);
1.1       veillard  315:                insert->payload = userdata;
                    316:                return(0);
                    317:            }
                    318:        }
1.3       veillard  319:        if ((xmlStrEqual(insert->name, name)) &&
                    320:            (xmlStrEqual(insert->name2, name2)) &&
                    321:            (xmlStrEqual(insert->name3, name3))) {
1.1       veillard  322:            if (f)
1.6     ! veillard  323:                f(insert->payload, insert->name);
1.1       veillard  324:            insert->payload = userdata;
                    325:            return(0);
                    326:        }
                    327:     }
                    328: 
                    329:     entry = xmlMalloc(sizeof(xmlHashEntry));
                    330:     if (entry == NULL)
                    331:        return(-1);
                    332:     entry->name = xmlStrdup(name);
1.3       veillard  333:     entry->name2 = xmlStrdup(name2);
                    334:     entry->name3 = xmlStrdup(name3);
1.1       veillard  335:     entry->payload = userdata;
                    336:     entry->next = NULL;
                    337: 
                    338: 
                    339:     if (insert == NULL) {
                    340:        table->table[key] = entry;
                    341:     } else {
                    342:        insert->next = entry;
                    343:     }
                    344:     return(0);
                    345: }
                    346: 
                    347: /**
                    348:  * xmlHashLookup:
                    349:  * @table: the hash table
                    350:  * @name: the name of the userdata
1.3       veillard  351:  * @name2: a second name of the userdata
                    352:  * @name3: a third name of the userdata
1.1       veillard  353:  *
1.5       veillard  354:  * Find the userdata specified by the (name, name2, name3) tuple.
1.1       veillard  355:  *
                    356:  * Returns the a pointer to the userdata
                    357:  */
                    358: void *
1.3       veillard  359: xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 
                    360:               const xmlChar *name2, const xmlChar *name3) {
1.1       veillard  361:     unsigned long key;
                    362:     xmlHashEntryPtr entry;
                    363: 
                    364:     if (table == NULL)
                    365:        return(NULL);
                    366:     if (name == NULL)
                    367:        return(NULL);
                    368:     key = xmlHashComputeKey(table, name);
                    369:     for (entry = table->table[key]; entry != NULL; entry = entry->next) {
1.4       veillard  370:        if ((xmlStrEqual(entry->name, name)) &&
                    371:            (xmlStrEqual(entry->name2, name2)) &&
                    372:            (xmlStrEqual(entry->name3, name3)))
1.1       veillard  373:            return(entry->payload);
                    374:     }
                    375:     return(NULL);
                    376: }
1.2       veillard  377: 
                    378: /**
                    379:  * xmlHashScan:
                    380:  * @table: the hash table
                    381:  * @f:  the scanner function for items in the hash
                    382:  * @data:  extra data passed to f
                    383:  *
                    384:  * Scan the hash table and applied f to each value.
                    385:  */
                    386: void
                    387: xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
                    388:     int i;
                    389:     xmlHashEntryPtr iter;
                    390:     xmlHashEntryPtr next;
                    391: 
                    392:     if (table == NULL)
                    393:        return;
                    394:     if (f == NULL)
                    395:        return;
                    396: 
                    397:     if (table->table) {
                    398:        for(i = 0; i < table->size; i++) {
                    399:            iter = table->table[i];
                    400:            while (iter) {
                    401:                next = iter->next;
                    402:                if (f)
1.6     ! veillard  403:                    f(iter->payload, data, iter->name);
1.5       veillard  404:                iter = next;
                    405:            }
                    406:        }
                    407:     }
                    408: }
                    409: 
                    410: /**
                    411:  * xmlHashScan3:
                    412:  * @table: the hash table
                    413:  * @name: the name of the userdata or NULL
                    414:  * @name2: a second name of the userdata or NULL
                    415:  * @name3: a third name of the userdata or NULL
                    416:  * @f:  the scanner function for items in the hash
                    417:  * @data:  extra data passed to f
                    418:  *
                    419:  * Scan the hash table and applied f to each value matching
                    420:  * (name, name2, name3) tuple. If one of the names is null,
                    421:  * the comparison is considered to match.
                    422:  */
                    423: void
                    424: xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, 
                    425:             const xmlChar *name2, const xmlChar *name3,
                    426:             xmlHashScanner f, void *data) {
                    427:     int i;
                    428:     xmlHashEntryPtr iter;
                    429:     xmlHashEntryPtr next;
                    430: 
                    431:     if (table == NULL)
                    432:        return;
                    433:     if (f == NULL)
                    434:        return;
                    435: 
                    436:     if (table->table) {
                    437:        for(i = 0; i < table->size; i++) {
                    438:            iter = table->table[i];
                    439:            while (iter) {
                    440:                next = iter->next;
                    441:                if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
                    442:                    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
                    443:                    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
1.6     ! veillard  444:                    f(iter->payload, data, iter->name);
1.5       veillard  445:                }
1.2       veillard  446:                iter = next;
                    447:            }
                    448:        }
                    449:     }
                    450: }
                    451: 
                    452: /**
                    453:  * xmlHashCopy:
                    454:  * @table: the hash table
                    455:  * @f:  the copier function for items in the hash
                    456:  *
                    457:  * Scan the hash table and applied f to each value.
                    458:  *
                    459:  * Returns the new table or NULL in case of error.
                    460:  */
                    461: xmlHashTablePtr
                    462: xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
                    463:     int i;
                    464:     xmlHashEntryPtr iter;
                    465:     xmlHashEntryPtr next;
                    466:     xmlHashTablePtr ret;
                    467: 
                    468:     if (table == NULL)
                    469:        return(NULL);
                    470:     if (f == NULL)
                    471:        return(NULL);
                    472: 
                    473:     ret = xmlHashCreate(table->size);
                    474:     if (table->table) {
                    475:        for(i = 0; i < table->size; i++) {
                    476:            iter = table->table[i];
                    477:            while (iter) {
                    478:                next = iter->next;
1.3       veillard  479:                xmlHashAddEntry3(ret, iter->name, iter->name2,
1.6     ! veillard  480:                                 iter->name3, f(iter->payload, iter->name));
1.2       veillard  481:                iter = next;
                    482:            }
                    483:        }
                    484:     }
                    485:     return(ret);
                    486: }
                    487: 

Webmaster