summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/mruby/hash.h4
-rw-r--r--include/mruby/variable.h4
-rw-r--r--mrbgems/mruby-class-ext/mrblib/module.rb89
-rw-r--r--mrbgems/mruby-class-ext/test/module.rb54
-rw-r--r--src/hash.c30
-rw-r--r--src/variable.c29
-rw-r--r--src/vm.c5
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)
{
diff --git a/src/vm.c b/src/vm.c
index 84e076ee8..b5249b325 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -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;