Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mruby
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
mruby
Commits
9676edda
Commit
9676edda
authored
Apr 21, 2012
by
Yukihiro Matsumoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
replace st.[ch] to remove SIZEOF_ST_INDEX_T
parent
748d762e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
131 additions
and
827 deletions
+131
-827
src/encoding.c
src/encoding.c
+25
-0
src/st.c
src/st.c
+90
-777
src/st.h
src/st.h
+16
-50
No files found.
src/encoding.c
View file @
9676edda
...
...
@@ -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
)
{
...
...
src/st.c
View file @
9676edda
/* 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
in
t
new_size
(
in
t
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
,
in
t
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
(
in
t
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
(
in
t
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
in
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
(
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
in
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
);
...
...
@@ -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
**
)
x
realloc
(
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
ar
g
)
strhash
(
const
char
*
strin
g
)
{
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
src/st.h
View file @
9676edda
...
...
@@ -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
*
,
in
t
);
st_table
*
st_init_numtable
(
void
);
st_table
*
st_init_numtable_with_size
(
st_index_
t
);
st_table
*
st_init_numtable_with_size
(
in
t
);
st_table
*
st_init_strtable
(
void
);
st_table
*
st_init_strtable_with_size
(
st_index_
t
);
st_table
*
st_init_strtable_with_size
(
in
t
);
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
*/
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment