summaryrefslogtreecommitdiff
path: root/ext/-test-/st/foreach
diff options
context:
space:
mode:
authornormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-09 07:16:19 +0000
committernormal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-10-09 07:16:19 +0000
commitf8b219e4d66b5b9e24dc14233256e9a57ee0351e (patch)
treede2078dfdd59dc43cf597ee3adbe9e61f0f9f3c6 /ext/-test-/st/foreach
parent4adfbab35c128a0c3b9f1fdb7c0d89ccdaf55351 (diff)
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
Diffstat (limited to 'ext/-test-/st/foreach')
-rw-r--r--ext/-test-/st/foreach/extconf.rb1
-rw-r--r--ext/-test-/st/foreach/foreach.c175
2 files changed, 176 insertions, 0 deletions
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 <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);
+}