Skip to content

Commit c40cf04

Browse files
committed
implement rb_hash_bulk_insert
1 parent 8594c3a commit c40cf04

File tree

5 files changed

+67
-1
lines changed

5 files changed

+67
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Compatibility:
1919
* Implement `rb_str_strlen()` (#3697, @Th3-M4jor).
2020
* Support `Time.new` with String argument and error when invalid (#3693, @rwstauner).
2121
* Implement `rb_enc_interned_str()` (#3703, @Th3-M4jor).
22+
* Implement `rb_hash_bulk_insert()` (#3705, @Th3-M4jor).
2223

2324
Performance:
2425

lib/cext/include/truffleruby/truffleruby-abi-version.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
// $RUBY_VERSION must be the same as TruffleRuby.LANGUAGE_VERSION.
2121
// $ABI_NUMBER starts at 1 and is incremented for every ABI-incompatible change.
2222

23-
#define TRUFFLERUBY_ABI_VERSION "3.2.4.6"
23+
#define TRUFFLERUBY_ABI_VERSION "3.2.4.7"
2424

2525
#endif

spec/ruby/optional/capi/ext/hash_spec.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,13 @@ VALUE hash_spec_compute_a_hash_code(VALUE self, VALUE seed) {
134134
return ULONG2NUM(h);
135135
}
136136

137+
VALUE hash_spec_rb_hash_bulk_insert(VALUE self, VALUE hash, VALUE array_len, VALUE array) {
138+
long len = FIX2LONG(array_len);
139+
VALUE *ptr = RARRAY_PTR(array);
140+
rb_hash_bulk_insert(len, ptr, hash);
141+
return hash;
142+
}
143+
137144
void Init_hash_spec(void) {
138145
VALUE cls = rb_define_class("CApiHashSpecs", rb_cObject);
139146
rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1);
@@ -162,6 +169,7 @@ void Init_hash_spec(void) {
162169
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
163170
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
164171
rb_define_method(cls, "compute_a_hash_code", hash_spec_compute_a_hash_code, 1);
172+
rb_define_method(cls, "rb_hash_bulk_insert", hash_spec_rb_hash_bulk_insert, 3);
165173
}
166174

167175
#ifdef __cplusplus

spec/ruby/optional/capi/hash_spec.rb

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,51 @@
194194
end
195195
end
196196

197+
describe "rb_hash_bulk_insert" do
198+
it 'inserts key-value pairs into the hash' do
199+
arr = [:a, 1, :b, 2, :c, 3]
200+
hash = {}
201+
202+
@s.rb_hash_bulk_insert(hash, arr.length, arr)
203+
204+
hash.should == {a: 1, b: 2, c: 3}
205+
end
206+
207+
it 'overwrites existing keys' do
208+
arr = [:a, 4, :b, 5, :c, 6]
209+
hash = {a: 1, b: 2}
210+
211+
@s.rb_hash_bulk_insert(hash, arr.length, arr)
212+
213+
hash.should == {a: 4, b: 5, c: 6}
214+
end
215+
216+
it 'raises an ArgumentError if the array length is not a multiple of 2' do
217+
arr = [:a, 1, :b, 2, :c]
218+
hash = {}
219+
220+
-> { @s.rb_hash_bulk_insert(hash, arr.length, arr) }.should raise_error(ArgumentError)
221+
end
222+
223+
it 'does not include any keys after the given length' do
224+
arr = [:a, 1, :b, 2, :c, 3, :d, 4]
225+
hash = {}
226+
227+
@s.rb_hash_bulk_insert(hash, arr.length - 2, arr)
228+
229+
hash.should == {a: 1, b: 2, c: 3}
230+
end
231+
232+
it 'does not modify the hash if the length is zero' do
233+
arr = []
234+
hash = {a: 1, b: 2}
235+
236+
@s.rb_hash_bulk_insert(hash, arr.length, arr)
237+
238+
hash.should == {a: 1, b: 2}
239+
end
240+
end
241+
197242
describe "rb_hash_size" do
198243
it "returns the size of the hash" do
199244
hsh = {fast: 'car', good: 'music'}

src/main/c/cext/hash.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ void rb_hash_foreach(VALUE hash, int (*func)(VALUE key, VALUE val, VALUE arg), V
100100
polyglot_invoke(RUBY_CEXT, "rb_hash_foreach", rb_tr_unwrap(hash), func, (void*)arg);
101101
}
102102

103+
void rb_hash_bulk_insert(long n, const VALUE *values, VALUE hash) {
104+
if (n % 2 != 0) {
105+
rb_raise(rb_eArgError, "Expected an even number of array elements");
106+
}
107+
108+
void* unwrapped_hash = rb_tr_unwrap(hash);
109+
110+
for (long i = 0; i < n; i += 2) {
111+
polyglot_invoke(unwrapped_hash, "[]=", rb_tr_unwrap(values[i]), rb_tr_unwrap(values[i + 1]));
112+
}
113+
}
114+
103115
VALUE rb_hash_size(VALUE hash) {
104116
return RUBY_INVOKE(hash, "size");
105117
}

0 commit comments

Comments
 (0)