Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
NIH: create our own hash structure
Baptiste Daroussin committed 4 years ago
commit 8ca695f9618f763186da95e57d86119859b7463b
parent 9872ee9
3 files changed +269 -1
modified libpkg/Makefile.autosetup
@@ -47,7 +47,8 @@ SRCS= backup.c \
	fetch_ssh.c \
	fetch_libfetch.c \
	fetch_file.c \
-
	triggers.c
+
	triggers.c \
+
	pkghash.c

LOCAL_CFLAGS=	-I$(top_srcdir)/compat \
		-I$(top_srcdir)/external/blake2 \
@@ -56,6 +57,7 @@ LOCAL_CFLAGS= -I$(top_srcdir)/compat \
		-I$(top_srcdir)/external/picosat \
		-I$(top_srcdir)/external/yxml \
		-I$(top_srcdir)/external/include \
+
		-I$(top_srcdir)/external/mum \
		-I$(top_srcdir)/external/libucl/include \
		-I$(top_srcdir)/external/libucl/klib \
		-I$(top_srcdir)/external/libfetch \
added libpkg/pkghash.c
@@ -0,0 +1,223 @@
+
/*-
+
 * Copyright (c) 2021 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * Redistribution and use in source and binary forms, with or without
+
 * modification, are permitted provided that the following conditions
+
 * are met:
+
 * 1. Redistributions of source code must retain the above copyright
+
 *    notice, this list of conditions and the following disclaimer
+
 *    in this position and unchanged.
+
 * 2. Redistributions in binary form must reproduce the above copyright
+
 *    notice, this list of conditions and the following disclaimer in the
+
 *    documentation and/or other materials provided with the distribution.
+
 *
+
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 */
+

+
#include "pkghash.h"
+

+
#include <stdint.h>
+
#include <stdlib.h>
+
#include <string.h>
+
#include <mum.h>
+
#include <xmalloc.h>
+

+
struct pkghash {
+
	pkghash_entry *entries;
+
	size_t capacity;
+
	size_t count;
+
	size_t index;
+
};
+

+
pkghash *
+
pkghash_new(void)
+
{
+
	pkghash *table = xmalloc(sizeof(pkghash));
+
	table->count = 0;
+
	table->capacity = 128;
+

+
	table->entries = xcalloc(table->capacity, sizeof(pkghash_entry));
+
	return (table);
+
}
+

+
void
+
pkghash_destroy(pkghash *table)
+
{
+
	if (table == NULL)
+
		return;
+

+
	for (size_t i = 0; i < table->capacity; i++) {
+
		if (table->entries[i].key != NULL)
+
			free(table->entries[i].key);
+
		if (table->entries[i].free_func != NULL)
+
			table->entries[i].free_func(table->entries[i].value);
+
	}
+
	free(table->entries);
+
	free(table);
+
}
+

+
pkghash_entry *
+
pkghash_get(pkghash *table, const char *key)
+
{
+
	if (table == NULL)
+
		return (NULL);
+
	uint64_t hash = mum_hash(key, strlen(key), 0);
+
	size_t index = (size_t)(hash & (uint64_t)(table->capacity -1));
+

+
	while (table->entries[index].key != NULL) {
+
		if (strcmp(key, table->entries[index].key) == 0)
+
			return (&table->entries[index]);
+
		index++;
+
		if (index >= table->capacity)
+
			index = 0;
+
	}
+
	return (NULL);
+
}
+

+
static const char *
+
pkghash_set_entry(pkghash_entry *entries, size_t capacity,
+
    const char *key, void *value, size_t *pcount, void (*free_func)(void *)) {
+
	uint64_t hash = mum_hash(key, strlen(key), 0);
+
	size_t index = (size_t)(hash & (uint64_t)(capacity - 1));
+

+
	while (entries[index].key != NULL) {
+
		if (strcmp(key, entries[index].key) == 0) {
+
			if (entries[index].free_func != NULL)
+
				entries[index].free_func(entries[index].value);
+
			entries[index].value = value;
+
			return (entries[index].key);
+
		}
+
		index++;
+
		if (index >= capacity)
+
			index = 0;
+
	}
+

+
	if (pcount != NULL) {
+
		key = xstrdup(key);
+
		(*pcount)++;
+
	}
+
	entries[index].key = (char *)key;
+
	entries[index].value = value;
+
	entries[index].free_func = free_func;
+
	return (key);
+
}
+

+
static bool
+
pkghash_expand(pkghash *table)
+
{
+
	size_t new_capacity = table->capacity * 2;
+
	if (new_capacity < table->capacity)
+
		return (false);
+
	pkghash_entry *new_entries = xcalloc(new_capacity, sizeof(pkghash_entry));
+

+
	for (size_t i = 0; i < table->capacity; i++) {
+
		pkghash_entry entry = table->entries[i];
+
		if (entry.key != NULL)
+
			pkghash_set_entry(new_entries, new_capacity, entry.key,
+
			    entry.value, NULL, entry.free_func);
+
	}
+

+
	free(table->entries);
+
	table->entries = new_entries;
+
	table->capacity = new_capacity;
+
	return (true);
+
}
+

+
const char *
+
pkghash_add(pkghash *table, const char *key, void *value, void (*free_func)(void *))
+
{
+
	if (table->count >= table->capacity / 2 && !pkghash_expand(table))
+
		return (NULL);
+

+
	return (pkghash_set_entry(table->entries, table->capacity, key, value,
+
	    &table->count, free_func));
+
}
+

+
size_t
+
pkghash_count(pkghash *table)
+
{
+
	if (table == 0)
+
		return (0);
+
	return (table->count);
+
}
+

+
pkghash_it
+
pkghash_iterator(pkghash *table)
+
{
+
	pkghash_it it;
+
	it._table = table;
+
	it._index = 0;
+
	return (it);
+
}
+

+
bool
+
pkghash_next(pkghash_it *it)
+
{
+
	pkghash *table = it->_table;
+
	if (table == NULL)
+
		return (false);
+
	if (table->count == 0)
+
		return (false);
+
	while (it->_index < table->capacity) {
+
		size_t i = it->_index;
+
		it->_index++;
+
		if (table->entries[i].key != NULL) {
+
			pkghash_entry entry = table->entries[i];
+
			it->key = entry.key;
+
			it->value = entry.value;
+
			return (true);
+
		}
+
	}
+
	return (false);
+
}
+

+
void
+
pkghash_loopinit(pkghash *h)
+
{
+
	if (h == NULL)
+
		return;
+
	h->index = 0;
+
}
+

+
pkghash_entry *
+
pkghash_inext(pkghash *h)
+
{
+
	if (h == NULL)
+
		return (NULL);
+
	if (h->count == 0) {
+
		h->index = 0;
+
		return (NULL);
+
	}
+

+
	while (h->index < h->capacity) {
+
		size_t i = h->index;
+
		h->index++;
+
		if (h->entries[i].key != NULL)
+
			return (&h->entries[i]);
+
	}
+
	/* rewind just in case */
+
	h->index = 0;
+
	return (NULL);
+
}
+

+
bool
+
pkghash_del(pkghash *h, const char *key)
+
{
+
	pkghash_entry *e = pkghash_get(h, key);
+
	if (e == NULL)
+
		return (false);
+
	free(e->key);
+
	if (e->free_func != NULL)
+
		e->free_func(e->value);
+
	h->count--;
+
	return (true);
+
}
added libpkg/pkghash.h
@@ -0,0 +1,43 @@
+
#ifndef _PKGHASH_H
+
#define _PKGHASH_H
+

+
#include <stdbool.h>
+
#include <stddef.h>
+

+
typedef struct pkghash pkghash;
+

+
pkghash *pkghash_new(void);
+
void pkghash_destroy(pkghash *table);
+
const char *pkghash_add(pkghash *table, const char *key, void *value, void (*free_func)(void *));
+
size_t pkghash_count(pkghash *table);
+

+
typedef struct {
+
	char* key;
+
	void* value;
+
	pkghash *_table;
+
	size_t _index;
+
} pkghash_it;
+

+
typedef struct {
+
	char *key;
+
	void *value;
+
	void (*free_func)(void*);
+
} pkghash_entry;
+

+
pkghash_entry *pkghash_get(pkghash *table, const char *key);
+
pkghash_it pkghash_iterator(pkghash *table);
+
bool pkghash_next(pkghash_it *it);
+
#define pkghash_safe_add(_t, _k, _v, _free_func) do { \
+
	if (_t == NULL)                               \
+
		_t = pkghash_new();                   \
+
	else if (pkghash_get(_t, _k) != NULL)         \
+
		break;                                \
+
	pkghash_add(_t, _k, _v, _free_func);          \
+
} while (0);
+

+
void pkghash_loopinit(pkghash *h);
+
pkghash_entry *pkghash_inext(pkghash *h);
+
bool pkghash_del(pkghash *h, const char *key);
+

+
#endif
+