⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jsdhash.c

📁 java script test programing source code
💻 C
📖 第 1 页 / 共 2 页
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- *//* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla JavaScript code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1999-2001 * the Initial Developer. All Rights Reserved. * * Contributor(s): *   Brendan Eich <brendan@mozilla.org> (Original Author) *   Chris Waterson <waterson@netscape.com> * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** *//* * Double hashing implementation. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "jsbit.h"#include "jsdhash.h"#include "jsutil.h"     /* for JS_ASSERT */#ifdef JS_DHASHMETER# if defined MOZILLA_CLIENT && defined DEBUG_XXXbrendan#  include "nsTraceMalloc.h"# endif# define METER(x)       x#else# define METER(x)       /* nothing */#endif/* * The following DEBUG-only code is used to assert that calls to one of * table->ops or to an enumerator do not cause re-entry into a call that * can mutate the table.  The recursion level is stored in additional * space allocated at the end of the entry store to avoid changing * JSDHashTable, which could cause issues when mixing DEBUG and * non-DEBUG components. */#ifdef DEBUG#define RECURSION_LEVEL(table_) (*(uint32*)(table_->entryStore + \                                            JS_DHASH_TABLE_SIZE(table_) * \                                            table_->entrySize))#define ENTRY_STORE_EXTRA                   sizeof(uint32)#define INCREMENT_RECURSION_LEVEL(table_)   (++RECURSION_LEVEL(table_))#define DECREMENT_RECURSION_LEVEL(table_)   (--RECURSION_LEVEL(table_))#else#define ENTRY_STORE_EXTRA 0#define INCREMENT_RECURSION_LEVEL(table_)   ((void)1)#define DECREMENT_RECURSION_LEVEL(table_)   ((void)0)#endif /* defined(DEBUG) */JS_PUBLIC_API(void *)JS_DHashAllocTable(JSDHashTable *table, uint32 nbytes){    return malloc(nbytes);}JS_PUBLIC_API(void)JS_DHashFreeTable(JSDHashTable *table, void *ptr){    free(ptr);}JS_PUBLIC_API(JSDHashNumber)JS_DHashStringKey(JSDHashTable *table, const void *key){    JSDHashNumber h;    const unsigned char *s;    h = 0;    for (s = key; *s != '\0'; s++)        h = (h >> (JS_DHASH_BITS - 4)) ^ (h << 4) ^ *s;    return h;}JS_PUBLIC_API(const void *)JS_DHashGetKeyStub(JSDHashTable *table, JSDHashEntryHdr *entry){    JSDHashEntryStub *stub = (JSDHashEntryStub *)entry;    return stub->key;}JS_PUBLIC_API(JSDHashNumber)JS_DHashVoidPtrKeyStub(JSDHashTable *table, const void *key){    return (JSDHashNumber)(unsigned long)key >> 2;}JS_PUBLIC_API(JSBool)JS_DHashMatchEntryStub(JSDHashTable *table,                       const JSDHashEntryHdr *entry,                       const void *key){    const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;    return stub->key == key;}JS_PUBLIC_API(JSBool)JS_DHashMatchStringKey(JSDHashTable *table,                       const JSDHashEntryHdr *entry,                       const void *key){    const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;    /* XXX tolerate null keys on account of sloppy Mozilla callers. */    return stub->key == key ||           (stub->key && key && strcmp(stub->key, key) == 0);}JS_PUBLIC_API(void)JS_DHashMoveEntryStub(JSDHashTable *table,                      const JSDHashEntryHdr *from,                      JSDHashEntryHdr *to){    memcpy(to, from, table->entrySize);}JS_PUBLIC_API(void)JS_DHashClearEntryStub(JSDHashTable *table, JSDHashEntryHdr *entry){    memset(entry, 0, table->entrySize);}JS_PUBLIC_API(void)JS_DHashFreeStringKey(JSDHashTable *table, JSDHashEntryHdr *entry){    const JSDHashEntryStub *stub = (const JSDHashEntryStub *)entry;    free((void *) stub->key);    memset(entry, 0, table->entrySize);}JS_PUBLIC_API(void)JS_DHashFinalizeStub(JSDHashTable *table){}static const JSDHashTableOps stub_ops = {    JS_DHashAllocTable,    JS_DHashFreeTable,    JS_DHashGetKeyStub,    JS_DHashVoidPtrKeyStub,    JS_DHashMatchEntryStub,    JS_DHashMoveEntryStub,    JS_DHashClearEntryStub,    JS_DHashFinalizeStub,    NULL};JS_PUBLIC_API(const JSDHashTableOps *)JS_DHashGetStubOps(void){    return &stub_ops;}JS_PUBLIC_API(JSDHashTable *)JS_NewDHashTable(const JSDHashTableOps *ops, void *data, uint32 entrySize,                 uint32 capacity){    JSDHashTable *table;    table = (JSDHashTable *) malloc(sizeof *table);    if (!table)        return NULL;    if (!JS_DHashTableInit(table, ops, data, entrySize, capacity)) {        free(table);        return NULL;    }    return table;}JS_PUBLIC_API(void)JS_DHashTableDestroy(JSDHashTable *table){    JS_DHashTableFinish(table);    free(table);}JS_PUBLIC_API(JSBool)JS_DHashTableInit(JSDHashTable *table, const JSDHashTableOps *ops, void *data,                  uint32 entrySize, uint32 capacity){    int log2;    uint32 nbytes;#ifdef DEBUG    if (entrySize > 10 * sizeof(void *)) {        fprintf(stderr,                "jsdhash: for the table at address %p, the given entrySize"                " of %lu %s favors chaining over double hashing.\n",                (void *)table,                (unsigned long) entrySize,                (entrySize > 16 * sizeof(void*)) ? "definitely" : "probably");    }#endif    table->ops = ops;    table->data = data;    if (capacity < JS_DHASH_MIN_SIZE)        capacity = JS_DHASH_MIN_SIZE;    JS_CEILING_LOG2(log2, capacity);    capacity = JS_BIT(log2);    if (capacity >= JS_DHASH_SIZE_LIMIT)        return JS_FALSE;    table->hashShift = JS_DHASH_BITS - log2;    table->maxAlphaFrac = 0xC0;                 /* .75 */    table->minAlphaFrac = 0x40;                 /* .25 */    table->entrySize = entrySize;    table->entryCount = table->removedCount = 0;    table->generation = 0;    nbytes = capacity * entrySize;    table->entryStore = ops->allocTable(table, nbytes + ENTRY_STORE_EXTRA);    if (!table->entryStore)        return JS_FALSE;    memset(table->entryStore, 0, nbytes);    METER(memset(&table->stats, 0, sizeof table->stats));#ifdef DEBUG    RECURSION_LEVEL(table) = 0;#endif    return JS_TRUE;}/* * Compute max and min load numbers (entry counts) from table params. */#define MAX_LOAD(table, size)   (((table)->maxAlphaFrac * (size)) >> 8)#define MIN_LOAD(table, size)   (((table)->minAlphaFrac * (size)) >> 8)JS_PUBLIC_API(void)JS_DHashTableSetAlphaBounds(JSDHashTable *table,                            float maxAlpha,                            float minAlpha){    uint32 size;    /*     * Reject obviously insane bounds, rather than trying to guess what the     * buggy caller intended.     */    JS_ASSERT(0.5 <= maxAlpha && maxAlpha < 1 && 0 <= minAlpha);    if (maxAlpha < 0.5 || 1 <= maxAlpha || minAlpha < 0)        return;    /*     * Ensure that at least one entry will always be free.  If maxAlpha at     * minimum size leaves no entries free, reduce maxAlpha based on minimum     * size and the precision limit of maxAlphaFrac's fixed point format.     */    JS_ASSERT(JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) >= 1);    if (JS_DHASH_MIN_SIZE - (maxAlpha * JS_DHASH_MIN_SIZE) < 1) {        maxAlpha = (float)                   (JS_DHASH_MIN_SIZE - JS_MAX(JS_DHASH_MIN_SIZE / 256, 1))                   / JS_DHASH_MIN_SIZE;    }    /*     * Ensure that minAlpha is strictly less than half maxAlpha.  Take care     * not to truncate an entry's worth of alpha when storing in minAlphaFrac     * (8-bit fixed point format).     */    JS_ASSERT(minAlpha < maxAlpha / 2);    if (minAlpha >= maxAlpha / 2) {        size = JS_DHASH_TABLE_SIZE(table);        minAlpha = (size * maxAlpha - JS_MAX(size / 256, 1)) / (2 * size);    }    table->maxAlphaFrac = (uint8)(maxAlpha * 256);    table->minAlphaFrac = (uint8)(minAlpha * 256);}/* * Double hashing needs the second hash code to be relatively prime to table * size, so we simply make hash2 odd. */#define HASH1(hash0, shift)         ((hash0) >> (shift))#define HASH2(hash0,log2,shift)     ((((hash0) << (log2)) >> (shift)) | 1)/* * Reserve keyHash 0 for free entries and 1 for removed-entry sentinels.  Note * that a removed-entry sentinel need be stored only if the removed entry had * a colliding entry added after it.  Therefore we can use 1 as the collision * flag in addition to the removed-entry sentinel value.  Multiplicative hash * uses the high order bits of keyHash, so this least-significant reservation * should not hurt the hash function's effectiveness much. * * If you change any of these magic numbers, also update JS_DHASH_ENTRY_IS_LIVE * in jsdhash.h.  It used to be private to jsdhash.c, but then became public to * assist iterator writers who inspect table->entryStore directly. */#define COLLISION_FLAG              ((JSDHashNumber) 1)#define MARK_ENTRY_FREE(entry)      ((entry)->keyHash = 0)#define MARK_ENTRY_REMOVED(entry)   ((entry)->keyHash = 1)#define ENTRY_IS_REMOVED(entry)     ((entry)->keyHash == 1)#define ENTRY_IS_LIVE(entry)        JS_DHASH_ENTRY_IS_LIVE(entry)#define ENSURE_LIVE_KEYHASH(hash0)  if (hash0 < 2) hash0 -= 2; else (void)0/* Match an entry's keyHash against an unstored one computed from a key. */#define MATCH_ENTRY_KEYHASH(entry,hash0) \    (((entry)->keyHash & ~COLLISION_FLAG) == (hash0))/* Compute the address of the indexed entry in table. */#define ADDRESS_ENTRY(table, index) \    ((JSDHashEntryHdr *)((table)->entryStore + (index) * (table)->entrySize))JS_PUBLIC_API(void)JS_DHashTableFinish(JSDHashTable *table){    char *entryAddr, *entryLimit;    uint32 entrySize;    JSDHashEntryHdr *entry;#ifdef DEBUG_XXXbrendan    static FILE *dumpfp = NULL;    if (!dumpfp) dumpfp = fopen("/tmp/jsdhash.bigdump", "w");    if (dumpfp) {#ifdef MOZILLA_CLIENT        NS_TraceStack(1, dumpfp);#endif        JS_DHashTableDumpMeter(table, NULL, dumpfp);        fputc('\n', dumpfp);    }#endif    INCREMENT_RECURSION_LEVEL(table);    /* Call finalize before clearing entries, so it can enumerate them. */    table->ops->finalize(table);    /* Clear any remaining live entries. */    entryAddr = table->entryStore;    entrySize = table->entrySize;    entryLimit = entryAddr + JS_DHASH_TABLE_SIZE(table) * entrySize;    while (entryAddr < entryLimit) {        entry = (JSDHashEntryHdr *)entryAddr;        if (ENTRY_IS_LIVE(entry)) {            METER(table->stats.removeEnums++);            table->ops->clearEntry(table, entry);        }        entryAddr += entrySize;    }    DECREMENT_RECURSION_LEVEL(table);    JS_ASSERT(RECURSION_LEVEL(table) == 0);    /* Free entry storage last. */    table->ops->freeTable(table, table->entryStore);}static JSDHashEntryHdr * JS_DHASH_FASTCALLSearchTable(JSDHashTable *table, const void *key, JSDHashNumber keyHash,            JSDHashOperator op){    JSDHashNumber hash1, hash2;    int hashShift, sizeLog2;    JSDHashEntryHdr *entry, *firstRemoved;    JSDHashMatchEntry matchEntry;    uint32 sizeMask;    METER(table->stats.searches++);    JS_ASSERT(!(keyHash & COLLISION_FLAG));    /* Compute the primary hash address. */    hashShift = table->hashShift;    hash1 = HASH1(keyHash, hashShift);    entry = ADDRESS_ENTRY(table, hash1);    /* Miss: return space for a new entry. */    if (JS_DHASH_ENTRY_IS_FREE(entry)) {        METER(table->stats.misses++);        return entry;    }    /* Hit: return entry. */    matchEntry = table->ops->matchEntry;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -