1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

st: test packed-to-unpacked transitions during iteration

The st_foreach and st_foreach_check functions support transitioning
from a packed to an unpacked state during iteration.  However, this
functionality did not get exercised by the current test suite until
now.  This should help us prevent breakage when making modifications
to st.

* ext/-test-/st/foreach/extconf.rb: new file
* ext/-test-/st/foreach/foreach.c: ditto
* test/-ext-/st/test_foreach.rb: ditto
  [Feature #10321]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47856 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
normal 2014-10-09 07:16:19 +00:00
parent 4adfbab35c
commit f8b219e4d6
4 changed files with 198 additions and 0 deletions

View file

@ -1,3 +1,10 @@
Thu Oct 9 16:15:26 2014 Eric Wong <e@80x24.org>
* ext/-test-/st/foreach/extconf.rb: new file
* ext/-test-/st/foreach/foreach.c: ditto
* test/-ext-/st/test_foreach.rb: ditto
[Feature #10321]
Thu Oct 9 12:40:28 2014 Eric Wong <e@80x24.org>
* benchmark/bm_hash_aref_sym*.rb: force static symbols

View file

@ -0,0 +1 @@
create_makefile("-test-/st/foreach")

View file

@ -0,0 +1,175 @@
#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->entries_packed) 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->entries_packed) rb_bug("should be unpacked\n");
}
if (key != c->nr) {
rb_bug("unexpected key: %lu (expected %lu)\n", key, c->nr);
}
if (val != c->nr) {
rb_bug("unexpected val: %lu (expected %lu)\n", val, 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: %lu (expected 0)", 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->entries_packed) 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: %lu (expected 1)\n", c.nr);
}
}
else if (c.nr != expect_size) {
rb_bug("mismatched iteration: %lu (expected %lu)\n",
c.nr, expect_size);
}
if (tbl->entries_packed) 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: %lu (expected 0)", 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->entries_packed) 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: %lu (expected 1)\n", c.nr);
}
}
else if (c.nr != expect_size) {
rb_bug("mismatched iteration: %lu (expected %lu)\n",
c.nr, expect_size);
}
if (tbl->entries_packed) 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);
}

View file

@ -0,0 +1,15 @@
require 'test/unit'
require '-test-/st/foreach'
class Test_StForeachUnpack < Test::Unit::TestCase
def test_st_foreach_check_unpack
assert_nil Bug.unp_st_foreach_check(:check), "goto unpacked_continue"
assert_nil Bug.unp_st_foreach_check(:delete1), "goto unpacked"
assert_nil Bug.unp_st_foreach_check(:delete2), "goto deleted"
end
def test_st_foreach_unpack
assert_nil Bug.unp_st_foreach(:unpacked), "goto unpacked"
assert_nil Bug.unp_st_foreach(:unpack_delete), "if (!ptr) return 0"
end
end