summaryrefslogtreecommitdiffhomepage
path: root/src/hash.c
diff options
context:
space:
mode:
authorFelix Jones <[email protected]>2017-02-16 13:33:46 +0000
committerFelix Jones <[email protected]>2017-02-16 13:33:46 +0000
commitd83aad8d570e4bbffa3bd3ce64e210f78afa425f (patch)
tree5389a87c135b1bdf3e23a1ba02e02400b7cf80fc /src/hash.c
parent70aa6dc38d75dd6b1e2c76f290bc576e36e36ea3 (diff)
parentb165708c8deba00685f9a27926c554aaa7f3b0fb (diff)
downloadmruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.tar.gz
mruby-d83aad8d570e4bbffa3bd3ce64e210f78afa425f.zip
Merge branch 'master' into android.rake-ndk-clang
Diffstat (limited to 'src/hash.c')
-rw-r--r--src/hash.c68
1 files changed, 52 insertions, 16 deletions
diff --git a/src/hash.c b/src/hash.c
index 2ad6a9642..d15faa206 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash);
static inline mrb_value
mrb_hash_ht_key(mrb_state *mrb, mrb_value key)
{
- if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) {
+ if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) {
key = mrb_str_dup(mrb, key);
- RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key));
+ MRB_SET_FROZEN_FLAG(mrb_str_ptr(key));
}
return key;
}
@@ -159,11 +159,15 @@ mrb_hash_new(mrb_state *mrb)
return mrb_hash_new_capa(mrb, 0);
}
+static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash);
+static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key);
+
MRB_API mrb_value
mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
{
khash_t(ht) *h = RHASH_TBL(hash);
khiter_t k;
+ mrb_sym mid;
if (h) {
k = kh_get(ht, mrb, h, key);
@@ -171,14 +175,12 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key)
return kh_value(h, k).v;
}
- /* not found */
- if (MRB_RHASH_DEFAULT_P(hash)) {
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
- }
- return RHASH_IFNONE(hash);
+ mid = mrb_intern_lit(mrb, "default");
+ if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) {
+ return hash_default(mrb, hash, key);
}
- return mrb_nil_value();
+ /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */
+ return mrb_funcall_argv(mrb, hash, mid, 1, &key);
}
MRB_API mrb_value
@@ -230,6 +232,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
struct RHash* ret;
khash_t(ht) *h, *ret_h;
khiter_t k, ret_k;
+ mrb_value ifnone, vret;
h = RHASH_TBL(hash);
ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class);
@@ -248,7 +251,18 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash)
}
}
- return mrb_obj_value(ret);
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_DEFAULT;
+ }
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ ret->flags |= MRB_HASH_PROC_DEFAULT;
+ }
+ vret = mrb_obj_value(ret);
+ ifnone = RHASH_IFNONE(hash);
+ if (!mrb_nil_p(ifnone)) {
+ mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone);
+ }
+ return vret;
}
MRB_API mrb_value
@@ -271,6 +285,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash)
static void
mrb_hash_modify(mrb_state *mrb, mrb_value hash)
{
+ if (MRB_FROZEN_P(mrb_hash_ptr(hash))) {
+ mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash");
+ }
mrb_hash_tbl(mrb, hash);
}
@@ -356,6 +373,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self)
return mrb_hash_get(mrb, self, key);
}
+static mrb_value
+hash_default(mrb_state *mrb, mrb_value hash, mrb_value key)
+{
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
+ }
+ return mrb_nil_value();
+}
+
/* 15.2.13.4.5 */
/*
* call-seq:
@@ -385,13 +416,16 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash)
mrb_bool given;
mrb_get_args(mrb, "|o?", &key, &given);
- if (MRB_RHASH_PROCDEFAULT_P(hash)) {
- if (!given) return mrb_nil_value();
- return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
- }
- else {
- return RHASH_IFNONE(hash);
+ if (MRB_RHASH_DEFAULT_P(hash)) {
+ if (MRB_RHASH_PROCDEFAULT_P(hash)) {
+ if (!given) return mrb_nil_value();
+ return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key);
+ }
+ else {
+ return RHASH_IFNONE(hash);
+ }
}
+ return mrb_nil_value();
}
/* 15.2.13.4.6 */
@@ -541,6 +575,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self)
mrb_value key;
mrb_get_args(mrb, "o", &key);
+ mrb_hash_modify(mrb, self);
return mrb_hash_delete_key(mrb, self, key);
}
@@ -607,6 +642,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash)
{
khash_t(ht) *h = RHASH_TBL(hash);
+ mrb_hash_modify(mrb, hash);
if (h) kh_clear(ht, mrb, h);
return hash;
}