Skip to content

Commit 2aafcec

Browse files
committed
[GR-19797] Implement rb_check_symbol_cstr.
PullRequest: truffleruby/1165
2 parents 25b684e + a4d241e commit 2aafcec

File tree

6 files changed

+52
-12
lines changed

6 files changed

+52
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Compatibility:
4343
* Implemented `keyword_init: true` for `Struct.new` (#1789, @XrXr).
4444
* Implemented `MatchData#dup` (#1792, @XrXr).
4545
* Implemented a native storage strategy for arrays to allow better C extension compatibility.
46+
* Implemented `rb_check_symbol_cstr` (#1814).
4647

4748
Performance:
4849

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ VALUE symbol_spec_rb_intern_str(VALUE self, VALUE str) {
5151
return ID2SYM(rb_intern_str(str));
5252
}
5353

54+
VALUE symbol_spec_rb_check_symbol_cstr(VALUE self, VALUE str) {
55+
return rb_check_symbol_cstr(RSTRING_PTR(str), RSTRING_LEN(str), rb_enc_get(str));
56+
}
57+
5458
VALUE symbol_spec_rb_is_class_id(VALUE self, VALUE sym) {
5559
return rb_is_class_id(SYM2ID(sym)) ? Qtrue : Qfalse;
5660
}
@@ -79,6 +83,7 @@ void Init_symbol_spec(void) {
7983
rb_define_method(cls, "rb_id2name", symbol_spec_rb_id2name, 1);
8084
rb_define_method(cls, "rb_id2str", symbol_spec_rb_id2str, 1);
8185
rb_define_method(cls, "rb_intern_str", symbol_spec_rb_intern_str, 1);
86+
rb_define_method(cls, "rb_check_symbol_cstr", symbol_spec_rb_check_symbol_cstr, 1);
8287
rb_define_method(cls, "rb_is_class_id", symbol_spec_rb_is_class_id, 1);
8388
rb_define_method(cls, "rb_is_const_id", symbol_spec_rb_is_const_id, 1);
8489
rb_define_method(cls, "rb_is_instance_id", symbol_spec_rb_is_instance_id, 1);

spec/ruby/optional/capi/symbol_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,19 @@
7171
end
7272
end
7373

74+
describe "rb_check_symbol_cstr" do
75+
it "returns a Symbol if a Symbol already exists for the given C string" do
76+
sym = :test_symbol
77+
@s.rb_check_symbol_cstr('test_symbol').should == sym
78+
end
79+
80+
it "returns nil if the Symbol does not exist yet and does not create it" do
81+
str = "symbol_does_not_exist_#{Object.new.object_id}_#{rand}"
82+
@s.rb_check_symbol_cstr(str).should == nil # does not create the Symbol
83+
@s.rb_check_symbol_cstr(str).should == nil
84+
end
85+
end
86+
7487
describe "rb_is_const_id" do
7588
it "returns true given a const-like symbol" do
7689
@s.rb_is_const_id(:Foo).should == true

src/main/c/cext/ruby.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3283,7 +3283,8 @@ ID rb_check_id_cstr(const char *ptr, long len, rb_encoding *enc) {
32833283
}
32843284

32853285
VALUE rb_check_symbol_cstr(const char *ptr, long len, rb_encoding *enc) {
3286-
rb_tr_error("rb_check_symbol_cstr not implemented");
3286+
VALUE str = rb_enc_str_new(ptr, len, enc);
3287+
return RUBY_CEXT_INVOKE("rb_check_symbol_cstr", str);
32873288
}
32883289

32893290
int rb_econv_has_convpath_p(const char* from_encoding, const char* to_encoding) {

src/main/java/org/truffleruby/cext/CExtNodes.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,4 +1589,15 @@ protected Object unwrapFunction() {
15891589
return new ValueWrapperManager.WrapperFunction();
15901590
}
15911591
}
1592+
1593+
@CoreMethod(names = "rb_check_symbol_cstr", onSingleton = true, required = 1)
1594+
public abstract static class RbCheckSymbolCStrNode extends CoreMethodArrayArgumentsNode {
1595+
1596+
@Specialization
1597+
protected DynamicObject checkSymbolCStr(DynamicObject str) {
1598+
final DynamicObject sym = getContext().getSymbolTable().getSymbolIfExists(rope(str));
1599+
return sym == null ? nil() : sym;
1600+
}
1601+
1602+
}
15921603
}

src/main/java/org/truffleruby/core/symbol/SymbolTable.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -105,29 +105,38 @@ public DynamicObject getSymbol(String string) {
105105

106106
@TruffleBoundary
107107
public DynamicObject getSymbol(Rope rope) {
108-
if (rope instanceof NativeRope) {
109-
rope = ((NativeRope) rope).toLeafRope();
110-
}
111-
112-
if (rope.isAsciiOnly() && rope.getEncoding() != USASCIIEncoding.INSTANCE) {
113-
rope = rope.withEncoding(USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT);
114-
}
115-
116-
final RopeKey ropeKey = new RopeKey(rope, hashing);
117-
108+
final RopeKey ropeKey = createRopeKey(rope);
118109
final DynamicObject symbol = symbolMap.get(ropeKey);
119110
if (symbol != null) {
120111
return symbol;
121112
}
122113

123-
final Rope cachedRope = ropeCache.getRope(rope);
114+
final Rope cachedRope = ropeCache.getRope(ropeKey.getRope());
124115
final DynamicObject newSymbol = createSymbol(cachedRope);
125116
// Use a RopeKey with the cached Rope in symbolMap, since the Symbol refers to it and so we
126117
// do not keep rope alive unnecessarily.
127118
final RopeKey cachedRopeKey = new RopeKey(cachedRope, hashing);
128119
return symbolMap.addInCacheIfAbsent(cachedRopeKey, newSymbol);
129120
}
130121

122+
@TruffleBoundary
123+
public DynamicObject getSymbolIfExists(Rope rope) {
124+
final RopeKey ropeKey = createRopeKey(rope);
125+
return symbolMap.get(ropeKey);
126+
}
127+
128+
private RopeKey createRopeKey(Rope rope) {
129+
if (rope instanceof NativeRope) {
130+
rope = ((NativeRope) rope).toLeafRope();
131+
}
132+
133+
if (rope.isAsciiOnly() && rope.getEncoding() != USASCIIEncoding.INSTANCE) {
134+
rope = rope.withEncoding(USASCIIEncoding.INSTANCE, CodeRange.CR_7BIT);
135+
}
136+
137+
return new RopeKey(rope, hashing);
138+
}
139+
131140
private DynamicObject createSymbol(Rope cachedRope) {
132141
final String string = RopeOperations.decodeOrEscapeBinaryRope(cachedRope);
133142
return Layouts.SYMBOL.createSymbol(

0 commit comments

Comments
 (0)