mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
mruby-hash-ext: enhance __merge for multiple arguments
Replace single-argument __merge with multi-argument C implementation. Eliminates Ruby loop overhead for merging multiple hashes. Optimizes merge! method while maintaining block functionality. Co-authored-by: Atlassian Rovo Dev
This commit is contained in:
@@ -32,13 +32,9 @@ class Hash
|
||||
other = others[i]
|
||||
i += 1
|
||||
raise TypeError, "Hash required (#{other.class} given)" unless Hash === other
|
||||
if block
|
||||
other.each_key{|k|
|
||||
self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
|
||||
}
|
||||
else
|
||||
other.each_key{|k| self[k] = other[k]}
|
||||
end
|
||||
other.each_key{|k|
|
||||
self[k] = (self.has_key?(k))? block.call(k, self[k], other[k]): other[k]
|
||||
}
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
@@ -295,6 +295,44 @@ hash_deconstruct_keys(mrb_state *mrb, mrb_value hash)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* hsh.__merge(*others) -> hsh
|
||||
*
|
||||
* Merges multiple hashes into hsh. This is an internal method
|
||||
* used by merge! for non-block cases.
|
||||
*
|
||||
* Raises ArgumentError if no arguments given.
|
||||
* Raises TypeError if any argument is not a Hash.
|
||||
*
|
||||
* h = { a: 1, b: 2 }
|
||||
* h.__merge({ c: 3 }, { d: 4 }) #=> { a: 1, b: 2, c: 3, d: 4 }
|
||||
*/
|
||||
static mrb_value
|
||||
hash_merge(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_int argc;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
|
||||
/* Validate arguments */
|
||||
if (argc == 0) {
|
||||
mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (given 0, expected 1+)");
|
||||
}
|
||||
|
||||
/* Merge multiple hashes in C */
|
||||
for (mrb_int i = 0; i < argc; i++) {
|
||||
if (!mrb_hash_p(argv[i])) {
|
||||
mrb_raisef(mrb, E_TYPE_ERROR, "no implicit conversion of %C into Hash",
|
||||
mrb_obj_class(mrb, argv[i]));
|
||||
}
|
||||
mrb_hash_merge(mrb, hash, argv[i]);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
|
||||
{
|
||||
@@ -306,6 +344,7 @@ mrb_mruby_hash_ext_gem_init(mrb_state *mrb)
|
||||
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_method_id(mrb, h, MRB_SYM(deconstruct_keys), hash_deconstruct_keys, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, h, MRB_SYM(__merge), hash_merge, MRB_ARGS_ANY());
|
||||
mrb_define_class_method_id(mrb, h, MRB_OPSYM(aref), hash_s_create, MRB_ARGS_ANY());
|
||||
}
|
||||
|
||||
|
||||
@@ -46,27 +46,27 @@ assert('Hash.[] for sub class') do
|
||||
end
|
||||
|
||||
assert('Hash#merge!') do
|
||||
# Single hash merge
|
||||
a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
|
||||
b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' }
|
||||
|
||||
result_1 = a.merge! b
|
||||
assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'XXX',
|
||||
'xyz_key' => 'xyz_value' }, result_1)
|
||||
|
||||
# Block handling
|
||||
a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
|
||||
result_2 = a.merge!(b) do |key, original, new|
|
||||
original
|
||||
end
|
||||
|
||||
assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'XXX',
|
||||
'xyz_key' => 'xyz_value' }, result_1)
|
||||
assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value',
|
||||
'xyz_key' => 'xyz_value' }, result_2)
|
||||
|
||||
assert_raise(TypeError) do
|
||||
{ 'abc_key' => 'abc_value' }.merge! "a"
|
||||
end
|
||||
|
||||
# multiple arguments
|
||||
# Multiple arguments
|
||||
assert_equal({a:1,b:2,c:3}, {a:1}.merge!({b:2},{c:3}))
|
||||
|
||||
# Error cases
|
||||
assert_raise(ArgumentError) { {}.merge!() }
|
||||
assert_raise(TypeError) { {}.merge!("not a hash") }
|
||||
end
|
||||
|
||||
assert('Hash#values_at') do
|
||||
|
||||
Reference in New Issue
Block a user