|
Packit |
6d2c1b |
/*
|
|
Packit |
6d2c1b |
* Copyright (c) 2001-2020 Mellanox Technologies, Ltd. All rights reserved.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* This software is available to you under a choice of one of two
|
|
Packit |
6d2c1b |
* licenses. You may choose to be licensed under the terms of the GNU
|
|
Packit |
6d2c1b |
* General Public License (GPL) Version 2, available from the file
|
|
Packit |
6d2c1b |
* COPYING in the main directory of this source tree, or the
|
|
Packit |
6d2c1b |
* BSD license below:
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* Redistribution and use in source and binary forms, with or
|
|
Packit |
6d2c1b |
* without modification, are permitted provided that the following
|
|
Packit |
6d2c1b |
* conditions are met:
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* - Redistributions of source code must retain the above
|
|
Packit |
6d2c1b |
* copyright notice, this list of conditions and the following
|
|
Packit |
6d2c1b |
* disclaimer.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* - Redistributions in binary form must reproduce the above
|
|
Packit |
6d2c1b |
* copyright notice, this list of conditions and the following
|
|
Packit |
6d2c1b |
* disclaimer in the documentation and/or other materials
|
|
Packit |
6d2c1b |
* provided with the distribution.
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
Packit |
6d2c1b |
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
Packit |
6d2c1b |
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
Packit |
6d2c1b |
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
Packit |
6d2c1b |
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
Packit |
6d2c1b |
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
Packit |
6d2c1b |
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
Packit |
6d2c1b |
* SOFTWARE.
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#include <stdio.h>
|
|
Packit |
6d2c1b |
#include <stdlib.h>
|
|
Packit |
6d2c1b |
#include <stdint.h>
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#include "hash.h"
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
#define HASH_KEY_INVALID (hash_key_t)(-1)
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
/**
|
|
Packit |
6d2c1b |
* @struct hash_element
|
|
Packit |
6d2c1b |
* @brief It is an object to be stored in a hash container
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
struct hash_element {
|
|
Packit |
6d2c1b |
hash_key_t key; /**< key */
|
|
Packit |
6d2c1b |
void *value; /**< value */
|
|
Packit |
6d2c1b |
};
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
/**
|
|
Packit |
6d2c1b |
* @struct hash_object
|
|
Packit |
6d2c1b |
* @brief hash container
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
struct hash_object {
|
|
Packit |
6d2c1b |
struct hash_element *hash_table; /**< hash table */
|
|
Packit |
6d2c1b |
struct hash_element *last; /**< last accessed */
|
|
Packit |
6d2c1b |
int size; /**< maximum number of elements */
|
|
Packit |
6d2c1b |
int count; /**< current count of elements */
|
|
Packit |
6d2c1b |
hash_freefunc_t free; /**< free function */
|
|
Packit |
6d2c1b |
};
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
static struct hash_element* hash_find(hash_t ht, hash_key_t key, int flag);
|
|
Packit |
6d2c1b |
static int check_prime(int value);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
hash_t hash_create(hash_freefunc_t free_func, size_t size)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
hash_t ht = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
/* Check passed size */
|
|
Packit |
6d2c1b |
if (!check_prime(size)) {
|
|
Packit |
6d2c1b |
return NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
ht = (struct hash_object *)malloc(sizeof(*ht));
|
|
Packit |
6d2c1b |
if (ht) {
|
|
Packit |
6d2c1b |
ht->size = size;
|
|
Packit |
6d2c1b |
ht->hash_table = (struct hash_element *)calloc(ht->size,
|
|
Packit |
6d2c1b |
sizeof(*ht->hash_table));
|
|
Packit |
6d2c1b |
if (ht->hash_table) {
|
|
Packit |
6d2c1b |
int i = 0;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
ht->last = NULL;
|
|
Packit |
6d2c1b |
ht->count = 0;
|
|
Packit |
6d2c1b |
ht->free = free_func;
|
|
Packit |
6d2c1b |
for (i = 0; i < ht->size; i++) {
|
|
Packit |
6d2c1b |
ht->hash_table[i].key = HASH_KEY_INVALID;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
free(ht);
|
|
Packit |
6d2c1b |
ht = NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return ht;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void hash_destroy(hash_t ht)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (ht) {
|
|
Packit |
6d2c1b |
if (ht->hash_table) {
|
|
Packit |
6d2c1b |
int i = 0;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
for (i = 0; i < ht->size; i++) {
|
|
Packit |
6d2c1b |
if (ht->hash_table[i].key != HASH_KEY_INVALID) {
|
|
Packit |
6d2c1b |
if (ht->free && ht->hash_table[i].value) {
|
|
Packit |
6d2c1b |
ht->free(ht->hash_table[i].value);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
ht->hash_table[i].key = HASH_KEY_INVALID;
|
|
Packit |
6d2c1b |
ht->hash_table[i].value = NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
free(ht->hash_table);
|
|
Packit |
6d2c1b |
ht->hash_table = NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
free(ht);
|
|
Packit |
6d2c1b |
ht = NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
int hash_count(hash_t ht)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
return ht->count;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
int hash_size(hash_t ht)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
return ht->size;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void *hash_get(hash_t ht, hash_key_t key)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (ht) {
|
|
Packit |
6d2c1b |
struct hash_element *entry = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
entry = hash_find(ht, key, 0);
|
|
Packit |
6d2c1b |
if (entry) {
|
|
Packit |
6d2c1b |
return entry->value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void *hash_enum(hash_t ht, size_t index)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (ht) {
|
|
Packit |
6d2c1b |
struct hash_element *entry = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
entry = &(ht->hash_table[index]);
|
|
Packit |
6d2c1b |
if (entry) {
|
|
Packit |
6d2c1b |
return entry->value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void *hash_put(hash_t ht, hash_key_t key, void *value)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (ht && (ht->count < ht->size)) {
|
|
Packit |
6d2c1b |
struct hash_element *entry = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
entry = hash_find(ht, key, 0);
|
|
Packit |
6d2c1b |
if (NULL == entry) {
|
|
Packit |
6d2c1b |
entry = hash_find(ht, key, 1);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (entry) {
|
|
Packit |
6d2c1b |
if (ht->free && entry->value) {
|
|
Packit |
6d2c1b |
ht->free(entry->value);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (entry->key == HASH_KEY_INVALID) {
|
|
Packit |
6d2c1b |
ht->count++;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
entry->key = key;
|
|
Packit |
6d2c1b |
entry->value = value;
|
|
Packit |
6d2c1b |
return value;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
void hash_del(hash_t ht, hash_key_t key)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
if (ht) {
|
|
Packit |
6d2c1b |
struct hash_element *entry = NULL;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
entry = hash_find(ht, key, 0);
|
|
Packit |
6d2c1b |
if (entry) {
|
|
Packit |
6d2c1b |
if (ht->free && entry->value) {
|
|
Packit |
6d2c1b |
ht->free(entry->value);
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
if (entry->key != HASH_KEY_INVALID) {
|
|
Packit |
6d2c1b |
ht->count--;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
entry->key = HASH_KEY_INVALID;
|
|
Packit |
6d2c1b |
entry->value = NULL;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
/* hash_find():
|
|
Packit |
6d2c1b |
*
|
|
Packit |
6d2c1b |
* Find a place (hash element) in the hash related key or
|
|
Packit |
6d2c1b |
* new element.
|
|
Packit |
6d2c1b |
* @param ht - point to hash object
|
|
Packit |
6d2c1b |
* @param key - key identified data
|
|
Packit |
6d2c1b |
* @param flag - 1 - add new, 0 - find existing
|
|
Packit |
6d2c1b |
* @return hash element or NULL in case there is no place.
|
|
Packit |
6d2c1b |
*/
|
|
Packit |
6d2c1b |
static struct hash_element* hash_find(hash_t ht, hash_key_t key, int flag)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
struct hash_element *entry = NULL;
|
|
Packit |
6d2c1b |
int attempts = 0;
|
|
Packit |
6d2c1b |
int idx = 0;
|
|
Packit |
6d2c1b |
hash_key_t expect_key;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
if (ht->last && ht->last->key == key)
|
|
Packit |
6d2c1b |
return ht->last;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
expect_key = (flag ? HASH_KEY_INVALID : key);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
idx = key % ht->size;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
do {
|
|
Packit |
6d2c1b |
entry = &(ht->hash_table[idx]);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
if (entry->key == expect_key) {
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
} else {
|
|
Packit |
6d2c1b |
if (attempts >= (ht->size - 1)) {
|
|
Packit |
6d2c1b |
entry = NULL;
|
|
Packit |
6d2c1b |
break;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
attempts++;
|
|
Packit |
6d2c1b |
idx = (idx + 1) % ht->size;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
} while (1);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
ht->last = (entry ? entry : ht->last);
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return entry;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
static int check_prime(int value)
|
|
Packit |
6d2c1b |
{
|
|
Packit |
6d2c1b |
int i = 0;
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
for (i = 2; i <= value / 2; i++) {
|
|
Packit |
6d2c1b |
if ((value % i) == 0) {
|
|
Packit |
6d2c1b |
return 0;
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
}
|
|
Packit |
6d2c1b |
|
|
Packit |
6d2c1b |
return 1;
|
|
Packit |
6d2c1b |
}
|