Blame tools/daemon/hash.c

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
}