Skip to content

Commit

Permalink
implement rb_hash_bulk_insert
Browse files Browse the repository at this point in the history
  • Loading branch information
Th3-M4jor committed Nov 10, 2024
1 parent 8594c3a commit 75f5120
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Compatibility:
* Implement `rb_str_strlen()` (#3697, @Th3-M4jor).
* Support `Time.new` with String argument and error when invalid (#3693, @rwstauner).
* Implement `rb_enc_interned_str()` (#3703, @Th3-M4jor).
* Implement `rb_hash_bulk_insert()` (#3705, @Th3-M4jor).

Performance:

Expand Down
2 changes: 1 addition & 1 deletion lib/cext/include/truffleruby/truffleruby-abi-version.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
// $RUBY_VERSION must be the same as TruffleRuby.LANGUAGE_VERSION.
// $ABI_NUMBER starts at 1 and is incremented for every ABI-incompatible change.

#define TRUFFLERUBY_ABI_VERSION "3.2.4.6"
#define TRUFFLERUBY_ABI_VERSION "3.2.4.7"

#endif
8 changes: 8 additions & 0 deletions spec/ruby/optional/capi/ext/hash_spec.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,13 @@ VALUE hash_spec_compute_a_hash_code(VALUE self, VALUE seed) {
return ULONG2NUM(h);
}

VALUE hash_spec_rb_hash_bulk_insert(VALUE self, VALUE hash, VALUE array_len, VALUE array) {
long len = FIX2LONG(array_len);
VALUE *ptr = RARRAY_PTR(array);
rb_hash_bulk_insert(len, ptr, hash);
return hash;
}

void Init_hash_spec(void) {
VALUE cls = rb_define_class("CApiHashSpecs", rb_cObject);
rb_define_method(cls, "rb_hash", hash_spec_rb_hash, 1);
Expand Down Expand Up @@ -162,6 +169,7 @@ void Init_hash_spec(void) {
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
rb_define_method(cls, "compute_a_hash_code", hash_spec_compute_a_hash_code, 1);
rb_define_method(cls, "rb_hash_bulk_insert", hash_spec_rb_hash_bulk_insert, 3);
}

#ifdef __cplusplus
Expand Down
38 changes: 38 additions & 0 deletions spec/ruby/optional/capi/hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,44 @@
end
end

describe "rb_hash_bulk_insert" do
it 'inserts key-value pairs into the hash' do
arr = [:a, 1, :b, 2, :c, 3]
hash = {}

@s.rb_hash_bulk_insert(hash, arr.length, arr)

hash.should == {a: 1, b: 2, c: 3}
end

it 'overwrites existing keys' do
arr = [:a, 4, :b, 5, :c, 6]
hash = {a: 1, b: 2}

@s.rb_hash_bulk_insert(hash, arr.length, arr)

hash.should == {a: 4, b: 5, c: 6}
end

it 'does not include any keys after the given length' do
arr = [:a, 1, :b, 2, :c, 3, :d, 4]
hash = {}

@s.rb_hash_bulk_insert(hash, arr.length - 2, arr)

hash.should == {a: 1, b: 2, c: 3}
end

it 'does not modify the hash if the length is zero' do
arr = []
hash = {a: 1, b: 2}

@s.rb_hash_bulk_insert(hash, arr.length, arr)

hash.should == {a: 1, b: 2}
end
end

describe "rb_hash_size" do
it "returns the size of the hash" do
hsh = {fast: 'car', good: 'music'}
Expand Down
12 changes: 12 additions & 0 deletions src/main/c/cext/hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ void rb_hash_foreach(VALUE hash, int (*func)(VALUE key, VALUE val, VALUE arg), V
polyglot_invoke(RUBY_CEXT, "rb_hash_foreach", rb_tr_unwrap(hash), func, (void*)arg);
}

void rb_hash_bulk_insert(long n, const VALUE *values, VALUE hash) {
if (n % 2 != 0) {
rb_raise(rb_eArgError, "Expected an even number of array elements");
}

void* unwrapped_hash = rb_tr_unwrap(hash);

for (long i = 0; i < n; i += 2) {
polyglot_invoke(unwrapped_hash, "[]=", rb_tr_unwrap(values[i]), rb_tr_unwrap(values[i + 1]));
}
}

VALUE rb_hash_size(VALUE hash) {
return RUBY_INVOKE(hash, "size");
}
Expand Down

0 comments on commit 75f5120

Please sign in to comment.