diff --git a/mrbgems/mruby-hash-ext/mrblib/hash.rb b/mrbgems/mruby-hash-ext/mrblib/hash.rb
index bc5b36746..9ba326bc2 100644
--- a/mrbgems/mruby-hash-ext/mrblib/hash.rb
+++ b/mrbgems/mruby-hash-ext/mrblib/hash.rb
@@ -200,25 +200,6 @@ class Hash
self
end
- ##
- # call-seq:
- # hsh.key(value) -> key
- #
- # Returns the key of an occurrence of a given value. If the value is
- # not found, returns nil.
- #
- # h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
- # h.key(200) #=> "b"
- # h.key(300) #=> "c"
- # h.key(999) #=> nil
- #
-
- def key(val)
- self.each do |k, v|
- return k if v == val
- end
- nil
- end
##
# call-seq:
diff --git a/mrbgems/mruby-hash-ext/src/hash_ext.c b/mrbgems/mruby-hash-ext/src/hash_ext.c
index 9412ea943..4de40b63c 100644
--- a/mrbgems/mruby-hash-ext/src/hash_ext.c
+++ b/mrbgems/mruby-hash-ext/src/hash_ext.c
@@ -198,6 +198,55 @@ hash_s_create(mrb_state *mrb, mrb_value klass)
return hash;
}
+/* Data structure for hash_key search */
+struct key_search {
+ mrb_value target;
+ mrb_value result;
+ mrb_bool found;
+};
+
+/* Iterator function for hash_key */
+static int
+hash_key_i(mrb_state *mrb, mrb_value key, mrb_value val, void *data)
+{
+ struct key_search *search = (struct key_search*)data;
+ if (mrb_equal(mrb, val, search->target)) {
+ search->result = key;
+ search->found = TRUE;
+ return 1; /* Stop iteration */
+ }
+ return 0; /* Continue iteration */
+}
+
+/*
+ * call-seq:
+ * hsh.key(value) -> key
+ *
+ * Returns the key of an occurrence of a given value. If the value is
+ * not found, returns nil.
+ *
+ * h = { "a" => 100, "b" => 200, "c" => 300, "d" => 300 }
+ * h.key(200) #=> "b"
+ * h.key(300) #=> "c" or "d"
+ * h.key(999) #=> nil
+ */
+static mrb_value
+hash_key(mrb_state *mrb, mrb_value hash)
+{
+ mrb_value val;
+ struct key_search search;
+
+ mrb_get_args(mrb, "o", &val);
+
+ search.target = val;
+ search.result = mrb_nil_value();
+ search.found = FALSE;
+
+ mrb_hash_foreach(mrb, mrb_hash_ptr(hash), hash_key_i, &search);
+
+ return search.found ? search.result : mrb_nil_value();
+}
+
void
mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
{
@@ -207,6 +256,7 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
mrb_define_method_id(mrb, h, MRB_SYM(values_at), hash_values_at, MRB_ARGS_ANY());
mrb_define_method_id(mrb, h, MRB_SYM(slice), hash_slice, MRB_ARGS_ANY());
mrb_define_method_id(mrb, h, MRB_SYM(except), hash_except, MRB_ARGS_ANY());
+ mrb_define_method_id(mrb, h, MRB_SYM(key), hash_key, MRB_ARGS_REQ(1));
mrb_define_class_method_id(mrb, h, MRB_OPSYM(aref), hash_s_create, MRB_ARGS_ANY());
}