mirror of
https://gitlab.com/gnuwget/wget2.git
synced 2026-02-01 14:41:08 +00:00
* libwget/hashmap_old.c: Removed
This commit is contained in:
@ -1,389 +0,0 @@
|
||||
/*
|
||||
* Copyright(c) 2012 Tim Ruehsen
|
||||
* Copyright(c) 2015-2016 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of libwget.
|
||||
*
|
||||
* Libwget is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Libwget is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with libwget. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
* hashmap routines
|
||||
*
|
||||
* Changelog
|
||||
* 06.11.2012 Tim Ruehsen created
|
||||
*
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <wget.h>
|
||||
#include "private.h"
|
||||
|
||||
typedef struct _ENTRY ENTRY;
|
||||
|
||||
struct _ENTRY {
|
||||
void
|
||||
*key,
|
||||
*value;
|
||||
ENTRY
|
||||
*next;
|
||||
unsigned int
|
||||
hash;
|
||||
};
|
||||
|
||||
struct _WGET_HASHMAP {
|
||||
unsigned int
|
||||
(*hash)(const void *); // hash function
|
||||
int
|
||||
(*cmp)(const void *, const void *); // compare function
|
||||
ENTRY
|
||||
**entry; // pointer to array of pointers to entries
|
||||
int
|
||||
max, // allocated entries
|
||||
cur, // number of entries in use
|
||||
off, // resize strategy: >0: resize = max + off, <0: resize = -off * max
|
||||
threshold; // resize when max reaches threshold
|
||||
float
|
||||
factor;
|
||||
};
|
||||
|
||||
// create hashmap with initial size <max>
|
||||
// hashmap growth is specified by off:
|
||||
// positive values: increase hashmap by <off> entries on each resize
|
||||
// negative values: increase hashmap by *<-off>, e.g. -2 doubles the size on each resize
|
||||
// cmp: comparison function for finding
|
||||
// the hashmap plus shallow content is freed by hashmap_free()
|
||||
|
||||
WGET_HASHMAP *wget_hashmap_create(int max, int off, unsigned int (*hash)(const void *), int (*cmp)(const void *, const void *))
|
||||
{
|
||||
WGET_HASHMAP *h = xmalloc(sizeof(WGET_HASHMAP));
|
||||
|
||||
h->entry = xcalloc(max, sizeof(ENTRY *));
|
||||
h->max = max;
|
||||
h->cur = 0;
|
||||
h->off = off;
|
||||
h->hash = hash;
|
||||
h->cmp = cmp;
|
||||
h->factor = 0.75;
|
||||
h->threshold = (int)(max * h->factor);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline ENTRY * G_GNUC_WGET_NONNULL_ALL hashmap_find_entry(const WGET_HASHMAP *h, const char *key, unsigned int hash, int pos)
|
||||
{
|
||||
ENTRY *e;
|
||||
|
||||
// info_printf("find %s: pos=%d cur=%d, max=%d hash=%08x\n",key,pos,h->cur,h->max,hash);
|
||||
for (e = h->entry[pos]; e; e = e->next) {
|
||||
if (hash == e->hash && (key == e->key || !h->cmp(key, e->key))) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
// if (h->entry[pos])
|
||||
// info_printf("collision on %s\n", key);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void G_GNUC_WGET_NONNULL_ALL hashmap_free_entry(ENTRY **e)
|
||||
{
|
||||
if (*e) {
|
||||
xfree((*e)->value);
|
||||
xfree((*e)->key);
|
||||
xfree(*e);
|
||||
}
|
||||
}
|
||||
|
||||
static void G_GNUC_WGET_NONNULL_ALL hashmap_rehash(WGET_HASHMAP *h, int newmax, int recalc_hash)
|
||||
{
|
||||
ENTRY **new_entry, *entry, *next;
|
||||
int it, pos, cur = h->cur;
|
||||
|
||||
if (cur) {
|
||||
new_entry = xcalloc(newmax, sizeof(ENTRY *));
|
||||
|
||||
for (it = 0; it < h->max && cur; it++) {
|
||||
for (entry = h->entry[it]; entry; entry = next) {
|
||||
next = entry->next;
|
||||
|
||||
// now move entry from 'h' to 'new_hashmap'
|
||||
if (recalc_hash)
|
||||
entry->hash = h->hash(entry->key);
|
||||
pos = entry->hash % newmax;
|
||||
entry->next = new_entry[pos];
|
||||
new_entry[pos] = entry;
|
||||
|
||||
cur--;
|
||||
}
|
||||
}
|
||||
|
||||
xfree(h->entry);
|
||||
h->entry = new_entry;
|
||||
h->max = newmax;
|
||||
h->threshold = (int)(newmax * h->factor);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void G_GNUC_WGET_NONNULL((1,3)) hashmap_new_entry(WGET_HASHMAP *h, unsigned int hash, const char *key, const char *value)
|
||||
{
|
||||
ENTRY *entry;
|
||||
int pos = hash % h->max;
|
||||
|
||||
entry = malloc(sizeof(ENTRY));
|
||||
entry->key = (void *)key;
|
||||
entry->value = (void *)value;
|
||||
entry->hash = hash;
|
||||
entry->next = h->entry[pos];
|
||||
h->entry[pos] = entry;
|
||||
|
||||
if (++h->cur >= h->threshold) {
|
||||
if (h->off > 0) {
|
||||
hashmap_rehash(h, h->max + h->off, 0);
|
||||
} else if (h->off<-1) {
|
||||
hashmap_rehash(h, h->max * -h->off, 0);
|
||||
} else {
|
||||
// no resizing occurs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int wget_hashmap_put_noalloc(WGET_HASHMAP *h, const void *key, const void *value)
|
||||
{
|
||||
ENTRY *entry;
|
||||
unsigned int hash = h->hash(key);
|
||||
int pos = hash % h->max;
|
||||
|
||||
if ((entry = hashmap_find_entry(h, key, hash, pos))) {
|
||||
if (entry->key == entry->value) {
|
||||
if (key != value && entry->value != value)
|
||||
entry->value = (void *)value;
|
||||
} else if (entry->value != value) {
|
||||
xfree(entry->value);
|
||||
entry->value = (void *)value;
|
||||
}
|
||||
|
||||
if (entry->key != key)
|
||||
xfree(key);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// a new entry
|
||||
hashmap_new_entry(h, hash, key, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wget_hashmap_put(WGET_HASHMAP *h, const void *key, size_t keysize, const void *value, size_t valuesize)
|
||||
{
|
||||
ENTRY *entry;
|
||||
unsigned int hash = h->hash(key);
|
||||
int pos = hash % h->max;
|
||||
|
||||
if ((entry = hashmap_find_entry(h, key, hash, pos))) {
|
||||
if (entry->key != entry->value)
|
||||
xfree(entry->value);
|
||||
|
||||
entry->value = wget_memdup(value, valuesize);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// a new entry
|
||||
hashmap_new_entry(h, hash, wget_memdup(key, keysize), value ? wget_memdup(value, valuesize) : NULL);
|
||||
|
||||
return 0;
|
||||
// return hashmap_put_noalloc(h, xmemdup(key, keysize), wget_memdup(value, valuesize));
|
||||
}
|
||||
|
||||
int wget_hashmap_put_ident(WGET_HASHMAP *h, const void *key, size_t keysize)
|
||||
{
|
||||
ENTRY *entry;
|
||||
void *keydup;
|
||||
unsigned int hash = h->hash(key);
|
||||
int pos = hash % h->max;
|
||||
|
||||
if ((entry = hashmap_find_entry(h, key, hash, pos))) {
|
||||
if (entry->key != entry->value) {
|
||||
xfree(entry->value);
|
||||
entry->value = entry->key;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// a new entry
|
||||
keydup = wget_memdup(key, keysize);
|
||||
hashmap_new_entry(h, hash, keydup, keydup);
|
||||
|
||||
return 0;
|
||||
|
||||
// if the key is as well the value (e.g. for blacklists)
|
||||
// void *keydup = xmemdup(key, keysize);
|
||||
// return hashmap_put_noalloc(h, keydup, keydup);
|
||||
}
|
||||
|
||||
int wget_hashmap_put_ident_noalloc(WGET_HASHMAP *h, const void *key)
|
||||
{
|
||||
// if the key is as well the value (e.g. for blacklists)
|
||||
return wget_hashmap_put_noalloc(h, key, key);
|
||||
}
|
||||
|
||||
void *wget_hashmap_get(const WGET_HASHMAP *h, const void *key)
|
||||
{
|
||||
ENTRY *entry;
|
||||
unsigned int hash = h->hash(key);
|
||||
int pos = hash % h->max;
|
||||
|
||||
if ((entry = hashmap_find_entry(h, key, hash, pos)))
|
||||
return entry->value;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void G_GNUC_WGET_NONNULL_ALL hashmap_remove_entry(WGET_HASHMAP *h, const char *key, int free_kv)
|
||||
{
|
||||
ENTRY *e, *next, *prev = NULL;
|
||||
unsigned int hash = h->hash(key);
|
||||
int pos = hash % h->max;
|
||||
|
||||
for (e = h->entry[pos]; e; prev = e, e = next) {
|
||||
next = e->next;
|
||||
|
||||
if (hash == e->hash && (key == e->key || !h->cmp(key, e->key))) {
|
||||
if (prev)
|
||||
prev->next = next;
|
||||
else
|
||||
h->entry[pos] = next;
|
||||
|
||||
if (free_kv) {
|
||||
if (e->key == e->value) {
|
||||
// special case: key/value identity
|
||||
xfree(e->key);
|
||||
e->value = NULL;
|
||||
} else {
|
||||
xfree(e->key);
|
||||
xfree(e->value);
|
||||
}
|
||||
}
|
||||
xfree(e);
|
||||
|
||||
h->cur--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void wget_hashmap_remove(WGET_HASHMAP *h, const void *key)
|
||||
{
|
||||
if (h)
|
||||
hashmap_remove_entry(h, key, 1);
|
||||
}
|
||||
|
||||
void wget_hashmap_remove_nofree(WGET_HASHMAP *h, const void *key)
|
||||
{
|
||||
if (h)
|
||||
hashmap_remove_entry(h, key, 0);
|
||||
}
|
||||
|
||||
void wget_hashmap_free(WGET_HASHMAP **h)
|
||||
{
|
||||
if (h && *h) {
|
||||
wget_hashmap_clear(*h);
|
||||
xfree((*h)->entry);
|
||||
xfree(*h);
|
||||
}
|
||||
}
|
||||
|
||||
void wget_hashmap_clear(WGET_HASHMAP *h)
|
||||
{
|
||||
if (h) {
|
||||
ENTRY *entry, *next;
|
||||
int it, cur = h->cur;
|
||||
|
||||
for (it = 0; it < h->max && cur; it++) {
|
||||
for (entry = h->entry[it]; entry; entry = next) {
|
||||
next = entry->next;
|
||||
if (entry->key == entry->value) {
|
||||
// special case: key/value identity
|
||||
xfree(entry->value);
|
||||
entry->key = NULL;
|
||||
} else {
|
||||
xfree(entry->value);
|
||||
xfree(entry->key);
|
||||
}
|
||||
xfree(entry);
|
||||
cur--;
|
||||
}
|
||||
h->entry[it] = NULL;
|
||||
}
|
||||
h->cur = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int wget_hashmap_size(const WGET_HASHMAP *h)
|
||||
{
|
||||
return h ? h->cur : 0;
|
||||
}
|
||||
|
||||
int wget_hashmap_browse(const WGET_HASHMAP *h, int (*browse)(const void *key, const void *value))
|
||||
{
|
||||
if (h) {
|
||||
ENTRY *entry;
|
||||
int it, ret, cur = h->cur;
|
||||
|
||||
for (it = 0; it < h->max && cur; it++) {
|
||||
for (entry = h->entry[it]; entry; entry = entry->next) {
|
||||
if ((ret = browse(entry->key, entry->value)) != 0)
|
||||
return ret;
|
||||
cur--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wget_hashmap_setcmpfunc(WGET_HASHMAP *h, int (*cmp)(const void *key1, const void *key2))
|
||||
{
|
||||
if (h)
|
||||
h->cmp = cmp;
|
||||
}
|
||||
|
||||
void wget_hashmap_sethashfunc(WGET_HASHMAP *h, unsigned int (*hash)(const void *key))
|
||||
{
|
||||
if (h) {
|
||||
h->hash = hash;
|
||||
|
||||
hashmap_rehash(h, h->max, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void wget_hashmap_setloadfactor(WGET_HASHMAP *h, float factor)
|
||||
{
|
||||
if (h) {
|
||||
h->factor = factor;
|
||||
h->threshold = (int)(h->max * h->factor);
|
||||
// rehashing occurs earliest on next put()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user