remove old hash.[ch] implementation
Signed-off-by: Karsten Blees <blees@dcon.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:

committed by
Junio C Hamano

parent
419a597f64
commit
efc684245b
@ -1,52 +0,0 @@
|
|||||||
hash API
|
|
||||||
========
|
|
||||||
|
|
||||||
The hash API is a collection of simple hash table functions. Users are expected
|
|
||||||
to implement their own hashing.
|
|
||||||
|
|
||||||
Data Structures
|
|
||||||
---------------
|
|
||||||
|
|
||||||
`struct hash_table`::
|
|
||||||
|
|
||||||
The hash table structure. The `array` member points to the hash table
|
|
||||||
entries. The `size` member counts the total number of valid and invalid
|
|
||||||
entries in the table. The `nr` member keeps track of the number of
|
|
||||||
valid entries.
|
|
||||||
|
|
||||||
`struct hash_table_entry`::
|
|
||||||
|
|
||||||
An opaque structure representing an entry in the hash table. The `hash`
|
|
||||||
member is the entry's hash key and the `ptr` member is the entry's
|
|
||||||
value.
|
|
||||||
|
|
||||||
Functions
|
|
||||||
---------
|
|
||||||
|
|
||||||
`init_hash`::
|
|
||||||
|
|
||||||
Initialize the hash table.
|
|
||||||
|
|
||||||
`free_hash`::
|
|
||||||
|
|
||||||
Release memory associated with the hash table.
|
|
||||||
|
|
||||||
`insert_hash`::
|
|
||||||
|
|
||||||
Insert a pointer into the hash table. If an entry with that hash
|
|
||||||
already exists, a pointer to the existing entry's value is returned.
|
|
||||||
Otherwise NULL is returned. This allows callers to implement
|
|
||||||
chaining, etc.
|
|
||||||
|
|
||||||
`lookup_hash`::
|
|
||||||
|
|
||||||
Lookup an entry in the hash table. If an entry with that hash exists
|
|
||||||
the entry's value is returned. Otherwise NULL is returned.
|
|
||||||
|
|
||||||
`for_each_hash`::
|
|
||||||
|
|
||||||
Call a function for each entry in the hash table. The function is
|
|
||||||
expected to take the entry's value as its only argument and return an
|
|
||||||
int. If the function returns a negative int the loop is aborted
|
|
||||||
immediately. Otherwise, the return value is accumulated and the sum
|
|
||||||
returned upon completion of the loop.
|
|
2
Makefile
2
Makefile
@ -677,7 +677,6 @@ LIB_H += git-compat-util.h
|
|||||||
LIB_H += gpg-interface.h
|
LIB_H += gpg-interface.h
|
||||||
LIB_H += graph.h
|
LIB_H += graph.h
|
||||||
LIB_H += grep.h
|
LIB_H += grep.h
|
||||||
LIB_H += hash.h
|
|
||||||
LIB_H += hashmap.h
|
LIB_H += hashmap.h
|
||||||
LIB_H += help.h
|
LIB_H += help.h
|
||||||
LIB_H += http.h
|
LIB_H += http.h
|
||||||
@ -809,7 +808,6 @@ LIB_OBJS += gettext.o
|
|||||||
LIB_OBJS += gpg-interface.o
|
LIB_OBJS += gpg-interface.o
|
||||||
LIB_OBJS += graph.o
|
LIB_OBJS += graph.o
|
||||||
LIB_OBJS += grep.o
|
LIB_OBJS += grep.o
|
||||||
LIB_OBJS += hash.o
|
|
||||||
LIB_OBJS += hashmap.o
|
LIB_OBJS += hashmap.o
|
||||||
LIB_OBJS += help.o
|
LIB_OBJS += help.o
|
||||||
LIB_OBJS += hex.o
|
LIB_OBJS += hex.o
|
||||||
|
1
cache.h
1
cache.h
@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "git-compat-util.h"
|
#include "git-compat-util.h"
|
||||||
#include "strbuf.h"
|
#include "strbuf.h"
|
||||||
#include "hash.h"
|
|
||||||
#include "hashmap.h"
|
#include "hashmap.h"
|
||||||
#include "advice.h"
|
#include "advice.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
110
hash.c
110
hash.c
@ -1,110 +0,0 @@
|
|||||||
/*
|
|
||||||
* Some generic hashing helpers.
|
|
||||||
*/
|
|
||||||
#include "cache.h"
|
|
||||||
#include "hash.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up a hash entry in the hash table. Return the pointer to
|
|
||||||
* the existing entry, or the empty slot if none existed. The caller
|
|
||||||
* can then look at the (*ptr) to see whether it existed or not.
|
|
||||||
*/
|
|
||||||
static struct hash_table_entry *lookup_hash_entry(unsigned int hash, const struct hash_table *table)
|
|
||||||
{
|
|
||||||
unsigned int size = table->size, nr = hash % size;
|
|
||||||
struct hash_table_entry *array = table->array;
|
|
||||||
|
|
||||||
while (array[nr].ptr) {
|
|
||||||
if (array[nr].hash == hash)
|
|
||||||
break;
|
|
||||||
nr++;
|
|
||||||
if (nr >= size)
|
|
||||||
nr = 0;
|
|
||||||
}
|
|
||||||
return array + nr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert a new hash entry pointer into the table.
|
|
||||||
*
|
|
||||||
* If that hash entry already existed, return the pointer to
|
|
||||||
* the existing entry (and the caller can create a list of the
|
|
||||||
* pointers or do anything else). If it didn't exist, return
|
|
||||||
* NULL (and the caller knows the pointer has been inserted).
|
|
||||||
*/
|
|
||||||
static void **insert_hash_entry(unsigned int hash, void *ptr, struct hash_table *table)
|
|
||||||
{
|
|
||||||
struct hash_table_entry *entry = lookup_hash_entry(hash, table);
|
|
||||||
|
|
||||||
if (!entry->ptr) {
|
|
||||||
entry->ptr = ptr;
|
|
||||||
entry->hash = hash;
|
|
||||||
table->nr++;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return &entry->ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void grow_hash_table(struct hash_table *table)
|
|
||||||
{
|
|
||||||
unsigned int i;
|
|
||||||
unsigned int old_size = table->size, new_size;
|
|
||||||
struct hash_table_entry *old_array = table->array, *new_array;
|
|
||||||
|
|
||||||
new_size = alloc_nr(old_size);
|
|
||||||
new_array = xcalloc(sizeof(struct hash_table_entry), new_size);
|
|
||||||
table->size = new_size;
|
|
||||||
table->array = new_array;
|
|
||||||
table->nr = 0;
|
|
||||||
for (i = 0; i < old_size; i++) {
|
|
||||||
unsigned int hash = old_array[i].hash;
|
|
||||||
void *ptr = old_array[i].ptr;
|
|
||||||
if (ptr)
|
|
||||||
insert_hash_entry(hash, ptr, table);
|
|
||||||
}
|
|
||||||
free(old_array);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *lookup_hash(unsigned int hash, const struct hash_table *table)
|
|
||||||
{
|
|
||||||
if (!table->array)
|
|
||||||
return NULL;
|
|
||||||
return lookup_hash_entry(hash, table)->ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table)
|
|
||||||
{
|
|
||||||
unsigned int nr = table->nr;
|
|
||||||
if (nr >= table->size/2)
|
|
||||||
grow_hash_table(table);
|
|
||||||
return insert_hash_entry(hash, ptr, table);
|
|
||||||
}
|
|
||||||
|
|
||||||
int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data)
|
|
||||||
{
|
|
||||||
int sum = 0;
|
|
||||||
unsigned int i;
|
|
||||||
unsigned int size = table->size;
|
|
||||||
struct hash_table_entry *array = table->array;
|
|
||||||
|
|
||||||
for (i = 0; i < size; i++) {
|
|
||||||
void *ptr = array->ptr;
|
|
||||||
array++;
|
|
||||||
if (ptr) {
|
|
||||||
int val = fn(ptr, data);
|
|
||||||
if (val < 0)
|
|
||||||
return val;
|
|
||||||
sum += val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free_hash(struct hash_table *table)
|
|
||||||
{
|
|
||||||
free(table->array);
|
|
||||||
table->array = NULL;
|
|
||||||
table->size = 0;
|
|
||||||
table->nr = 0;
|
|
||||||
}
|
|
50
hash.h
50
hash.h
@ -1,50 +0,0 @@
|
|||||||
#ifndef HASH_H
|
|
||||||
#define HASH_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* These are some simple generic hash table helper functions.
|
|
||||||
* Not necessarily suitable for all users, but good for things
|
|
||||||
* where you want to just keep track of a list of things, and
|
|
||||||
* have a good hash to use on them.
|
|
||||||
*
|
|
||||||
* It keeps the hash table at roughly 50-75% free, so the memory
|
|
||||||
* cost of the hash table itself is roughly
|
|
||||||
*
|
|
||||||
* 3 * 2*sizeof(void *) * nr_of_objects
|
|
||||||
*
|
|
||||||
* bytes.
|
|
||||||
*
|
|
||||||
* FIXME: on 64-bit architectures, we waste memory. It would be
|
|
||||||
* good to have just 32-bit pointers, requiring a special allocator
|
|
||||||
* for hashed entries or something.
|
|
||||||
*/
|
|
||||||
struct hash_table_entry {
|
|
||||||
unsigned int hash;
|
|
||||||
void *ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hash_table {
|
|
||||||
unsigned int size, nr;
|
|
||||||
struct hash_table_entry *array;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void *lookup_hash(unsigned int hash, const struct hash_table *table);
|
|
||||||
extern void **insert_hash(unsigned int hash, void *ptr, struct hash_table *table);
|
|
||||||
extern int for_each_hash(const struct hash_table *table, int (*fn)(void *, void *), void *data);
|
|
||||||
extern void free_hash(struct hash_table *table);
|
|
||||||
|
|
||||||
static inline void init_hash(struct hash_table *table)
|
|
||||||
{
|
|
||||||
table->size = 0;
|
|
||||||
table->nr = 0;
|
|
||||||
table->array = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void preallocate_hash(struct hash_table *table, unsigned int elts)
|
|
||||||
{
|
|
||||||
assert(table->size == 0 && table->nr == 0 && table->array == NULL);
|
|
||||||
table->size = elts * 2;
|
|
||||||
table->array = xcalloc(sizeof(struct hash_table_entry), table->size);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -126,85 +126,6 @@ static void perf_hashmap(unsigned int method, unsigned int rounds)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hash_entry
|
|
||||||
{
|
|
||||||
struct hash_entry *next;
|
|
||||||
char key[FLEX_ARRAY];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Test performance of hash.[ch]
|
|
||||||
* Usage: time echo "perfhash method rounds" | test-hashmap
|
|
||||||
*/
|
|
||||||
static void perf_hash(unsigned int method, unsigned int rounds)
|
|
||||||
{
|
|
||||||
struct hash_table map;
|
|
||||||
char buf[16];
|
|
||||||
struct hash_entry **entries, **res, *entry;
|
|
||||||
unsigned int *hashes;
|
|
||||||
unsigned int i, j;
|
|
||||||
|
|
||||||
entries = malloc(TEST_SIZE * sizeof(struct hash_entry *));
|
|
||||||
hashes = malloc(TEST_SIZE * sizeof(int));
|
|
||||||
for (i = 0; i < TEST_SIZE; i++) {
|
|
||||||
snprintf(buf, sizeof(buf), "%i", i);
|
|
||||||
entries[i] = malloc(sizeof(struct hash_entry) + strlen(buf) + 1);
|
|
||||||
strcpy(entries[i]->key, buf);
|
|
||||||
hashes[i] = hash(method, i, entries[i]->key);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method & TEST_ADD) {
|
|
||||||
/* test adding to the map */
|
|
||||||
for (j = 0; j < rounds; j++) {
|
|
||||||
init_hash(&map);
|
|
||||||
|
|
||||||
/* add entries */
|
|
||||||
for (i = 0; i < TEST_SIZE; i++) {
|
|
||||||
res = (struct hash_entry **) insert_hash(
|
|
||||||
hashes[i], entries[i], &map);
|
|
||||||
if (res) {
|
|
||||||
entries[i]->next = *res;
|
|
||||||
*res = entries[i];
|
|
||||||
} else {
|
|
||||||
entries[i]->next = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_hash(&map);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* test map lookups */
|
|
||||||
init_hash(&map);
|
|
||||||
|
|
||||||
/* fill the map (sparsely if specified) */
|
|
||||||
j = (method & TEST_SPARSE) ? TEST_SIZE / 10 : TEST_SIZE;
|
|
||||||
for (i = 0; i < j; i++) {
|
|
||||||
res = (struct hash_entry **) insert_hash(hashes[i],
|
|
||||||
entries[i], &map);
|
|
||||||
if (res) {
|
|
||||||
entries[i]->next = *res;
|
|
||||||
*res = entries[i];
|
|
||||||
} else {
|
|
||||||
entries[i]->next = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (j = 0; j < rounds; j++) {
|
|
||||||
for (i = 0; i < TEST_SIZE; i++) {
|
|
||||||
entry = lookup_hash(hashes[i], &map);
|
|
||||||
while (entry) {
|
|
||||||
if (!strcmp(entries[i]->key, entry->key))
|
|
||||||
break;
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free_hash(&map);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DELIM " \t\r\n"
|
#define DELIM " \t\r\n"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -218,7 +139,6 @@ static void perf_hash(unsigned int method, unsigned int rounds)
|
|||||||
* size -> tablesize numentries
|
* size -> tablesize numentries
|
||||||
*
|
*
|
||||||
* perfhashmap method rounds -> test hashmap.[ch] performance
|
* perfhashmap method rounds -> test hashmap.[ch] performance
|
||||||
* perfhash method rounds -> test hash.[ch] performance
|
|
||||||
*/
|
*/
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -324,10 +244,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
perf_hashmap(atoi(p1), atoi(p2));
|
perf_hashmap(atoi(p1), atoi(p2));
|
||||||
|
|
||||||
} else if (!strcmp("perfhash", cmd) && l1 && l2) {
|
|
||||||
|
|
||||||
perf_hash(atoi(p1), atoi(p2));
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
printf("Unknown command %s\n", cmd);
|
printf("Unknown command %s\n", cmd);
|
||||||
|
Reference in New Issue
Block a user