1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/ext/-test-/st/foreach/foreach.c
ko1 75775157ea Introduce table improvement by Vladimir Makarov <vmakarov@redhat.com>.
[Feature #12142]
	See header of st.c for improvment details.

	You can see all of code history here:
	<https://github.com/vnmakarov/ruby/tree/hash_tables_with_open_addressing>

	This improvement is discussed at
	<https://bugs.ruby-lang.org/issues/12142>
	with many people, especially with Yura Sokolov.

	* st.c: improve st_table.

	* include/ruby/st.h: ditto.

	* internal.h, numeric.c, hash.c (rb_dbl_long_hash): extract a function.

	* ext/-test-/st/foreach/foreach.c: catch up this change.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@56650 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2016-11-07 00:45:00 +00:00

175 lines
3.9 KiB
C

#include <ruby.h>
#include <ruby/st.h>
static st_data_t expect_size = 32;
struct checker {
st_table *tbl;
st_index_t nr;
VALUE test;
};
static void
force_unpack_check(struct checker *c, st_data_t key, st_data_t val)
{
if (c->nr == 0) {
st_data_t i;
if (c->tbl->bins != NULL) rb_bug("should be packed\n");
/* force unpacking during iteration: */
for (i = 1; i < expect_size; i++)
st_add_direct(c->tbl, i, i);
if (c->tbl->bins == NULL) rb_bug("should be unpacked\n");
}
if (key != c->nr) {
rb_bug("unexpected key: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)key, (VALUE)c->nr);
}
if (val != c->nr) {
rb_bug("unexpected val: %"PRIuVALUE" (expected %"PRIuVALUE")\n", (VALUE)val, (VALUE)c->nr);
}
c->nr++;
}
static int
unp_fec_i(st_data_t key, st_data_t val, st_data_t args, int error)
{
struct checker *c = (struct checker *)args;
if (error) {
if (c->test == ID2SYM(rb_intern("delete2")))
return ST_STOP;
rb_bug("unexpected error");
}
force_unpack_check(c, key, val);
if (c->test == ID2SYM(rb_intern("check"))) {
return ST_CHECK;
}
if (c->test == ID2SYM(rb_intern("delete1"))) {
if (c->nr == 1) return ST_DELETE;
return ST_CHECK;
}
if (c->test == ID2SYM(rb_intern("delete2"))) {
if (c->nr == 1) {
st_data_t k = 0;
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
}
}
return ST_CHECK;
}
rb_raise(rb_eArgError, "unexpected arg: %+"PRIsVALUE, c->test);
}
static VALUE
unp_fec(VALUE self, VALUE test)
{
st_table *tbl = st_init_numtable();
struct checker c;
c.tbl = tbl;
c.nr = 0;
c.test = test;
st_add_direct(tbl, 0, 0);
if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach_check(tbl, unp_fec_i, (st_data_t)&c, -1);
if (c.test == ID2SYM(rb_intern("delete2"))) {
if (c.nr != 1) {
rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE")\n",
(VALUE)c.nr, (VALUE)expect_size);
}
if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
return Qnil;
}
static int
unp_fe_i(st_data_t key, st_data_t val, st_data_t args, int error)
{
struct checker *c = (struct checker *)args;
force_unpack_check(c, key, val);
if (c->test == ID2SYM(rb_intern("unpacked"))) {
return ST_CONTINUE;
}
else if (c->test == ID2SYM(rb_intern("unpack_delete"))) {
if (c->nr == 1) {
st_data_t k = 0;
st_data_t v;
if (!st_delete(c->tbl, &k, &v)) {
rb_bug("failed to delete\n");
}
if (v != 0) {
rb_bug("unexpected value deleted: %"PRIuVALUE" (expected 0)", (VALUE)v);
}
return ST_CONTINUE;
}
rb_bug("should never get here\n");
}
rb_raise(rb_eArgError, "unexpected arg: %+"PRIsVALUE, c->test);
}
static VALUE
unp_fe(VALUE self, VALUE test)
{
st_table *tbl = st_init_numtable();
struct checker c;
c.tbl = tbl;
c.nr = 0;
c.test = test;
st_add_direct(tbl, 0, 0);
if (tbl->bins != NULL) rb_bug("should still be packed\n");
st_foreach(tbl, unp_fe_i, (st_data_t)&c);
if (c.test == ID2SYM(rb_intern("unpack_delete"))) {
if (c.nr != 1) {
rb_bug("mismatched iteration: %"PRIuVALUE" (expected 1)\n", (VALUE)c.nr);
}
}
else if (c.nr != expect_size) {
rb_bug("mismatched iteration: %"PRIuVALUE" (expected %"PRIuVALUE"o)\n",
(VALUE)c.nr, (VALUE)expect_size);
}
if (tbl->bins == NULL) rb_bug("should be unpacked\n");
st_free_table(tbl);
return Qnil;
}
void
Init_foreach(void)
{
VALUE bug = rb_define_module("Bug");
rb_define_singleton_method(bug, "unp_st_foreach_check", unp_fec, 1);
rb_define_singleton_method(bug, "unp_st_foreach", unp_fe, 1);
}