hash.cpp

来自「Shorthand是一个强大的脚本语言」· C++ 代码 · 共 273 行

CPP
273
字号
///////////////////////////////////////////////////////////////////////////////
// $Header: /shorthand/src/hash.cpp 1     1/09/03 7:14p Arm $
//-----------------------------------------------------------------------------
// Project: ShortHand interpreter
// Author: Andrei Remenchuk <andrei@remenchuk.com>
//-----------------------------------------------------------------------------
// sharray.cpp: ShortHand Hash Array class - implementation
///////////////////////////////////////////////////////////////////////////////
#include "hash.h"
#include "except.h"
#include <stdlib.h>

#define BUCKET_COUNT_0 64
#define BUCKET_LEVELS  1

static unsigned int makeHash(const char* s)
{
   register const char *p;
   register unsigned int h = 0;
   for(p = (const char*) s; *p != '\0'; p++) 
   {
      h = ( h << 5 ) - h + *p;
   }
   return h;
}


ShhHashEntry::ShhHashEntry(const string& index, const ShhValue& value)
: m_index(index), m_value(value)
{
    m_hash = makeHash(index.cstr());
}


ShhHashBucket::ShhHashBucket(unsigned int level, unsigned int key)
{
    m_level = level;
    m_key = key;
    m_divider = 1; 
    for(unsigned int i=0;i<=level;i++) m_divider *= BUCKET_COUNT_0;

    m_count = 0;
    m_sorted = 0;
    m_dirty = 0;
    m_capacity = 0;
    m_elements = 0;
}

void ShhHashBucket::provideCapacity(int newCapacity)
{
    if (newCapacity > m_capacity)
    {
        m_capacity = (newCapacity/32+1)*32;
        if (m_elements == NULL) 
            m_elements = (ShhHashEntry**) malloc(sizeof(ShhHashEntry*)*m_capacity);
        else 
            m_elements = (ShhHashEntry**) realloc(m_elements, sizeof(ShhHashEntry*)*m_capacity);
    }
}

ShhHashBucket::~ShhHashBucket()
{
    if (m_elements != NULL)
    {
        for(int i=0,n=m_count; i<n; i++)
        {
            if (m_elements[i] != NULL) delete m_elements[i];
        }
    }
}

typedef int (*compare_t)(const void *arg1, const void *arg2);

static int compareHashCodes(ShhHashCode **a, ShhHashCode **b)
{
    return (*a)->m_hash - (*b)->m_hash;
}



ShhHashEntry* ShhHashBucket::findElement(const string& index)
{
    int i;
    unsigned int hashCode = makeHash(index);
    if (m_sorted > 0)
    {
        ShhHashCode bKey(hashCode);
        ShhHashCode* bKeyAddress = &bKey;
        ShhHashEntry** match = (ShhHashEntry**)
            bsearch(&bKeyAddress, m_elements, m_sorted, sizeof(ShhHashEntry*), (compare_t) compareHashCodes);
        if (match != NULL)
        {
            i = match - m_elements;
            while(i>0 && m_elements[i-1]->m_hash == hashCode) i--;
            while(i<m_sorted && m_elements[i]->m_hash == hashCode)
            {
                if (strcmp(m_elements[i]->getIndex(), index) == 0) return m_elements[i];
            }
        }
    }
    for(i=m_sorted; i<m_count; i++)
    {
        if (strcmp(m_elements[i]->getIndex(), index) == 0) return m_elements[i];
    }
    return NULL;
}

ShhHashEntry* ShhHashBucket::createElement(const string& index, const ShhValue& value)
{
    provideCapacity(m_count+1);
    ShhHashEntry* element = new ShhHashEntry(index, value);
    m_elements[m_count] = element;
    m_count++;
    m_dirty++;
    if (m_dirty > 64)
    {
        qsort(m_elements, m_count, sizeof(ShhHashEntry*), (compare_t) compareHashCodes);
        m_sorted = m_count;
    }
    return element;
}



ShhHash::ShhHash(ShhModule& module, const YYLTYPE& location)
: ShhObject(module, "HASH", location)
{
    m_count = 0;
    for(int i=0,n=BUCKET_COUNT_0; i<n; i++)
    {
        m_buckets.add(new ShhHashBucket(0, i));
    }
}

ShhHash::~ShhHash()
{
}

void ShhHash::constructor(ShhValueList* args)
{
}

bool ShhHash::hasMethod(const char* name)
{
    return false;
}

ShhValue ShhHash::executeMethod(const char* name, ShhValueList* args)
{
    return ShhValue::null();
}

ShhValue& ShhHash::getProperty(const char* name)
{
    if (stricmp(name, "count") == 0)
    {
        m_count_property = m_count;
        return m_count_property;
    }
    else
        return ShhObject::getProperty(name);
}


ShhHashBucket* ShhHash::findBucket(unsigned int hashCode)
{
    int key = hashCode%BUCKET_COUNT_0;
    return m_buckets.get(key);
}

ShhHashBucket* ShhHash::createBucket(unsigned int hashCode)
{
    int key = hashCode%BUCKET_COUNT_0;
    return m_buckets.get(key);
}


ShhValue ShhHash::rvalue(const ShhValue& index) 
{
    string sIndex;
    index.toString(sIndex);
    unsigned int hashCode = makeHash(sIndex);

    ShhHashBucket* bucket = findBucket(hashCode);
    if (bucket == NULL) bucket = createBucket(hashCode);

    ShhHashEntry* element = bucket->findElement(sIndex);
    if (element == NULL) return ShhValue::null();
    else return element->getValue();
}

ShhValue& ShhHash::lvalue(const ShhValue& index) 
{
    string sIndex;
    index.toString(sIndex);
    unsigned int hashCode = makeHash(sIndex);

    ShhHashBucket* bucket = findBucket(hashCode);
    if (bucket == NULL) bucket = createBucket(hashCode);

    ShhHashEntry* element = bucket->findElement(sIndex);
    if (element == NULL) 
    {
        m_count++;
        element = bucket->createElement(sIndex, ShhValue::EMPTY);
    }
    return element->getValue();
}

void ShhHash::set(const ShhValue& index, ShhValue value)
{
    string sIndex;
    index.toString(sIndex);
    unsigned int hashCode = makeHash(sIndex);

    ShhHashBucket* bucket = findBucket(hashCode);
    if (bucket == NULL) bucket = createBucket(hashCode);

    ShhHashEntry* element = bucket->findElement(sIndex);
    if (element == NULL) 
    {
        element = bucket->createElement(sIndex, value);
        m_count++;
    }
    else
        element->getValue() = value;
}

int ShhHash::size() const
{
    return m_count;
}

ShhHashIterator::ShhHashIterator()
{
    m_hash = NULL;
    m_bucket_index = 0;
    m_element_index = 0;
}

bool ShhHashIterator::next(ShhValue& index, ShhValue& value)
{
    int bucketCount = m_hash->m_buckets.size();
    while(m_bucket_index < bucketCount)
    {
        ShhHashBucket* bucket = m_hash->m_buckets.get(m_bucket_index);
        int elementCount = bucket->m_count;
        if (m_element_index < elementCount)
        {
            ShhHashEntry* entry = bucket->m_elements[m_element_index];
            index = entry->getIndex();
            value = entry->getValue();
            m_element_index++;
            return true;
        }
        m_bucket_index++;
        m_element_index = 0;
    }
    return false;

    
}

void ShhHash::createIterator(ShhHashIterator& iterator)
{
    iterator.m_hash = this;
    iterator.m_bucket_index = 0;
    iterator.m_element_index = 0;
}



⌨️ 快捷键说明

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