Skip to content

Commit 529bd60

Browse files
Th3-M4jorandrykonchin
authored andcommitted
Implement rb_hash_bulk_insert
1 parent 8594c3a commit 529bd60

File tree

5 files changed

+80
-1
lines changed

5 files changed

+80
-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: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,20 @@ 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 array_len, VALUE array, VALUE hash) {
138+
VALUE* ptr;
139+
140+
if (array == Qnil) {
141+
ptr = NULL;
142+
} else {
143+
ptr = RARRAY_PTR(array);
144+
}
145+
146+
long len = FIX2LONG(array_len);
147+
rb_hash_bulk_insert(len, ptr, hash);
148+
return Qnil;
149+
}
150+
137151
void Init_hash_spec(void) {
138152
VALUE cls = rb_define_class("CApiHashSpecs", rb_cObject);
139153
rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1);
@@ -162,6 +176,7 @@ void Init_hash_spec(void) {
162176
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
163177
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
164178
rb_define_method(cls, "compute_a_hash_code", hash_spec_compute_a_hash_code, 1);
179+
rb_define_method(cls, "rb_hash_bulk_insert", hash_spec_rb_hash_bulk_insert, 3);
165180
}
166181

167182
#ifdef __cplusplus

spec/ruby/optional/capi/hash_spec.rb

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,61 @@
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(arr.length, arr, hash)
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(arr.length, arr, hash)
212+
213+
hash.should == {a: 4, b: 5, c: 6}
214+
end
215+
216+
it 'uses the last key in the array if it appears multiple times' do
217+
arr = [:a, 1, :b, 2, :a, 3]
218+
hash = {}
219+
220+
@s.rb_hash_bulk_insert(arr.length, arr, hash)
221+
222+
hash.should == {a: 3, b: 2}
223+
end
224+
225+
it 'allows the array to be NULL if the length is zero' do
226+
hash = {}
227+
228+
@s.rb_hash_bulk_insert(0, nil, hash)
229+
230+
hash.should == {}
231+
end
232+
233+
it 'does not include any keys after the given length' do
234+
arr = [:a, 1, :b, 2, :c, 3, :d, 4]
235+
hash = {}
236+
237+
@s.rb_hash_bulk_insert(arr.length - 2, arr, hash)
238+
239+
hash.should == {a: 1, b: 2, c: 3}
240+
end
241+
242+
it 'does not modify the hash if the length is zero' do
243+
arr = []
244+
hash = {a: 1, b: 2}
245+
246+
@s.rb_hash_bulk_insert(arr.length, arr, hash)
247+
248+
hash.should == {a: 1, b: 2}
249+
end
250+
end
251+
197252
describe "rb_hash_size" do
198253
it "returns the size of the hash" do
199254
hsh = {fast: 'car', good: 'music'}

src/main/c/cext/hash.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,14 @@ 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+
void* unwrapped_hash = rb_tr_unwrap(hash);
105+
106+
for (long i = 0; i < n; i += 2) {
107+
polyglot_invoke(unwrapped_hash, "[]=", rb_tr_unwrap(values[i]), rb_tr_unwrap(values[i + 1]));
108+
}
109+
}
110+
103111
VALUE rb_hash_size(VALUE hash) {
104112
return RUBY_INVOKE(hash, "size");
105113
}

0 commit comments

Comments
 (0)