diff --git a/ChangeLog b/ChangeLog index 467be7fbb7..006bbee8d4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Thu Oct 9 16:15:26 2014 Eric Wong + + * 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 * benchmark/bm_hash_aref_sym*.rb: force static symbols diff --git a/ext/-test-/st/foreach/extconf.rb b/ext/-test-/st/foreach/extconf.rb new file mode 100644 index 0000000000..969f386ff9 --- /dev/null +++ b/ext/-test-/st/foreach/extconf.rb @@ -0,0 +1 @@ +create_makefile("-test-/st/foreach") diff --git a/ext/-test-/st/foreach/foreach.c b/ext/-test-/st/foreach/foreach.c new file mode 100644 index 0000000000..d9be603789 --- /dev/null +++ b/ext/-test-/st/foreach/foreach.c @@ -0,0 +1,175 @@ +#include +#include + +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); +} diff --git a/test/-ext-/st/test_foreach.rb b/test/-ext-/st/test_foreach.rb new file mode 100644 index 0000000000..259b0a93b1 --- /dev/null +++ b/test/-ext-/st/test_foreach.rb @@ -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