summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hash.c170
-rw-r--r--insns.def13
-rw-r--r--internal.h1
-rw-r--r--vm.c31
4 files changed, 91 insertions, 124 deletions
diff --git a/hash.c b/hash.c
index ea31e08..b583390 100644
--- a/hash.c
+++ b/hash.c
@@ -626,110 +626,6 @@ rb_hash_initialize(int argc, VALUE *argv, VALUE hash)
return hash;
}
-static inline VALUE
-hash_alloc_from_st(VALUE klass, st_table *ntbl)
-{
- VALUE h = hash_alloc(klass);
- RHASH(h)->ntbl = ntbl;
- return h;
-}
-
-static inline void
-hash_insert_raw(VALUE hash, st_table *tbl, VALUE key, VALUE val)
-{
- st_data_t v = (st_data_t)val;
- st_data_t k = (rb_obj_class(key) == rb_cString) ?
- (st_data_t)rb_str_new_frozen(key) :
- (st_data_t)key;
-
- st_insert(tbl, k, v);
- RB_OBJ_WRITTEN(hash, Qundef, key);
- RB_OBJ_WRITTEN(hash, Qundef, val);
-}
-
-static VALUE
-rb_hash_new_from_values_with_klass(long argc, const VALUE *argv, VALUE klass)
-{
- long i;
- st_table *t;
- VALUE v;
-
- if (argc % 2) {
- rb_raise(rb_eArgError, "odd number of arguments for Hash");
- }
-
- t = st_init_table_with_size(&objhash, argc / 2);
- v = hash_alloc_from_st(klass, t);
-
- for (i = 0; i < argc; /* */) {
- VALUE key = argv[i++];
- VALUE val = argv[i++];
-
- hash_insert_raw(v, t, key, val);
- }
- return v;
-}
-
-VALUE
-rb_hash_new_from_values(long argc, const VALUE *argv)
-{
- return rb_hash_new_from_values_with_klass(argc, argv, rb_cHash);
-}
-
-static VALUE
-rb_hash_new_from_object(VALUE klass, VALUE obj)
-{
- VALUE tmp = rb_hash_s_try_convert(Qnil, obj);
- if (!NIL_P(tmp)) {
- VALUE hash = hash_alloc(klass);
- if (RHASH(tmp)->ntbl) {
- RHASH(hash)->ntbl = st_copy(RHASH(tmp)->ntbl);
- }
- return hash;
- }
-
- tmp = rb_check_array_type(obj);
- if (!NIL_P(tmp)) {
- long i;
- long len = RARRAY_LEN(tmp);
- st_table *tbl = len ? st_init_table_with_size(&objhash, len) : NULL;
- VALUE hv = hash_alloc_from_st(klass, tbl);;
-
- for (i = 0; i < len; ++i) {
- VALUE e = RARRAY_AREF(tmp, i);
- VALUE v = rb_check_array_type(e);
- VALUE key, val = Qnil;
-
- if (NIL_P(v)) {
-#if 0 /* refix in the next release */
- rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
- rb_builtin_class_name(e), i);
-
-#else
- rb_warn("wrong element type %s at %ld (expected array)",
- rb_builtin_class_name(e), i);
- rb_warn("ignoring wrong elements is deprecated, remove them explicitly");
- rb_warn("this causes ArgumentError in the next release");
- continue;
-#endif
- }
- switch (RARRAY_LEN(v)) {
- default:
- rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
- RARRAY_LEN(v));
- case 2:
- val = RARRAY_AREF(v, 1);
- case 1:
- key = RARRAY_AREF(v, 0);
- hash_insert_raw(hv, tbl, key, val);
- }
- }
- return hv;
- }
-
- rb_raise(rb_eArgError, "odd number of arguments for Hash");
-}
-
/*
* call-seq:
* Hash[ key, value, ... ] -> new_hash
@@ -753,11 +649,69 @@ rb_hash_new_from_object(VALUE klass, VALUE obj)
static VALUE
rb_hash_s_create(int argc, VALUE *argv, VALUE klass)
{
- switch (argc) {
- case 0: return hash_alloc(klass);
- case 1: return rb_hash_new_from_object(klass, argv[0]);
- default: return rb_hash_new_from_values_with_klass(argc, argv, klass);
+ VALUE hash, tmp;
+ int i;
+
+ if (argc == 1) {
+ tmp = rb_hash_s_try_convert(Qnil, argv[0]);
+ if (!NIL_P(tmp)) {
+ hash = hash_alloc(klass);
+ if (RHASH(tmp)->ntbl) {
+ RHASH(hash)->ntbl = st_copy(RHASH(tmp)->ntbl);
+ }
+ return hash;
+ }
+
+ tmp = rb_check_array_type(argv[0]);
+ if (!NIL_P(tmp)) {
+ long i;
+
+ hash = hash_alloc(klass);
+ for (i = 0; i < RARRAY_LEN(tmp); ++i) {
+ VALUE e = RARRAY_AREF(tmp, i);
+ VALUE v = rb_check_array_type(e);
+ VALUE key, val = Qnil;
+
+ if (NIL_P(v)) {
+#if 0 /* refix in the next release */
+ rb_raise(rb_eArgError, "wrong element type %s at %ld (expected array)",
+ rb_builtin_class_name(e), i);
+
+#else
+ rb_warn("wrong element type %s at %ld (expected array)",
+ rb_builtin_class_name(e), i);
+ rb_warn("ignoring wrong elements is deprecated, remove them explicitly");
+ rb_warn("this causes ArgumentError in the next release");
+ continue;
+#endif
+ }
+ switch (RARRAY_LEN(v)) {
+ default:
+ rb_raise(rb_eArgError, "invalid number of elements (%ld for 1..2)",
+ RARRAY_LEN(v));
+ case 2:
+ val = RARRAY_AREF(v, 1);
+ case 1:
+ key = RARRAY_AREF(v, 0);
+ rb_hash_aset(hash, key, val);
+ }
+ }
+ return hash;
+ }
+ }
+ if (argc % 2 != 0) {
+ rb_raise(rb_eArgError, "odd number of arguments for Hash");
+ }
+
+ hash = hash_alloc(klass);
+ if (argc > 0) {
+ RHASH(hash)->ntbl = st_init_table_with_size(&objhash, argc / 2);
+ }
+ for (i=0; i<argc; i+=2) {
+ rb_hash_aset(hash, argv[i], argv[i + 1]);
}
+
+ return hash;
}
static VALUE
diff --git a/insns.def b/insns.def
index 36ba48e..a056b22 100644
--- a/insns.def
+++ b/insns.def
@@ -492,13 +492,16 @@ newhash
(...)
(VALUE val) // inc += 1 - num;
{
+ rb_num_t i;
+
RUBY_DTRACE_CREATE_HOOK(HASH, num);
- if (num) {
- val = rb_hash_new_from_values(num, STACK_ADDR_FROM_TOP(num));
- }
- else {
- val = rb_hash_new();
+ val = rb_hash_new();
+
+ for (i = num; i > 0; i -= 2) {
+ const VALUE v = TOPN(i - 2);
+ const VALUE k = TOPN(i - 1);
+ rb_hash_aset(val, k, v);
}
POPN(num);
}
diff --git a/internal.h b/internal.h
index de89418..afea318 100644
--- a/internal.h
+++ b/internal.h
@@ -1236,7 +1236,6 @@ VALUE rb_hash_rehash(VALUE hash);
int rb_hash_add_new_element(VALUE hash, VALUE key, VALUE val);
#define HASH_DELETED FL_USER1
#define HASH_PROC_DEFAULT FL_USER2
-extern VALUE rb_hash_new_from_values(long, const VALUE *);
/* inits.c */
void rb_call_inits(void);
diff --git a/vm.c b/vm.c
index 968f2db..e64c072 100644
--- a/vm.c
+++ b/vm.c
@@ -2646,6 +2646,7 @@ m_core_set_postexe(VALUE self)
return Qnil;
}
+static VALUE core_hash_merge_ary(VALUE hash, VALUE ary);
static VALUE core_hash_from_ary(VALUE ary);
static VALUE core_hash_merge_kwd(int argc, VALUE *argv);
@@ -2655,6 +2656,7 @@ core_hash_merge(VALUE hash, long argc, const VALUE *argv)
long i;
Check_Type(hash, T_HASH);
+ VM_ASSERT(argc % 2 == 0);
for (i=0; i<argc; i+=2) {
rb_hash_aset(hash, argv[i], argv[i+1]);
}
@@ -2672,18 +2674,27 @@ m_core_hash_from_ary(VALUE self, VALUE ary)
static VALUE
core_hash_from_ary(VALUE ary)
{
- long n;
+ VALUE hash = rb_hash_new();
+ RUBY_DTRACE_CREATE_HOOK(HASH, (Check_Type(ary, T_ARRAY), RARRAY_LEN(ary)));
+ return core_hash_merge_ary(hash, ary);
+}
+
+#if 0
+static VALUE
+m_core_hash_merge_ary(VALUE self, VALUE hash, VALUE ary)
+{
+ REWIND_CFP(core_hash_merge_ary(hash, ary));
+ return hash;
+}
+#endif
+
+static VALUE
+core_hash_merge_ary(VALUE hash, VALUE ary)
+{
Check_Type(ary, T_ARRAY);
- n = RARRAY_LEN(ary);
- RUBY_DTRACE_CREATE_HOOK(HASH, n);
- if (n) {
- VM_ASSERT(n % 2 == 0);
- return rb_hash_new_from_values(n, RARRAY_PTR(ary));
- }
- else {
- return rb_hash_new();
- }
+ core_hash_merge(hash, RARRAY_LEN(ary), RARRAY_CONST_PTR(ary));
+ return hash;
}
static VALUE