From 6e1e631cd2c11aaaafc4192710793d8028cdd086 Mon Sep 17 00:00:00 2001 From: Jose Narvaez Date: Wed, 31 Jan 2024 17:45:10 +0000 Subject: [PATCH] Add C API rb_enc_interned_str_cstr function Co-authored-by: Thomas Marshall --- CHANGELOG.md | 1 + lib/cext/ABI_check.txt | 2 +- spec/ruby/optional/capi/ext/string_spec.c | 6 ++++++ spec/ruby/optional/capi/string_spec.rb | 24 +++++++++++++++++++++++ src/main/c/cext/string.c | 5 +++++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 74fe2c50306f..aff41c93ad12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Compatibility: * Do not autosplat a proc that accepts a single positional argument and keywords (#3039, @andrykonchin). * Support passing anonymous * and ** parameters as method call arguments (#3039, @andrykonchin). * Handle either positional or keywords arguments by default in `Struct.new` (#3039, @rwstauner). +* Add `rb_enc_interned_str_cstr` function (#3408, @goyox86, @thomasmarshall). Performance: diff --git a/lib/cext/ABI_check.txt b/lib/cext/ABI_check.txt index f599e28b8ab0..b4de39476753 100644 --- a/lib/cext/ABI_check.txt +++ b/lib/cext/ABI_check.txt @@ -1 +1 @@ -10 +11 diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index 702620b9dacb..390c5a8ab2be 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -584,6 +584,11 @@ static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) { return rb_str_unlocktmp(str); } +static VALUE string_spec_rb_enc_interned_str_cstr(VALUE self, VALUE str, VALUE enc) { + rb_encoding *e = rb_to_encoding(enc); + return rb_enc_interned_str_cstr(RSTRING_PTR(str), e); +} + void Init_string_spec(void) { VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject); rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2); @@ -685,6 +690,7 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_str_catf", string_spec_rb_str_catf, 1); rb_define_method(cls, "rb_str_locktmp", string_spec_rb_str_locktmp, 1); rb_define_method(cls, "rb_str_unlocktmp", string_spec_rb_str_unlocktmp, 1); + rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 3a47fa9762fd..8090926b1f42 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -1227,4 +1227,28 @@ def inspect -> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string') end end + + describe "rb_enc_interned_str_cstr" do + it "returns a frozen string" do + str = "hello\0not used" + val = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII) + + val.should.is_a?(String) + val.encoding.should == Encoding::US_ASCII + val.should.frozen? + end + + it "returns the same frozen string" do + str = "hello\0not used" + val1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII) + val2 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII) + + val1.object_id.should == val2.object_id + + val1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII) + val2 = @s.rb_enc_interned_str_cstr(str, Encoding::UTF_8) + + val1.object_id.should != val2.object_id + end + end end diff --git a/src/main/c/cext/string.c b/src/main/c/cext/string.c index be58ad1bc573..fa7bad955154 100644 --- a/src/main/c/cext/string.c +++ b/src/main/c/cext/string.c @@ -437,3 +437,8 @@ long rb_str_coderange_scan_restartable(const char *s, const char *e, rb_encoding *cr = ENC_CODERANGE_VALID; return e - s; } + +VALUE rb_enc_interned_str_cstr(const char *ptr, rb_encoding *enc) { + VALUE string = rb_enc_str_new_cstr(ptr, enc); + return rb_fstring(string); +}