summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorh2so5 <[email protected]>2013-10-27 03:18:22 +0900
committerh2so5 <[email protected]>2013-10-27 04:04:06 +0900
commit88758e36308492c860808ed9f7fb66e74f89e589 (patch)
tree90fbe608749027aacabea16491cb0ea7a99b86f9
parent3a668241bead302d3fa3db8a6b1915ec192ea274 (diff)
downloadmruby-88758e36308492c860808ed9f7fb66e74f89e589.tar.gz
mruby-88758e36308492c860808ed9f7fb66e74f89e589.zip
Uniquify the results of Object#methods
-rw-r--r--include/mruby/khash.h15
-rw-r--r--src/kernel.c36
2 files changed, 37 insertions, 14 deletions
diff --git a/include/mruby/khash.h b/include/mruby/khash.h
index fb11586d2..cadb3d074 100644
--- a/include/mruby/khash.h
+++ b/include/mruby/khash.h
@@ -50,7 +50,7 @@ static const uint8_t __m_either[8] = {0x03, 0x0c, 0x30, 0xc0};
name: hash name
khkey_t: key data type
khval_t: value data type
- kh_is_map: (not implemented / not used in RiteVM)
+ kh_is_map: (0: hash set / 1: hash map)
*/
#define KHASH_DECLARE(name, khkey_t, khval_t, kh_is_map) \
typedef struct kh_##name { \
@@ -89,7 +89,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
name: hash name
khkey_t: key data type
khval_t: value data type
- kh_is_map: (not implemented / not used in RiteVM)
+ kh_is_map: (0: hash set / 1: hash map)
__hash_func: hash function
__hash_equal: hash comparation function
*/
@@ -97,12 +97,13 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
void kh_alloc_##name(kh_##name##_t *h) \
{ \
khint_t sz = h->n_buckets; \
- uint8_t *p = mrb_malloc(h->mrb, sizeof(uint8_t)*sz/4+(sizeof(khkey_t)+sizeof(khval_t))*sz); \
+ int len = sizeof(khkey_t) + (kh_is_map ? sizeof(khval_t) : 0); \
+ uint8_t *p = mrb_malloc(h->mrb, sizeof(uint8_t)*sz/4+len*sz); \
h->size = h->n_occupied = 0; \
h->upper_bound = UPPER_BOUND(sz); \
h->keys = (khkey_t *)p; \
- h->vals = (khval_t *)(p+sizeof(khkey_t)*sz); \
- h->ed_flags = (p+sizeof(khkey_t)*sz+sizeof(khval_t)*sz); \
+ h->vals = kh_is_map ? (khval_t *)(p+sizeof(khkey_t)*sz) : NULL; \
+ h->ed_flags = p+len*sz; \
kh_fill_flags(h->ed_flags, 0xaa, sz/4); \
h->mask = sz-1; \
h->inc = sz/2-1; \
@@ -162,7 +163,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
for (i=0 ; i<old_n_buckets ; i++) { \
if (!__ac_iseither(old_ed_flags, i)) { \
khint_t k = kh_put_##name(h, old_keys[i]); \
- kh_value(h,k) = old_vals[i]; \
+ if (kh_is_map) kh_value(h,k) = old_vals[i]; \
} \
} \
mrb_free(h->mrb, old_keys); \
@@ -207,7 +208,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len)
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); \
+ if(kh_is_map) kh_value(h2, k2) = kh_value(h, k); \
} \
} \
return h2; \
diff --git a/src/kernel.c b/src/kernel.c
index bd58078fe..05ad37fa7 100644
--- a/src/kernel.c
+++ b/src/kernel.c
@@ -721,8 +721,11 @@ mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self)
return mrb_bool_value(kind_of_p);
}
+KHASH_DECLARE(st, mrb_sym, char, 0)
+KHASH_DEFINE(st, mrb_sym, char, 0, kh_int_hash_func, kh_int_hash_equal)
+
static void
-method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
+method_entry_loop(mrb_state *mrb, struct RClass* klass, khash_t(st)* set)
{
khint_t i;
@@ -730,7 +733,7 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
if (!h) return;
for (i=0;i<kh_end(h);i++) {
if (kh_exist(h, i)) {
- mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(h,i)));
+ kh_put(st, set, kh_key(h,i));
}
}
}
@@ -738,13 +741,14 @@ method_entry_loop(mrb_state *mrb, struct RClass* klass, mrb_value ary)
mrb_value
class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass, int obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* oldklass;
+ khash_t(st)* set = kh_init(st, mrb);
- ary = mrb_ary_new(mrb);
oldklass = 0;
while (klass && (klass != oldklass)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
if ((klass->tt == MRB_TT_ICLASS) ||
(klass->tt == MRB_TT_SCLASS)) {
}
@@ -755,28 +759,46 @@ class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass* klass,
klass = klass->super;
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, set);
+
return ary;
}
mrb_value
mrb_obj_singleton_methods(mrb_state *mrb, mrb_bool recur, mrb_value obj)
{
+ khint_t i;
mrb_value ary;
struct RClass* klass;
+ khash_t(st)* set = kh_init(st, mrb);
klass = mrb_class(mrb, obj);
- ary = mrb_ary_new(mrb);
+
if (klass && (klass->tt == MRB_TT_SCLASS)) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
if (recur) {
while (klass && ((klass->tt == MRB_TT_SCLASS) || (klass->tt == MRB_TT_ICLASS))) {
- method_entry_loop(mrb, klass, ary);
+ method_entry_loop(mrb, klass, set);
klass = klass->super;
}
}
+ ary = mrb_ary_new(mrb);
+ for (i=0;i<kh_end(set);i++) {
+ if (kh_exist(set, i)) {
+ mrb_ary_push(mrb, ary, mrb_symbol_value(kh_key(set,i)));
+ }
+ }
+ kh_destroy(st, set);
+
return ary;
}