一種基於hash算法的容器接口(適用於所有類hash算法的數據存儲處理)

源碼的下載地址:https://download.csdn.net/download/xiyuan255/12372494
/*
 * File name    : xy_chash_source.c
 *
 * Created on    : 2019年10月11日14:40:24
 * Author        : Firmware of xiyuan255
 * Version        : 2.0
 * Language        : C
 * Copyright    : Copyright (C) 2019, xiyuan255 Inc.
 *
 */
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <assert.h>
#include "xy_chash_source.h"

#ifndef BITS_PER_BYTE
    #define BITS_PER_BYTE     ((int) (8 * sizeof(char)))
#endif

#ifndef BITS
    #define BITS(type)      ((int) (BITS_PER_BYTE * (int) sizeof(type)))
#endif

/**
 * 封裝整型值
 */
PUBLIC cell_value_t value_integer(long value)
{
    cell_value_t v;

    memset(&v, 0x00, sizeof(v));
    v.valid = 1;
    v.type = integer;
    v.value.integer = value;
    return v;
}

/**
 * 封裝浮點型值
 */
PUBLIC cell_value_t value_floating(double value)
{
    cell_value_t v;

    memset(&v, 0x00, sizeof(v));
    v.valid = 1;
    v.type = floating;
    v.value.floating = value;
    return v;
}

/**
 * 封裝字符串型值
 */
PUBLIC cell_value_t value_string(const char *value, int flags)
{
    cell_value_t v;    
    int value_len = 0;

    memset(&v, 0x00, sizeof(v));
    v.valid = 1;
    v.type = string;
    if (value && *value && flags & VALUE_ALLOCATE) {
        v.allocated = 1;
        value_len = strlen(value);
        v.value.string = calloc(sizeof(char), value_len);
        if (NULL != v.value.string) {
            strcpy(v.value.string, value);
        }
    } else {
        v.allocated = 0;
        v.value.string = (char*) value;
    }
    return v;
}

/**
 * 封裝字節型值
 */
PUBLIC cell_value_t value_bytes(const uint8_t *value, int len)
{
    cell_value_t v;    

    memset(&v, 0x00, sizeof(v));
    v.valid = 1;
    v.type = bytes;
    
    if (len > 0) {        
        v.allocated = 1;
        v.byteslen = len;
        v.value.bytes = calloc(sizeof(char), len);
        if (NULL != v.value.bytes) {
            memcpy(v.value.bytes, value, len);
        }
    } else {
        v.allocated = 0;
        v.byteslen = 0;
        v.value.bytes = (uint8_t *)value;
    }    

    return v;
}

/**
 * 封裝符號型值
 */
PUBLIC cell_value_t value_symbol(const void *value)
{
    cell_value_t v;

    memset(&v, 0x00, sizeof(v));
    v.valid = 1;
    v.type = symbol;
    v.value.symbol = (void *)value;
    return v;
}

/**
 * 釋放成員動態內存
 */
PUBLIC void value_free(cell_value_t *v)
{
    if (v->valid && v->allocated) {
        if (string == v->type && NULL != v->value.string) {
            free(v->value.string);
        } else if (bytes == v->type && NULL != v->value.bytes) {
            free(v->value.bytes);
        }
    }
    v->type = undefined;
    v->byteslen = 0;
    v->valid = 0;
    v->allocated = 0;
}

/*
    Check if this number is a prime
 */
__STATIC_INLINE int is_prime(int n)
{
    int     i, max;

    assert(n > 0);

    max = n / 2;
    for (i = 2; i <= max; i++) {
        if (n % i == 0) {
            return 0;
        }
    }
    return 1;
}

/*
    Calculate the largest prime smaller than size.
 */
__STATIC int calc_prime(int size)
{
    int count;

    assert(size > 0);

    for (count = size; count > 0; count--) {
        if (is_prime(count)) {
            return count;
        }
    }
    return 1;
}

/**
 * 計算hash指示值
 * 這個稱爲散列函數,根據不同的key產生散列值。不同的key可能出現相同的散列值,
 * 這稱爲hash碰撞。hash有一個特性,不同的散列值則對應的key一定不同,但相同的
 * 散列值可能對應相同的key也可能對應不同的key。
 */
__STATIC int hash_index(HashTable_t *chash, const char *key)
{
    unsigned int    sum = 0;
    int                i = 0;

    assert(chash && key && *key);
    
    i = 0;
    sum = 0;
    while (*key) {
        sum += (((int) *key++) << i);
        i = (i + 7) % (BITS(int) - BITS_PER_BYTE);
    }
    return sum % chash->size;
}

/*
    Close this symbol table. Call a cleanup function to allow the caller to free resources associated with each symbol
    table entry.
 */
PUBLIC void c_hash_free(HashTable_t *chash)
{
    hash_cell_t   *sp, *forw;
    int         i;

    if (NULL == chash) {
        return;
    }

    /*
        Free all symbols in the hash table, then the hash table itself.
     */
    for (i = 0; i < chash->size; i++) {
        for (sp = chash->hash_table[i]; sp; sp = forw) {
            forw = sp->ptr_next;
            value_free(&sp->key);
            value_free(&sp->content);
            free((void *)sp);
            sp = forw;
        }
    }
    free((void *)chash->hash_table);
    free((void *)chash);
}

/**
 * 創建hash對象
 */
PUBLIC HashTable_t *c_hash_create(int size)
{
    HashTable_t *chash = NULL;

    chash = (HashTable_t *)calloc(sizeof(char), sizeof(HashTable_t));
      if (NULL == chash) {
       return NULL;
    }
    
    chash->size = calc_prime(size); /* 求出size之下的最大素數 */
    chash->hash_table = (hash_cell_p *)malloc(chash->size * sizeof(hash_cell_p));
    if (NULL == chash->hash_table) {
       free(chash);
       return NULL;
    }
    memset(chash->hash_table, 0, chash->size * sizeof(hash_cell_p));

    return chash;
}

/**
 * 向hash對象插入cell_value_t成員
 */
PUBLIC hash_cell_t *c_hash_enter(HashTable_t *chash, const char *key, cell_value_t v, void *arg)
{
    hash_cell_t    *sp, *last;
    int         hindex;    
    char        *cp;

    assert(chash && key && *key);

    last = NULL;
    
    hindex = hash_index(chash, key); 
    if (NULL != (sp = chash->hash_table[hindex])) {
        for (; sp; sp = sp->ptr_next) {
            cp = sp->key.value.string;
            if (cp[0] == key[0] && 0 == strcmp(cp, key)) {
                break;
            }
            last = sp;
        }
        if (sp) { // 已經存在則更新
            if (sp->content.valid) {
                value_free(&sp->content);
            }
            sp->content = v;
            sp->arg = arg;
            return sp;
        }
        sp = (hash_cell_t *)calloc(sizeof(char), sizeof(hash_cell_t));
        if (NULL == sp) {
            return NULL;
        }
        sp->key = value_string(key, VALUE_ALLOCATE);
        sp->content = v;
        sp->ptr_next = (hash_cell_t *)NULL;
        sp->arg = arg;
        sp->index = hindex;
        last->ptr_next = sp;

    } else {
        if ((sp = (hash_cell_t *)malloc(sizeof(hash_cell_t))) == 0) {
            return NULL;
        }
        chash->hash_table[hindex] = sp;

        sp->ptr_next = (hash_cell_t *) NULL;
        sp->content = v;
        sp->arg = arg;
        sp->key = value_string(key, VALUE_ALLOCATE);
        sp->index = hindex;
    }
    return sp;
}

/**
 * 刪除hash對象中key的成員
 */
PUBLIC int c_hash_delete(HashTable_t *chash, const char *key)
{
    hash_cell_t    *sp, *last;
    int         hindex;    
    char        *cp;

    assert(chash && key && *key);
    
    last = NULL;
    hindex = hash_index(chash, key);
    if (NULL != (sp = chash->hash_table[hindex])) {
        for ( ; sp; sp = sp->ptr_next) {
            cp = sp->key.value.string;
            if (cp[0] == key[0] && 0 == strcmp(cp, key)) {
                break;
            }
            last = sp;
        }
    }
    if ((hash_cell_t *)NULL == sp) {
        return -1;
    }
    
    if (last) {
        last->ptr_next = sp->ptr_next;
    } else {
        chash->hash_table[hindex] = sp->ptr_next;
    }
    value_free(&sp->key);
    value_free(&sp->content);
    free((void *)sp);
    
    return 0;
}

/**
 * 獲取hash對象的第一個成員
 */
PUBLIC hash_cell_p c_hash_first(HashTable_t *chash)
{
    int            i = 0;
    hash_cell_p    sp = NULL;
    
    assert(chash);
    
    for (i = 0; i < chash->size; i++) {
        if (NULL != (sp = chash->hash_table[i])) {
            break;
        }
    }
    return sp;
}

/**
 * 獲取hash對象的下一成員
 */
PUBLIC hash_cell_p c_hash_next(HashTable_t *chash, hash_cell_p cell)
{    
    int         i = 0;
    hash_cell_p sp = NULL;
    
    assert(chash);
    
    if (NULL == cell) {
        return c_hash_first(chash);
    }
    if (NULL != cell->ptr_next) {
        return cell->ptr_next;
    }
    for (i = cell->index + 1; i < chash->size; i++) {
        if (NULL != (sp = chash->hash_table[i])) {
            return sp;
        }
    }
    return NULL;
}

/**
 * 查詢hash對象的的key成員
 */
PUBLIC hash_cell_p c_hash_lookup(HashTable_t *chash, const char *key)
{
    hash_cell_p sp = NULL;    
    char        *cp;

    if (NULL == chash || NULL == key) {
        return NULL;
    }
    
    for (sp = chash->hash_table[hash_index(chash, key)]; sp; sp = sp->ptr_next) {
        cp = sp->key.value.string;
        if (cp[0] == key[0] && 0 == strcmp(cp, key)) {
            break;
        }
    }
    return sp;
}

/**
 * 查詢hash對象的的key成員中的整型值
 */
PUBLIC int c_hash_lookup_integer(HashTable_t *chash, const char *key, long *integer)
{
    hash_cell_t    *kp;

    if (NULL == (kp = c_hash_lookup(chash, key))) {
        return -1;
    }
    *integer = kp->content.value.integer;
    
    return 0;
}

/**
 * 查詢hash對象的的key成員中的浮點型值
 */
PUBLIC int c_hash_lookup_floating(HashTable_t *chash, const char *key, double *floating)
{
    hash_cell_t    *kp;

    if (NULL == (kp = c_hash_lookup(chash, key))) {
        return -1;
    }
    *floating = kp->content.value.floating;
    
    return 0;
}

/**
 * 查詢hash對象的的key成員中的字符串值
 */
PUBLIC int c_hash_lookup_string(HashTable_t *chash, const char *key, char *string, int len)
{
    hash_cell_t    *kp;
    int         slen = 0;

    if (NULL == (kp = c_hash_lookup(chash, key))) {
        return -1;
    }
    slen = strlen(kp->content.value.string);
    memcpy(string, kp->content.value.string, (slen >= len)? len-1 : slen);
    
    return 0;
}

/**
 * 查詢hash對象的的key成員中的字節型值
 */
PUBLIC int c_hash_lookup_bytes(HashTable_t *chash, const char *key, uint8_t *bytes, int *iolen)
{
    hash_cell_t    *kp;    
    int         blen = 0;

    if (NULL == (kp = c_hash_lookup(chash, key))) {
        return -1;
    }
    blen = kp->content.byteslen;
    memcpy(bytes, kp->content.value.bytes, (blen >= *iolen)? *iolen-1 : blen);
    *iolen = blen;
    
    return 0;
}

/**
 * 查詢hash對象的的key成員中的符號型值
 */
PUBLIC int c_hash_lookup_symbol(HashTable_t *chash, const char *key, void **symbol)
{
    hash_cell_t    *kp;

    if (NULL == (kp = c_hash_lookup(chash, key))) {
        return -1;
    }
    *symbol = kp->content.value.symbol;
    
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章