diff options
| author | Felix Jones <[email protected]> | 2017-02-16 13:33:46 +0000 |
|---|---|---|
| committer | Felix Jones <[email protected]> | 2017-02-16 13:33:46 +0000 |
| commit | d83aad8d570e4bbffa3bd3ce64e210f78afa425f (patch) | |
| tree | 5389a87c135b1bdf3e23a1ba02e02400b7cf80fc /src/hash.c | |
| parent | 70aa6dc38d75dd6b1e2c76f290bc576e36e36ea3 (diff) | |
| parent | b165708c8deba00685f9a27926c554aaa7f3b0fb (diff) | |
| download | mruby-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.c | 68 |
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; } |
