diff options
| -rw-r--r-- | include/mruby/hash.h | 4 | ||||
| -rw-r--r-- | include/mruby/variable.h | 4 | ||||
| -rw-r--r-- | mrbgems/mruby-class-ext/mrblib/module.rb | 89 | ||||
| -rw-r--r-- | mrbgems/mruby-class-ext/test/module.rb | 54 | ||||
| -rw-r--r-- | src/hash.c | 30 | ||||
| -rw-r--r-- | src/variable.c | 29 | ||||
| -rw-r--r-- | src/vm.c | 5 |
7 files changed, 187 insertions, 28 deletions
diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 7811894ae..911a96042 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -210,6 +210,10 @@ void mrb_gc_mark_hash(mrb_state*, struct RHash*); size_t mrb_gc_mark_hash_size(mrb_state*, struct RHash*); void mrb_gc_free_hash(mrb_state*, struct RHash*); +/* return non zero to break the loop */ +typedef int (mrb_hash_foreach_func)(mrb_state *mrb, mrb_value key, mrb_value val, void *data); +MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_HASH_H */ diff --git a/include/mruby/variable.h b/include/mruby/variable.h index a0fbca1f9..68a2a7121 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -131,6 +131,10 @@ void mrb_gc_mark_iv(mrb_state*, struct RObject*); size_t mrb_gc_mark_iv_size(mrb_state*, struct RObject*); void mrb_gc_free_iv(mrb_state*, struct RObject*); +/* return non zero to break the loop */ +typedef int (mrb_iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +MRB_API void mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p); + MRB_END_DECL #endif /* MRUBY_VARIABLE_H */ diff --git a/mrbgems/mruby-class-ext/mrblib/module.rb b/mrbgems/mruby-class-ext/mrblib/module.rb new file mode 100644 index 000000000..301585187 --- /dev/null +++ b/mrbgems/mruby-class-ext/mrblib/module.rb @@ -0,0 +1,89 @@ +class Module + + ## + # call-seq: + # mod < other -> true, false, or nil + # + # Returns true if `mod` is a subclass of `other`. Returns + # <code>nil</code> if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "A < B".) + # + def <(other) + if self.equal?(other) + false + else + self <= other + end + end + + ## + # call-seq: + # mod <= other -> true, false, or nil + # + # Returns true if `mod` is a subclass of `other` or + # is the same as `other`. Returns + # <code>nil</code> if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "A < B".) + def <=(other) + raise TypeError, 'compared with non class/module' unless other.is_a?(Module) + if self.ancestors.include?(other) + return true + elsif other.ancestors.include?(self) + return false + end + end + + ## + # call-seq: + # mod > other -> true, false, or nil + # + # Returns true if `mod` is an ancestor of `other`. Returns + # <code>nil</code> if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "B > A".) + # + def >(other) + if self.equal?(other) + false + else + self >= other + end + end + + ## + # call-seq: + # mod >= other -> true, false, or nil + # + # Returns true if `mod` is an ancestor of `other`, or the + # two modules are the same. Returns + # <code>nil</code> if there's no relationship between the two. + # (Think of the relationship in terms of the class definition: + # "class A < B" implies "B > A".) + # + def >=(other) + raise TypeError, 'compared with non class/module' unless other.is_a?(Module) + return other < self + end + + ## + # call-seq: + # module <=> other_module -> -1, 0, +1, or nil + # + # Comparison---Returns -1, 0, +1 or nil depending on whether `module` + # includes `other_module`, they are the same, or if `module` is included by + # `other_module`. + # + # Returns `nil` if `module` has no relationship with `other_module`, if + # `other_module` is not a module, or if the two values are incomparable. + # + def <=>(other) + return 0 if self.equal?(other) + return nil unless other.is_a?(Module) + cmp = self < other + return -1 if cmp + return 1 unless cmp.nil? + return nil + end +end diff --git a/mrbgems/mruby-class-ext/test/module.rb b/mrbgems/mruby-class-ext/test/module.rb index 71a8da451..52e04ab37 100644 --- a/mrbgems/mruby-class-ext/test/module.rb +++ b/mrbgems/mruby-class-ext/test/module.rb @@ -1,3 +1,57 @@ +assert 'Module#<' do + a = Class.new + b = Class.new(a) + c = Class.new(a) + d = Module.new + e = Class.new { include d } + f = Module.new { include d } + + # compare class to class + assert_true b < a + assert_false b < b + assert_false a < b + assert_nil c < b + + # compare class to module + assert_true e < d + assert_false d < e + assert_nil a < d + + # compare module to module + assert_true f < d + assert_false f < f + assert_false d < f + + assert_raise(TypeError) { a < Object.new } +end + +assert 'Module#<=' do + a = Class.new + b = Class.new(a) + c = Class.new(a) + d = Module.new + e = Class.new { include d } + f = Module.new { include d } + + # compare class to class + assert_true b <= a + assert_true b <= b + assert_false a <= b + assert_nil c <= b + + # compare class to module + assert_true e <= d + assert_false d <= e + assert_nil a <= d + + # compare module to module + assert_true f <= d + assert_true f <= f + assert_false d <= f + + assert_raise(TypeError) { a <= Object.new } +end + assert 'Module#name' do module Outer class Inner; end diff --git a/src/hash.c b/src/hash.c index 467b20a51..3d6c2ed7d 100644 --- a/src/hash.c +++ b/src/hash.c @@ -16,13 +16,10 @@ mrb_int mrb_float_id(mrb_float f); #endif -/* return non zero to break the loop */ -typedef int (ht_foreach_func)(mrb_state *mrb,mrb_value key, mrb_value val, void *data); - #ifndef MRB_HT_INIT_SIZE #define MRB_HT_INIT_SIZE 4 #endif -#define HT_SEG_INCREASE_RATIO 1.2 +#define HT_SEG_INCREASE_RATIO 6 / 5 struct segkv { mrb_value key; @@ -41,7 +38,7 @@ typedef struct segindex { struct segkv *table[]; } segindex; -/* Instance variable table structure */ +/* hash table structure */ typedef struct htable { segment *rootseg; segment *lastseg; @@ -135,7 +132,7 @@ ht_hash_equal(mrb_state *mrb, htable *t, mrb_value a, mrb_value b) } } -/* Creates the instance variable table. */ +/* Creates the hash table. */ static htable* ht_new(mrb_state *mrb) { @@ -349,7 +346,7 @@ ht_index_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) t->size++; } -/* Set the value for the key in the table. */ +/* Set the value for the key in the hash table. */ static void ht_put(mrb_state *mrb, htable *t, mrb_value key, mrb_value val) { @@ -468,7 +465,7 @@ ht_get(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Deletes the value for the symbol from the instance variable table. */ +/* Deletes the value for the symbol from the hash table. */ /* Deletion is done by overwriting keys by `undef`. */ static mrb_bool ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) @@ -499,9 +496,9 @@ ht_del(mrb_state *mrb, htable *t, mrb_value key, mrb_value *vp) return FALSE; } -/* Iterates over the instance variable table. */ +/* Iterates over the hash table. */ static void -ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) +ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) { segment *seg; mrb_int i; @@ -522,7 +519,14 @@ ht_foreach(mrb_state *mrb, htable *t, ht_foreach_func *func, void *p) } } -/* Copy the instance variable table. */ +/* Iterates over the hash table. */ +MRB_API void +mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) +{ + ht_foreach(mrb, hash->ht, func, p); +} + +/* Copy the hash table. */ static htable* ht_copy(mrb_state *mrb, htable *t) { @@ -548,7 +552,7 @@ ht_copy(mrb_state *mrb, htable *t) return t2; } -/* Free memory of the instance variable table. */ +/* Free memory of the hash table. */ static void ht_free(mrb_state *mrb, htable *t) { @@ -1008,7 +1012,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) return mrb_hash_delete_key(mrb, self, key); } -/* find first element in a hash table, and remove it. */ +/* find first element in the hash table, and remove it. */ static void ht_shift(mrb_state *mrb, htable *t, mrb_value *kp, mrb_value *vp) { diff --git a/src/variable.c b/src/variable.c index 72c13aa1f..14e9da9ef 100644 --- a/src/variable.c +++ b/src/variable.c @@ -9,8 +9,7 @@ #include <mruby/class.h> #include <mruby/proc.h> #include <mruby/string.h> - -typedef int (iv_foreach_func)(mrb_state*,mrb_sym,mrb_value,void*); +#include <mruby/variable.h> #ifndef MRB_IV_SEGMENT_SIZE #define MRB_IV_SEGMENT_SIZE 4 @@ -156,14 +155,13 @@ iv_del(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value *vp) } /* Iterates over the instance variable table. */ -static mrb_bool -iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) +static void +iv_foreach(mrb_state *mrb, iv_tbl *t, mrb_iv_foreach_func *func, void *p) { segment *seg; size_t i; - int n; - if (t == NULL) return TRUE; + if (t == NULL) return; seg = t->rootseg; while (seg) { for (i=0; i<MRB_IV_SEGMENT_SIZE; i++) { @@ -171,20 +169,17 @@ iv_foreach(mrb_state *mrb, iv_tbl *t, iv_foreach_func *func, void *p) /* no value in last segment after last_len */ if (!seg->next && i >= t->last_len) { - return FALSE; + return; } if (key != 0) { - n =(*func)(mrb, key, seg->val[i], p); - if (n > 0) return FALSE; - if (n < 0) { - t->size--; - seg->key[i] = 0; + if ((*func)(mrb, key, seg->val[i], p) != 0) { + return; } } } seg = seg->next; } - return TRUE; + return; } /* Get the size of the instance variable table. */ @@ -363,6 +358,14 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) mrb_write_barrier(mrb, (struct RBasic*)obj); } +/* Iterates over the instance variable table. */ +MRB_API void +mrb_iv_foreach(mrb_state *mrb, mrb_value obj, mrb_iv_foreach_func *func, void *p) +{ + if (!obj_iv_p(obj)) return; + iv_foreach(mrb, mrb_obj_ptr(obj)->iv, func, p); +} + static inline mrb_bool namespace_p(enum mrb_vtype tt) { @@ -667,10 +667,11 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) return MRB_PROC_CFUNC(p)(mrb, self); } nregs = p->body.irep->nregs; - mrb_stack_extend(mrb, (nregs < 3) ? 3 : nregs); + if (nregs < 3) nregs = 3; + mrb_stack_extend(mrb, nregs); mrb->c->stack[0] = self; mrb->c->stack[1] = self; - mrb->c->stack[2] = mrb_nil_value(); + stack_clear(mrb->c->stack+2, nregs-2); ci = cipush(mrb); ci->target_class = 0; ci->pc = p->body.irep->iseq; |
