Commit 9676edda authored by Yukihiro Matsumoto's avatar Yukihiro Matsumoto

replace st.[ch] to remove SIZEOF_ST_INDEX_T

parent 748d762e
......@@ -922,6 +922,31 @@ enc_name(mrb_state *mrb, mrb_value self)
return mrb_usascii_str_new2(mrb, mrb_enc_name((mrb_encoding*)DATA_PTR(self)));
}
struct fn_arg {
mrb_state *mrb;
int (*func)(ANYARGS);
void *a;
};
static int
fn_i(st_data_t key, st_data_t val, st_data_t arg) {
struct fn_arg *a = (struct fn_arg*)arg;
return (*a->func)(a->mrb, key, val, a->a);
}
static int
st_foreachNew(mrb_state *mrb, st_table *tbl, int (*func)(ANYARGS), void *a)
{
struct fn_arg arg = {
mrb,
func,
a,
};
return st_foreach(tbl, fn_i, (st_data_t)&arg);
}
static int
enc_names_i(mrb_state *mrb, st_data_t name, st_data_t idx, st_data_t args)
{
......
/* This is a public domain general purpose hash table package written by Peter Moore @ UCB. */
/* static char sccsid[] = "@(#) st.c 5.1 89/12/14 Crucible"; */
#define NOT_RUBY
#ifdef NOT_RUBY
#include "regint.h"
#include "st.h"
#else
#include "ruby/ruby.h"
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <string.h>
#include "st.h"
#define ST_DEFAULT_MAX_DENSITY 5
#define ST_DEFAULT_INIT_TABLE_SIZE 11
......@@ -27,15 +21,16 @@
* allocated initially
*
*/
static const struct st_hash_type type_numhash = {
st_numcmp,
st_numhash,
static int numcmp(long, long);
static st_index_t numhash(long);
static struct st_hash_type type_numhash = {
numcmp,
numhash,
};
/* extern int strcmp(const char *, const char *); */
static st_index_t strhash(st_data_t);
static const struct st_hash_type type_strhash = {
static st_index_t strhash(const char *);
static struct st_hash_type type_strhash = {
strcmp,
strhash,
};
......@@ -51,18 +46,14 @@ static void rehash(st_table *);
#ifdef RUBY
#define malloc xmalloc
#define calloc xcalloc
#define free(x) xfree(x)
#endif
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
#define alloc(type) (type*)malloc((size_t)sizeof(type))
#define alloc(type) (type*)malloc((unsigned)sizeof(type))
#define Calloc(n,s) (char*)calloc((n),(s))
#define EQUAL(table,x,y) ((x)==(y) || (*table->type->compare)((x),(y)) == 0)
/* remove cast to unsigned int in the future */
#define do_hash(key,table) (unsigned int)(st_index_t)(*(table)->type->hash)((key))
#define do_hash(key,table) (unsigned int)(*(table)->type->hash)((key))
#define do_hash_bin(key,table) (do_hash(key, table)%(table)->num_bins)
/*
......@@ -74,7 +65,7 @@ static void rehash(st_table *);
/*
Table of prime numbers 2^n+a, 2<=n<=30.
*/
static const unsigned int primes[] = {
static long primes[] = {
8 + 3,
16 + 3,
32 + 5,
......@@ -106,27 +97,32 @@ static const unsigned int primes[] = {
0
};
static st_index_t
new_size(st_index_t size)
static int
new_size(int size)
{
int i;
st_index_t newsize;
#if 0
for (i=3; i<31; i++) {
if ((1<<i) > size) return 1<<i;
}
return -1;
#else
int newsize;
for (i = 0, newsize = MINSIZE; i < numberof(primes); i++, newsize <<= 1) {
for (i = 0, newsize = MINSIZE;
i < sizeof(primes)/sizeof(primes[0]);
i++, newsize <<= 1)
{
if (newsize > size) return primes[i];
}
/* Ran out of polynomials */
#ifndef NOT_RUBY
rb_raise(rb_eRuntimeError, "st_table too big");
#endif
return -1; /* should raise exception */
#endif
}
#define MAX_PACKED_NUMHASH (ST_DEFAULT_INIT_TABLE_SIZE/2)
st_table*
st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
st_init_table_with_size(const struct st_hash_type *type, int size)
{
st_table *tbl;
......@@ -135,7 +131,6 @@ st_init_table_with_size(const struct st_hash_type *type, st_index_t size)
tbl = alloc(st_table);
tbl->type = type;
tbl->num_entries = 0;
tbl->entries_packed = type == &type_numhash && size/2 <= MAX_PACKED_NUMHASH;
tbl->num_bins = size;
tbl->bins = (st_table_entry **)Calloc(size, sizeof(st_table_entry*));
tbl->head = 0;
......@@ -157,7 +152,7 @@ st_init_numtable(void)
}
st_table*
st_init_numtable_with_size(st_index_t size)
st_init_numtable_with_size(int size)
{
return st_init_table_with_size(&type_numhash, size);
}
......@@ -169,7 +164,7 @@ st_init_strtable(void)
}
st_table*
st_init_strtable_with_size(st_index_t size)
st_init_strtable_with_size(int size)
{
return st_init_table_with_size(&type_strhash, size);
}
......@@ -192,11 +187,6 @@ st_clear(st_table *table)
register st_table_entry *ptr, *next;
st_index_t i;
if (table->entries_packed) {
table->num_entries = 0;
return;
}
for(i = 0; i < table->num_bins; i++) {
ptr = table->bins[i];
table->bins[i] = 0;
......@@ -219,29 +209,13 @@ st_free_table(st_table *table)
free(table);
}
size_t
st_memsize(const st_table *table)
{
if (table->entries_packed) {
return table->num_bins * sizeof (void *) + sizeof(st_table);
}
else {
return table->num_entries * sizeof(struct st_table_entry) + table->num_bins * sizeof (void *) + sizeof(st_table);
}
}
#define PTR_NOT_EQUAL(table, ptr, hash_val, key) \
((ptr) != 0 && (ptr->hash != (hash_val) || !EQUAL((table), (key), (ptr)->key)))
#define COLLISION
#define FOUND_ENTRY
#define FIND_ENTRY(table, ptr, hash_val, bin_pos) do {\
bin_pos = hash_val%(table)->num_bins;\
ptr = (table)->bins[bin_pos];\
FOUND_ENTRY;\
if (PTR_NOT_EQUAL(table, ptr, hash_val, key)) {\
COLLISION;\
while (PTR_NOT_EQUAL(table, ptr->next, hash_val, key)) {\
ptr = ptr->next;\
}\
......@@ -249,25 +223,12 @@ st_memsize(const st_table *table)
}\
} while (0)
#define collision_check 0
int
st_lookup(st_table *table, register st_data_t key, st_data_t *value)
st_lookup(st_table *table, st_data_t key, st_data_t *value)
{
st_index_t hash_val, bin_pos;
unsigned int hash_val, bin_pos;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
if (value !=0) *value = (st_data_t)table->bins[i*2+1];
return 1;
}
}
return 0;
}
hash_val = do_hash(key, table);
FIND_ENTRY(table, ptr, hash_val, bin_pos);
......@@ -280,46 +241,10 @@ st_lookup(st_table *table, register st_data_t key, st_data_t *value)
}
}
int
st_get_key(st_table *table, register st_data_t key, st_data_t *result)
{
st_index_t hash_val, bin_pos;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
if (result !=0) *result = (st_data_t)table->bins[i*2];
return 1;
}
}
return 0;
}
hash_val = do_hash(key, table);
FIND_ENTRY(table, ptr, hash_val, bin_pos);
if (ptr == 0) {
return 0;
}
else {
if (result != 0) *result = ptr->key;
return 1;
}
}
#undef collision_check
#define collision_check 1
#define MORE_PACKABLE_P(table) \
((st_index_t)((table)->num_entries+1) * 2 <= (table)->num_bins && \
(table)->num_entries+1 <= MAX_PACKED_NUMHASH)
#define ADD_DIRECT(table, key, value, hash_val, bin_pos)\
do {\
st_table_entry *entry;\
if (table->num_entries > ST_DEFAULT_MAX_DENSITY * table->num_bins) {\
if (table->num_entries/(table->num_bins) > ST_DEFAULT_MAX_DENSITY) {\
rehash(table);\
bin_pos = hash_val % table->num_bins;\
}\
......@@ -343,49 +268,12 @@ do {\
table->num_entries++;\
} while (0)
static void
unpack_entries(register st_table *table)
{
st_index_t i;
struct st_table_entry *packed_bins[MAX_PACKED_NUMHASH*2];
st_table tmp_table = *table;
memcpy(packed_bins, table->bins, sizeof(struct st_table_entry *) * table->num_entries*2);
table->bins = packed_bins;
tmp_table.entries_packed = 0;
tmp_table.num_entries = 0;
memset(tmp_table.bins, 0, sizeof(struct st_table_entry *) * tmp_table.num_bins);
for (i = 0; i < table->num_entries; i++) {
st_insert(&tmp_table, (st_data_t)packed_bins[i*2], (st_data_t)packed_bins[i*2+1]);
}
*table = tmp_table;
}
int
st_insert(register st_table *table, register st_data_t key, st_data_t value)
st_insert(st_table *table, st_data_t key, st_data_t value)
{
st_index_t hash_val, bin_pos;
unsigned int hash_val, bin_pos;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
table->bins[i*2+1] = (struct st_table_entry*)value;
return 1;
}
}
if (MORE_PACKABLE_P(table)) {
i = table->num_entries++;
table->bins[i*2] = (struct st_table_entry*)key;
table->bins[i*2+1] = (struct st_table_entry*)value;
return 0;
}
else {
unpack_entries(table);
}
}
hash_val = do_hash(key, table);
FIND_ENTRY(table, ptr, hash_val, bin_pos);
......@@ -399,63 +287,10 @@ st_insert(register st_table *table, register st_data_t key, st_data_t value)
}
}
int
st_insert2(register st_table *table, register st_data_t key, st_data_t value,
st_data_t (*func)(st_data_t))
{
st_index_t hash_val, bin_pos;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == key) {
table->bins[i*2+1] = (struct st_table_entry*)value;
return 1;
}
}
if (MORE_PACKABLE_P(table)) {
i = table->num_entries++;
table->bins[i*2] = (struct st_table_entry*)key;
table->bins[i*2+1] = (struct st_table_entry*)value;
return 0;
}
else {
unpack_entries(table);
}
}
hash_val = do_hash(key, table);
FIND_ENTRY(table, ptr, hash_val, bin_pos);
if (ptr == 0) {
key = (*func)(key);
ADD_DIRECT(table, key, value, hash_val, bin_pos);
return 0;
}
else {
ptr->record = value;
return 1;
}
}
void
st_add_direct(st_table *table, st_data_t key, st_data_t value)
{
st_index_t hash_val, bin_pos;
if (table->entries_packed) {
int i;
if (MORE_PACKABLE_P(table)) {
i = table->num_entries++;
table->bins[i*2] = (struct st_table_entry*)key;
table->bins[i*2+1] = (struct st_table_entry*)value;
return;
}
else {
unpack_entries(table);
}
}
unsigned int hash_val, bin_pos;
hash_val = do_hash(key, table);
bin_pos = hash_val % table->num_bins;
......@@ -470,7 +305,7 @@ rehash(register st_table *table)
new_num_bins = new_size(table->num_bins+1);
new_bins = (st_table_entry**)
xrealloc(table->bins, new_num_bins * sizeof(st_table_entry*));
realloc(table->bins, new_num_bins * sizeof(st_table_entry*));
for (i = 0; i < new_num_bins; ++i) new_bins[i] = 0;
table->num_bins = new_num_bins;
table->bins = new_bins;
......@@ -506,11 +341,6 @@ st_copy(st_table *old_table)
return 0;
}
if (old_table->entries_packed) {
memcpy(new_table->bins, old_table->bins, sizeof(struct st_table_entry *) * old_table->num_bins);
return new_table;
}
if ((ptr = old_table->head) != 0) {
prev = 0;
tail = &new_table->head;
......@@ -557,23 +387,7 @@ st_delete(register st_table *table, register st_data_t *key, st_data_t *value)
st_table_entry **prev;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == *key) {
if (value != 0) *value = (st_data_t)table->bins[i*2+1];
table->num_entries--;
memmove(&table->bins[i*2], &table->bins[(i+1)*2],
sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
return 1;
}
}
if (value != 0) *value = 0;
return 0;
}
hash_val = do_hash_bin(*key, table);
for (prev = &table->bins[hash_val]; (ptr = *prev) != 0; prev = &ptr->next) {
if (EQUAL(table, *key, ptr->key)) {
*prev = ptr->next;
......@@ -589,78 +403,6 @@ st_delete(register st_table *table, register st_data_t *key, st_data_t *value)
return 0;
}
int
st_delete_safe(register st_table *table, register st_data_t *key, st_data_t *value, st_data_t never)
{
st_index_t hash_val;
register st_table_entry *ptr;
if (table->entries_packed) {
st_index_t i;
for (i = 0; i < table->num_entries; i++) {
if ((st_data_t)table->bins[i*2] == *key) {
if (value != 0) *value = (st_data_t)table->bins[i*2+1];
table->bins[i*2] = (void *)never;
return 1;
}
}
if (value != 0) *value = 0;
return 0;
}
hash_val = do_hash_bin(*key, table);
ptr = table->bins[hash_val];
for (; ptr != 0; ptr = ptr->next) {
if ((ptr->key != never) && EQUAL(table, ptr->key, *key)) {
REMOVE_ENTRY(table, ptr);
*key = ptr->key;
if (value != 0) *value = ptr->record;
ptr->key = ptr->record = never;
return 1;
}
}
if (value != 0) *value = 0;
return 0;
}
void
st_cleanup_safe(st_table *table, st_data_t never)
{
st_table_entry *ptr, **last, *tmp;
st_index_t i;
if (table->entries_packed) {
st_index_t i = 0, j = 0;
while ((st_data_t)table->bins[i*2] != never) {
if (i++ == table->num_entries) return;
}
for (j = i; ++i < table->num_entries;) {
if ((st_data_t)table->bins[i*2] == never) continue;
table->bins[j*2] = table->bins[i*2];
table->bins[j*2+1] = table->bins[i*2+1];
j++;
}
table->num_entries = j;
return;
}
for (i = 0; i < table->num_bins; i++) {
ptr = *(last = &table->bins[i]);
while (ptr != 0) {
if (ptr->key == never) {
tmp = ptr;
*last = ptr = ptr->next;
free(tmp);
}
else {
ptr = *(last = &ptr->next);
}
}
}
}
int
st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
{
......@@ -668,40 +410,6 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
enum st_retval retval;
st_index_t i;
if (table->entries_packed) {
for (i = 0; i < table->num_entries; i++) {
st_index_t j;
st_data_t key, val;
key = (st_data_t)table->bins[i*2];
val = (st_data_t)table->bins[i*2+1];
retval = (*func)(key, val, arg);
switch (retval) {
case ST_CHECK: /* check if hash is modified during iteration */
for (j = 0; j < table->num_entries; j++) {
if ((st_data_t)table->bins[j*2] == key)
break;
}
if (j == table->num_entries) {
/* call func with error notice */
retval = (*func)(0, 0, arg, 1);
return 1;
}
/* fall through */
case ST_CONTINUE:
break;
case ST_STOP:
return 0;
case ST_DELETE:
table->num_entries--;
memmove(&table->bins[i*2], &table->bins[(i+1)*2],
sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
i--;
break;
}
}
return 0;
}
if ((ptr = table->head) != 0) {
do {
i = ptr->hash % table->num_bins;
......@@ -716,6 +424,7 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
}
}
/* fall through */
default:
case ST_CONTINUE:
ptr = ptr->fore;
break;
......@@ -740,466 +449,46 @@ st_foreach(st_table *table, int (*func)(ANYARGS), st_data_t arg)
return 0;
}
typedef int st_foreach_func(mrb_sym, void*, void *);
struct foreach_safe_arg {
st_table *tbl;
st_foreach_func *func;
void *arg;
};
static int
foreach_safe_i(mrb_state *mrb, mrb_sym key, void* value, struct foreach_safe_arg *arg)
{
int status;
if (key == 0xffffffff/*key == Qundef*/) return ST_CONTINUE;
status = (*arg->func)(key, value, arg->arg);
if (status == ST_CONTINUE) {
return ST_CHECK;
}
return status;
}
void
st_foreach_safe(mrb_state *mrb, void *table, int (*func)(ANYARGS), void* a)
{
struct foreach_safe_arg arg;
arg.tbl = table;
arg.func = (st_foreach_func *)func;
arg.arg = a;
if (st_foreach(table, foreach_safe_i, (st_data_t)&arg)) {
mrb_raise(mrb, mrb->eRuntimeError_class, "hash modified during iteration");
}
}
int
st_foreachNew(mrb_state *mrb, st_table *table, int (*func)(ANYARGS), void* arg)
{
st_table_entry *ptr, **last, *tmp;
enum st_retval retval;
st_index_t i;
if (table->entries_packed) {
for (i = 0; i < table->num_entries; i++) {
st_index_t j;
st_data_t key, val;
key = (st_data_t)table->bins[i*2];
val = (st_data_t)table->bins[i*2+1];
retval = (*func)(mrb, key, val, arg);
switch (retval) {
case ST_CHECK: /* check if hash is modified during iteration */
for (j = 0; j < table->num_entries; j++) {
if ((st_data_t)table->bins[j*2] == key)
break;
}
if (j == table->num_entries) {
/* call func with error notice */
retval = (*func)(0, 0, arg, 1);
return 1;
}
/* fall through */
case ST_CONTINUE:
break;
case ST_STOP:
return 0;
case ST_DELETE:
table->num_entries--;
memmove(&table->bins[i*2], &table->bins[(i+1)*2],
sizeof(struct st_table_entry*) * 2*(table->num_entries-i));
i--;
break;
}
}
return 0;
}
if ((ptr = table->head) != 0) {
do {
i = ptr->hash % table->num_bins;
retval = (*func)(mrb, ptr->key, ptr->record, arg);
switch (retval) {
case ST_CHECK: /* check if hash is modified during iteration */
for (tmp = table->bins[i]; tmp != ptr; tmp = tmp->next) {
if (!tmp) {
/* call func with error notice */
retval = (*func)(0, 0, arg, 1);
return 1;
}
}
/* fall through */
case ST_CONTINUE:
ptr = ptr->fore;
break;
case ST_STOP:
return 0;
case ST_DELETE:
last = &table->bins[ptr->hash % table->num_bins];
for (; (tmp = *last) != 0; last = &tmp->next) {
if (ptr == tmp) {
tmp = ptr->fore;
*last = ptr->next;
REMOVE_ENTRY(table, ptr);
free(ptr);
if (ptr == tmp) return 0;
ptr = tmp;
break;
}
}
}
} while (ptr && table->head);
}
return 0;
}
/*
* hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code
*
* @(#) $Hash32: Revision: 1.1 $
* @(#) $Hash32: Id: hash_32a.c,v 1.1 2003/10/03 20:38:53 chongo Exp $
* @(#) $Hash32: Source: /usr/local/src/cmd/fnv/RCS/hash_32a.c,v $
*
***
*
* Fowler/Noll/Vo hash
*
* The basis of this hash algorithm was taken from an idea sent
* as reviewer comments to the IEEE POSIX P1003.2 committee by:
*
* Phong Vo (http://www.research.att.com/info/kpv/)
* Glenn Fowler (http://www.research.att.com/~gsf/)
*
* In a subsequent ballot round:
*
* Landon Curt Noll (http://www.isthe.com/chongo/)
*
* improved on their algorithm. Some people tried this hash
* and found that it worked rather well. In an EMail message
* to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
*
* FNV hashes are designed to be fast while maintaining a low
* collision rate. The FNV speed allows one to quickly hash lots
* of data while maintaining a reasonable collision rate. See:
*
* http://www.isthe.com/chongo/tech/comp/fnv/index.html
*
* for more details as well as other forms of the FNV hash.
***
*
* To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the
* Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str().
*
***
*
* Please do not copyright this code. This code is in the public domain.
*
* LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
* EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
* USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*
* By:
* chongo <Landon Curt Noll> /\oo/\
* http://www.isthe.com/chongo/
*
* Share and Enjoy! :-)
*/
/*
* 32 bit FNV-1 and FNV-1a non-zero initial basis
*
* The FNV-1 initial basis is the FNV-0 hash of the following 32 octets:
*
* chongo <Landon Curt Noll> /\../\
*
* NOTE: The \'s above are not back-slashing escape characters.
* They are literal ASCII backslash 0x5c characters.
*
* NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition.
*/
#define FNV1_32A_INIT 0x811c9dc5
/*
* 32 bit magic FNV-1a prime
*/
#define FNV_32_PRIME 0x01000193
#ifdef ST_USE_FNV1
static st_index_t
strhash(st_data_t arg)
strhash(const char *string)
{
register const char *string = (const char *)arg;
register st_index_t hval = FNV1_32A_INIT;
register int c;
/*
* FNV-1a hash each octet in the buffer
*/
while (*string) {
/* xor the bottom with the current octet */
hval ^= (unsigned int)*string++;
#ifdef HASH_ELFHASH
register unsigned int h = 0, g;
/* multiply by the 32 bit FNV magic prime mod 2^32 */
hval *= FNV_32_PRIME;
while ((c = *string++) != '\0') {
h = ( h << 4 ) + c;
if ( g = h & 0xF0000000 )
h ^= g >> 24;
h &= ~g;
}
return hval;
}
#else
#ifndef UNALIGNED_WORD_ACCESS
# if defined __i386__ || defined _M_IX86
# define UNALIGNED_WORD_ACCESS 1
# endif
#endif
#ifndef UNALIGNED_WORD_ACCESS
# define UNALIGNED_WORD_ACCESS 0
#endif
/* MurmurHash described in http://murmurhash.googlepages.com/ */
#ifndef MURMUR
#define MURMUR 2
#endif
#if MURMUR == 1
#define MurmurMagic 0xc6a4a793
#elif MURMUR == 2
#if SIZEOF_ST_INDEX_T > 4
#define MurmurMagic 0xc6a4a7935bd1e995
#else
#define MurmurMagic 0x5bd1e995
#endif
#endif
static inline st_index_t
murmur(st_index_t h, st_index_t k, int r)
{
const st_index_t m = MurmurMagic;
#if MURMUR == 1
h += k;
h *= m;
h ^= h >> r;
#elif MURMUR == 2
k *= m;
k ^= k >> r;
k *= m;
h *= m;
h ^= k;
#endif
return h;
}
static inline st_index_t
murmur_finish(st_index_t h)
{
#if MURMUR == 1
h = murmur(h, 0, 10);
h = murmur(h, 0, 17);
#elif MURMUR == 2
h ^= h >> 13;
h *= MurmurMagic;
h ^= h >> 15;
#endif
return h;
}
#define murmur_step(h, k) murmur(h, k, 16)
#if MURMUR == 1
#define murmur1(h) murmur_step(h, 16)
#else
#define murmur1(h) murmur_step(h, 24)
#endif
st_index_t
st_hash(const void *ptr, size_t len, st_index_t h)
{
const char *data = ptr;
st_index_t t = 0;
h += 0xdeadbeef;
#define data_at(n) (st_index_t)((unsigned char)data[n])
#define UNALIGNED_ADD_4 UNALIGNED_ADD(2); UNALIGNED_ADD(1); UNALIGNED_ADD(0)
#if SIZEOF_ST_INDEX_T > 4
#define UNALIGNED_ADD_8 UNALIGNED_ADD(6); UNALIGNED_ADD(5); UNALIGNED_ADD(4); UNALIGNED_ADD(3); UNALIGNED_ADD_4
#if SIZEOF_ST_INDEX_T > 8
#define UNALIGNED_ADD_16 UNALIGNED_ADD(14); UNALIGNED_ADD(13); UNALIGNED_ADD(12); UNALIGNED_ADD(11); \
UNALIGNED_ADD(10); UNALIGNED_ADD(9); UNALIGNED_ADD(8); UNALIGNED_ADD(7); UNALIGNED_ADD_8
#define UNALIGNED_ADD_ALL UNALIGNED_ADD_16
#endif
#define UNALIGNED_ADD_ALL UNALIGNED_ADD_8
#else
#define UNALIGNED_ADD_ALL UNALIGNED_ADD_4
#endif
if (len >= sizeof(st_index_t)) {
#if !UNALIGNED_WORD_ACCESS
int align = (int)((st_data_t)data % sizeof(st_index_t));
if (align) {
st_index_t d = 0;
int sl, sr, pack;
switch (align) {
#ifdef WORDS_BIGENDIAN
# define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 2)
#else
# define UNALIGNED_ADD(n) case SIZEOF_ST_INDEX_T - (n) - 1: \
t |= data_at(n) << CHAR_BIT*(n)
#endif
UNALIGNED_ADD_ALL;
#undef UNALIGNED_ADD
}
#ifdef WORDS_BIGENDIAN
t >>= (CHAR_BIT * align) - CHAR_BIT;
#else
t <<= (CHAR_BIT * align);
#endif
#elif defined(HASH_PERL)
register int val = 0;
data += sizeof(st_index_t)-align;
len -= sizeof(st_index_t)-align;
sl = CHAR_BIT * (SIZEOF_ST_INDEX_T-align);
sr = CHAR_BIT * align;
while (len >= sizeof(st_index_t)) {
d = *(st_index_t *)data;
#ifdef WORDS_BIGENDIAN
t = (t << sr) | (d >> sl);
#else
t = (t >> sr) | (d << sl);
#endif
h = murmur_step(h, t);
t = d;
data += sizeof(st_index_t);
len -= sizeof(st_index_t);
}
pack = len < (size_t)align ? (int)len : align;
d = 0;
switch (pack) {
#ifdef WORDS_BIGENDIAN
# define UNALIGNED_ADD(n) case (n) + 1: \
d |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
#else
# define UNALIGNED_ADD(n) case (n) + 1: \
d |= data_at(n) << CHAR_BIT*(n)
#endif
UNALIGNED_ADD_ALL;
#undef UNALIGNED_ADD
}
#ifdef WORDS_BIGENDIAN
t = (t << sr) | (d >> sl);
#else
t = (t >> sr) | (d << sl);
#endif
#if MURMUR == 2
if (len < (size_t)align) goto skip_tail;
#endif
h = murmur_step(h, t);
data += pack;
len -= pack;
}
else
#endif
{
do {
h = murmur_step(h, *(st_index_t *)data);
data += sizeof(st_index_t);
len -= sizeof(st_index_t);
} while (len >= sizeof(st_index_t));
}
while ((c = *string++) != '\0') {
val += c;
val += (val << 10);
val ^= (val >> 6);
}
val += (val << 3);
val ^= (val >> 11);
t = 0;
switch (len) {
#ifdef WORDS_BIGENDIAN
# define UNALIGNED_ADD(n) case (n) + 1: \
t |= data_at(n) << CHAR_BIT*(SIZEOF_ST_INDEX_T - (n) - 1)
return val + (val << 15);
#else
# define UNALIGNED_ADD(n) case (n) + 1: \
t |= data_at(n) << CHAR_BIT*(n)
#endif
UNALIGNED_ADD_ALL;
#undef UNALIGNED_ADD
#if MURMUR == 1
h = murmur_step(h, t);
#elif MURMUR == 2
# if !UNALIGNED_WORD_ACCESS
skip_tail:
# endif
h ^= t;
h *= MurmurMagic;
#endif
}
return murmur_finish(h);
}
register int val = 0;
st_index_t
st_hash_uint32(st_index_t h, uint32_t i)
{
return murmur_step(h + i, 16);
}
while ((c = *string++) != '\0') {
val = val*997 + c;
}
st_index_t
st_hash_uint(st_index_t h, st_index_t i)
{
st_index_t v = 0;
h += i;
#ifdef WORDS_BIGENDIAN
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
v = murmur1(v + (h >> 12*8));
#endif
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
v = murmur1(v + (h >> 8*8));
#endif
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
v = murmur1(v + (h >> 4*8));
#endif
#endif
v = murmur1(v + h);
#ifndef WORDS_BIGENDIAN
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 4*8
v = murmur1(v + (h >> 4*8));
#endif
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 8*8
v = murmur1(v + (h >> 8*8));
#endif
#if SIZEOF_ST_INDEX_T*CHAR_BIT > 12*8
v = murmur1(v + (h >> 12*8));
return val + (val>>5);
#endif
#endif
return v;
}
st_index_t
st_hash_end(st_index_t h)
{
h = murmur_step(h, 10);
h = murmur_step(h, 17);
return h;
}
#undef st_hash_start
st_index_t
st_hash_start(st_index_t h)
{
return h;
}
static st_index_t
strhash(st_data_t arg)
{
register const char *string = (const char *)arg;
return st_hash(string, strlen(string), FNV1_32A_INIT);
}
#endif
#define FNV1_32A_INIT 0x811c9dc5
#define FNV_32_PRIME 0x01000193
int
st_strcasecmp(const char *s1, const char *s2)
......@@ -1270,14 +559,38 @@ strcasehash(st_data_t arg)
return hval;
}
int
st_numcmp(st_data_t x, st_data_t y)
static int
numcmp(long x, long y)
{
return x != y;
}
st_index_t
st_numhash(st_data_t n)
static st_index_t
numhash(long n)
{
return n;
}
#if 0
static int
f(st_data_t key, st_data_t val, st_data_t a)
{
printf("tbl=%p key=%s val=%s\n", (st_table*)a, (char*)key, (char*)val);
// return ST_CONTINUE;
}
void
main(int argc, char **argv)
{
return (st_index_t)n;
st_table *tbl = st_init_strtable();
int i;
for (i = 1; i<argc; i+=2) {
st_insert(tbl, (st_data_t)argv[i], (st_data_t)argv[i+1]);
}
st_foreach(tbl, f, (st_data_t)tbl);
st_delete(tbl, (st_data_t*)&argv[1], 0);
st_foreach(tbl, f, (st_data_t)tbl);
}
#endif
......@@ -9,23 +9,8 @@
extern "C" {
#endif
#ifndef RUBY_LIB_PREFIX
#ifdef RUBY_EXTCONF_H
#include RUBY_EXTCONF_H
#endif
#endif
#if defined STDC_HEADERS
#include <stddef.h>
#elif defined HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#include <inttypes.h>
#include <stdint.h>
#ifndef CHAR_BIT
# ifdef HAVE_LIMITS_H
......@@ -35,10 +20,6 @@ extern "C" {
# endif
#endif
#ifndef _
# define _(args) args
#endif
#ifndef ANYARGS
# ifdef __cplusplus
# define ANYARGS ...
......@@ -69,16 +50,10 @@ struct st_hash_type {
st_index_t (*hash)(ANYARGS /*st_data_t*/); /* st_hash_func* */
};
#define ST_INDEX_BITS (sizeof(st_index_t) * CHAR_BIT)
struct st_table {
const struct st_hash_type *type;
st_index_t num_bins;
unsigned int entries_packed : 1;
#ifdef __GNUC__
__extension__
#endif
st_index_t num_entries : ST_INDEX_BITS - 1;
int num_bins;
int num_entries;
struct st_table_entry **bins;
struct st_table_entry *head, *tail;
};
......@@ -88,46 +63,37 @@ struct st_table {
enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK};
st_table *st_init_table(const struct st_hash_type *);
st_table *st_init_table_with_size(const struct st_hash_type *, st_index_t);
st_table *st_init_table_with_size(const struct st_hash_type *, int);
st_table *st_init_numtable(void);
st_table *st_init_numtable_with_size(st_index_t);
st_table *st_init_numtable_with_size(int);
st_table *st_init_strtable(void);
st_table *st_init_strtable_with_size(st_index_t);
st_table *st_init_strtable_with_size(int);
st_table *st_init_strcasetable(void);
st_table *st_init_strcasetable_with_size(st_index_t);
int st_delete(st_table *, st_data_t *, st_data_t *); /* returns 0:notfound 1:deleted */
int st_delete(st_table *, st_data_t *, st_data_t *);
int st_delete_safe(st_table *, st_data_t *, st_data_t *, st_data_t);
int st_insert(st_table *, st_data_t, st_data_t);
int st_insert2(st_table *, st_data_t, st_data_t, st_data_t (*)(st_data_t));
int st_lookup(st_table *, st_data_t, st_data_t *);
int st_get_key(st_table *, st_data_t, st_data_t *);
int st_foreach(st_table *, int (*)(ANYARGS), st_data_t);
int st_foreachNew(mrb_state *mrb, st_table *, int (*)(ANYARGS), void*);
int st_reverse_foreach(st_table *, int (*)(ANYARGS), st_data_t);
void st_add_direct(st_table *, st_data_t, st_data_t);
void st_free_table(st_table *);
void st_cleanup_safe(st_table *, st_data_t);
void st_clear(st_table *);
st_table *st_copy(st_table *);
int st_numcmp(st_data_t, st_data_t);
st_index_t st_numhash(st_data_t);
int st_strcasecmp(const char *s1, const char *s2);
int st_strncasecmp(const char *s1, const char *s2, size_t n);
size_t st_memsize(const st_table *);
st_index_t st_hash(const void *ptr, size_t len, st_index_t h);
st_index_t st_hash_uint32(st_index_t h, uint32_t i);
st_index_t st_hash_uint(st_index_t h, st_index_t i);
st_index_t st_hash_end(st_index_t h);
st_index_t st_hash_start(st_index_t h);
#define st_hash_start(h) ((st_index_t)(h))
int st_strcasecmp(const char *s1, const char *s2);
int st_strncasecmp(const char *s1, const char *s2, size_t n);
#define STRCASECMP(s1, s2) (st_strcasecmp(s1, s2))
#define STRNCASECMP(s1, s2, n) (st_strncasecmp(s1, s2, n))
#define ST_NUMCMP ((int (*)()) 0)
#define ST_NUMHASH ((int (*)()) -2)
#define st_numcmp ST_NUMCMP
#define st_numhash ST_NUMHASH
int st_strhash();
#if defined(__cplusplus)
} /* extern "C" { */
#endif
#endif /* RUBY_ST_H */
#endif /* ST_INCLUDED */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment