How can I call String#replace (rb_str_replace()) in C API?

J

James Masters

Hi all,

I am wrapping a C++ API using SWIG for Ruby and in some cases strings
need to be allocated and passed to the wrapped function where the
value of the string itself will need to be modified within the C/C++
code generated by SWIG. Specifically, I need the String#object_id to
stay the same and just have the contents change.

How can I do this with the Ruby C API? I looked at rb_str_replace in
string.c; however, that is not a public function in the C API. After
searching I found a few postings on this topic, I found that
rb_funcall could be initiated but this seems to add some overhead
which affects performance.

I'm really just looking for a way to take a Ruby string VALUE and
replace the contents of that object with a C string in the most
efficient method possible. Can someone help me in doing this or at
least point me in the right direction?

Thanks,
-James
 
C

Caleb Clausen

How can I do this with the Ruby C API? I looked at rb_str_replace in
string.c; however, that is not a public function in the C API. After

Are you using ruby 1.8 or 1.9? 1.9 makes rb_str_replace non-static and
declares it in intern.h. I don't see it in 1.8's intern.h, so its very
likely static there. If you're on 1.9 I say just go ahead and call it.
If on 1.8, you're looking at calling a static function from the
outside which is difficult and icky at best.

Official policy is that only funcs in ruby.h are considered part of
the public api, and anything else shouldn't be used. Actually obeying
this would mean that such useful and necessary utilities as rb_str_new
and rb_ary_new couldn't be used by extensions, so it has to be taken
with a gain of salt. I think you should be fairly safe with
rb_str_replace. (Tho ruby maintainers are in effect reserving the
right to change its calling conventions without warning or regret, it
is unlikely they will do so.)
searching I found a few postings on this topic, I found that
rb_funcall could be initiated but this seems to add some overhead
which affects performance.

Yeah, that's slow. And klutsy. Unfortunately, it is what you have to
do to call a ruby method most of the time :(. If you're on 1.8, this
is probably your best option.
I'm really just looking for a way to take a Ruby string VALUE and
replace the contents of that object with a C string in the most
efficient method possible. Can someone help me in doing this or at
least point me in the right direction?

One other option is to fiddle directly with the fields of struct
RString, but I don't recommend that unless you're really dedicated.
 
J

James Masters

How can I do this with the Ruby C API?  I looked at rb_str_replace in
Are you using ruby 1.8 or 1.9? 1.9 makes rb_str_replace non-static and
declares it in intern.h. I don't see it in 1.8's intern.h, so its very

Unfortunately I am using Ruby 1.8.
One other option is to fiddle directly with the fields of struct
RString, but I don't recommend that unless you're really dedicated.

I am thinking about doing this but it would be a pain and probably
dangerous as you have mentioned. I can probably put something
together with good performance by tweaking the pointer location and
string length but I'll need to get more familiar with the Ruby code
before I attempt something like this. One good thing is that I am
creating the Ruby string to be used as the replacement myself in the C+
+ code on my own so I shouldn't need to do type checking. If anyone
has any pointers on where to find some of the underlying Ruby C data
structures (e.g. ELTS_SHARED and STR_ASSOC flags) then I could use it.

Thanks for your reply... it was helpful to at least confirm the issue
at hand.
 
C

Caleb Clausen

Unfortunately I am using Ruby 1.8.


I am thinking about doing this but it would be a pain and probably
dangerous as you have mentioned. I can probably put something
together with good performance by tweaking the pointer location and
string length but I'll need to get more familiar with the Ruby code
before I attempt something like this. One good thing is that I am
creating the Ruby string to be used as the replacement myself in the C+
+ code on my own so I shouldn't need to do type checking. If anyone
has any pointers on where to find some of the underlying Ruby C data
structures (e.g. ELTS_SHARED and STR_ASSOC flags) then I could use it.

BEWARE: if you go this route, you MUST interface correctly with ruby's
garbage collector, or else your program will crash mysteriously in
unlikely places. Ruby likes to control not only where struct RString
is allocated, but also the string buffer it points to. The apis for
using those internal memory management facilities are definitely not
public, so this gets icky real fast. I've never tried to do this and
can't offer any advise about how to fool the garbage collector into
thinking that a string buffer you allocated is actually kosher.

You're better off trying to call rb_str_replace even tho it is static.
Or maybe porting your app to 1.9. (Which is a nontrivial effort.)

I can't offer any help with those flags either, other than "Use the
source, Luke.". The GC issues are likely to be the biggest challenge.

Good luck!
 
J

James Masters

I'm really just looking for a way to take a Ruby string VALUE and
BEWARE: if you go this route, you MUST interface correctly with ruby's
garbage collector, or else your program will crash mysteriously in
unlikely places. Ruby likes to control not only where struct RString
is allocated, but also the string buffer it points to. The apis for
using those internal memory management facilities are definitely not
public, so this gets icky real fast. I've never tried to do this and
can't offer any advise about how to fool the garbage collector into
thinking that a string buffer you allocated is actually kosher.

You're better off trying to call rb_str_replace even tho it is static.
Or maybe porting your app to 1.9. (Which is a nontrivial effort.)

I can't offer any help with those flags either, other than "Use the
source, Luke.". The GC issues are likely to be the biggest challenge.

Thanks for the advice :). Yeah, I was actually thinking about
allocating another Ruby string and doing something similar to what
rb_str_replace does to avoid crashing and GC issues. But it will
still be tricky. I wish that this was easier...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top