From 2a2ffe7f7dc5202b29a1f59ab5e128b7040e0d86 Mon Sep 17 00:00:00 2001 From: Masamitsu MURASE Date: Thu, 21 Jun 2012 02:00:05 +0900 Subject: Modify Kernel#clone and Kernel#dup. Kernel#clone, Kernel#dup: - 'iv' should not be shared with the original object, but it should be copied. Kernel#clone: - 'mt' of singleton_class should be copied. --- include/mruby/khash.h | 16 ++++++++++++++++ src/kernel.c | 13 +++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/include/mruby/khash.h b/include/mruby/khash.h index e236f0bea..0803521b7 100644 --- a/include/mruby/khash.h +++ b/include/mruby/khash.h @@ -61,6 +61,7 @@ static const uint8_t __m[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; khint_t kh_put_##name(kh_##name##_t *h, khkey_t key); \ void kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \ void kh_del_##name(kh_##name##_t *h, khint_t x); \ + kh_##name##_t *kh_copy_##name(mrb_state *mrb, kh_##name##_t *h); /* define kh_xxx_funcs @@ -179,6 +180,20 @@ static const uint8_t __m[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; { \ h->d_flags[x/8] |= __m[x%8]; \ h->size--; \ + } \ + kh_##name##_t *kh_copy_##name(mrb_state *mrb, kh_##name##_t *h) \ + { \ + kh_##name##_t *h2; \ + khiter_t k, k2; \ + \ + h2 = kh_init_##name(mrb); \ + for (k = kh_begin(h); k != kh_end(h); k++) { \ + if (kh_exist(h, k)) { \ + k2 = kh_put_##name(h2, kh_key(h, k)); \ + kh_value(h2, k2) = kh_value(h, k); \ + } \ + } \ + return h2; \ } @@ -191,6 +206,7 @@ static const uint8_t __m[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}; #define kh_put(name, h, k) kh_put_##name(h, k) #define kh_get(name, h, k) kh_get_##name(h, k) #define kh_del(name, h, k) kh_del_##name(h, k) +#define kh_copy(name, mrb, h) kh_copy_##name(mrb, h) #define kh_exist(h, x) (!__ac_iseither((h)->e_flags, (h)->d_flags, (x))) #define kh_key(h, x) ((h)->keys[x]) diff --git a/src/kernel.c b/src/kernel.c index 8da112ee5..5e17d4b5a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -338,7 +338,12 @@ mrb_singleton_class_clone(mrb_state *mrb, mrb_value obj) if (klass->iv) { clone->iv = klass->iv; } - clone->mt = kh_init(mt, mrb); + if (klass->mt) { + clone->mt = kh_copy(mt, mrb, klass->mt); + } + else { + clone->mt = kh_init(mt, mrb); + } clone->tt = MRB_TT_SCLASS; return clone; } @@ -361,10 +366,11 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_CLASS: case MRB_TT_MODULE: if (ROBJECT(dest)->iv) { + kh_destroy(iv, ROBJECT(dest)->iv); ROBJECT(dest)->iv = 0; } if (ROBJECT(obj)->iv) { - ROBJECT(dest)->iv = ROBJECT(obj)->iv; + ROBJECT(dest)->iv = kh_copy(iv, mrb, ROBJECT(obj)->iv); } break; @@ -446,9 +452,8 @@ mrb_obj_dup(mrb_state *mrb, mrb_value obj) mrb_raise(mrb, E_TYPE_ERROR, "can't dup %s", mrb_obj_classname(mrb, obj)); } p = mrb_obj_alloc(mrb, mrb_type(obj), mrb_obj_class(mrb, obj)); - //init_copy(dup, obj); dup = mrb_obj_value(p); - mrb_funcall(mrb, dup, "initialize_copy", 1, obj); + init_copy(mrb, dup, obj); return dup; } -- cgit v1.2.3 From 062e96960d078cb5bca48ba3b878f681871be72a Mon Sep 17 00:00:00 2001 From: Masamitsu MURASE Date: Fri, 22 Jun 2012 01:31:33 +0900 Subject: Add sample test for Kernel#clone and Kernel#dup. --- test/t/kernel.rb | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/t/kernel.rb b/test/t/kernel.rb index ba708dbb7..6531383e5 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -71,6 +71,62 @@ assert('Kernel.raise', '15.3.1.2.12') do e_list[0].class == RuntimeError end +assert('Kernel#clone', '15.3.1.3.8') do + class KernelCloneTest + def initialize + @v = 0 + end + + def get + @v + end + + def set(v) + @v = v + end + end + + a = KernelCloneTest.new + a.set(1) + b = a.clone + + def a.test + end + a.set(2) + c = a.clone + + a.get == 2 && b.get == 1 && c.get == 2 && + a.respond_to?(:test) == true && b.respond_to?(:test) == false && c.respond_to?(:test) == true +end + +assert('Kernel#dup', '15.3.1.3.9') do + class KernelDupTest + def initialize + @v = 0 + end + + def get + @v + end + + def set(v) + @v = v + end + end + + a = KernelDupTest.new + a.set(1) + b = a.dup + + def a.test + end + a.set(2) + c = a.dup + + a.get == 2 && b.get == 1 && c.get == 2 && + a.respond_to?(:test) == true && b.respond_to?(:test) == false && c.respond_to?(:test) == false +end + assert('Kernel#hash', '15.3.1.2.15') do hash == hash end -- cgit v1.2.3