How to correctly create ruby objects from C extensions.

B

Brian Schröder

Hello Group,

I'm asking myself what is the way to create a ruby object correctly from
a C extension. As I've extracted from ruby.h and README.EXT the things I
can come up with are:

rb_funcall(rb_const_get(self, rb_intern('Complex')), rb_intern('new'), 2, rb_float_new(real), rb_float_new(imag));
// which is impressively complicated and long.

rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

This seems to be really complicated just for wrapping my C complex
numbers into ruby Complex numbers.

So as I always have seen that things are easier in ruby, what should I
do?

Thanks a lot,

Brian
 
Y

Yoshiki Tsunesada

Hello Group,

I'm asking myself what is the way to create a ruby object correctly from
a C extension. As I've extracted from ruby.h and README.EXT the things I
can come up with are:

See for example http://www.ruby-doc.org/doxygen/1.8.1/index.html
rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

To get char* pointer from Ruby string,
char *p;
p = StringValuePtr(rubyString);
To create Ruby string from C string,
return rb_str_new( (char pointer), (length));
or
return rb_str_new2("a string");
or with rb_str_new3(), 4(), 5() and other functions.
 
A

Asbjørn Reglund Thorsen

---259931839-602644157-1106844967=:1262
Content-Type: MULTIPART/MIXED; BOUNDARY="-259931839-602644157-1106844967=:1262"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---259931839-602644157-1106844967=:1262
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below):=20
"PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.


(This code is used for typemapping in SWIG/Python)
%typemap(out) Ptv_double& {
Ptv_double& p=3D (*$1);
int size =3D p.size();
$result =3D PyList_New(size);
for (int i=3D0; i<size; i++)
PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));
}

Can anyone please help ?



</asbj=F8rn>































---259931839-602644157-1106844967=:1262--
---259931839-602644157-1106844967=:1262--
 
L

Lyle Johnson

I am quite new to extending Ruby, and I have read the README.EXT.
I am wondering how to translate (from the code below):
"PyList_SetItem($result, i, PyFloat_FromDouble((double) p(i+1)));"
Into Extending Ruby syntax.

The (roughly) equivalent code in a Ruby extension would be:

$result = rb_ary_new2(size);
for (int i = 0; i < size; i++)
rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

Hope this helps,

Lyle
 
A

Asbjørn Reglund Thorsen

---259931839-127852608-1106847681=:1262
Content-Type: MULTIPART/MIXED; BOUNDARY="-259931839-127852608-1106847681=:1262"

This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.

---259931839-127852608-1106847681=:1262
Content-Type: TEXT/PLAIN; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: QUOTED-PRINTABLE

Thank you Lyle !! It really helps. :)
Think I am getting the hang of it now.

The (roughly) equivalent code in a Ruby extension would be:

$result =3D rb_ary_new2(size);
for (int i =3D 0; i < size; i++)
rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

Hope this helps,

Lyle
---259931839-127852608-1106847681=:1262--
---259931839-127852608-1106847681=:1262--
 
C

Charles Mills

Brian said:
Hello Group,

I'm asking myself what is the way to create a ruby object correctly from
a C extension. As I've extracted from ruby.h and README.EXT the things I
can come up with are:

rb_funcall(rb_const_get(self, rb_intern('Complex')),
rb_intern('new'), 2, rb_float_new(real), rb_float_new(imag));
// which is impressively complicated and long.
You could write a function like


/* initialize these static variables in your *_init() function */
static VALUE cComplex;
static ID id_new;

static VALUE
complex_new(double real, double imag)
{
return rb_funcall(cComplex, id_new, 2, rb_float_new(real),
rb_float_new(imag));
}

Since the complex class is implemented in ruby there is no
rb_complex_new().
rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.
You can use the ruby string functions and then call
StringValueCStr(ruby_string).
This seems to be really complicated just for wrapping my C complex
numbers into ruby Complex numbers.

I think it would be nice if ruby had a COMPLEX_T - for both efficency
and for writing C extensions. On 64 bit systems it is easy to add
this, but on 32 bit systems it would increase the size of all ruby
objects unless you use a pointer to a second structure.
But, considering that even C has a built in complex type, I think it
would be worth while.
So as I always have seen that things are easier in ruby, what should I
do?
Use ruby ;)

-Charlie
 
K

klaus schilling

Brian said:
rb_eval_string(constructing_string)
// Which is ugly because of eval and because of C string functions.

eval is nowhere near ugly, it's the best invention since sliced bread

Klaus Schilling
 
T

Tim Sutherland

The (roughly) equivalent code in a Ruby extension would be:

$result = rb_ary_new2(size);
for (int i = 0; i < size; i++)
rb_ary_store($result, i, rb_float_new((double) p(i+1)));

Note that in Ruby you construct an Array instance with a certain
initial size by calling rb_ary_new2(size), and then you set the array
items by calling rb_ary_store(). Also, the function for constructing a
Ruby Float object from a C double is rb_float_new().

As an alternative to rb_ary_store(), you can access the buffer underlying
the Array directly:

$result = rb_ary_new2(size);
for (int i = 0; i < size; ++i)
RARRAY($result)->ptr = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.
 
C

Charles Mills

Tim said:
)
As an alternative to rb_ary_store(), you can access the buffer underlying
the Array directly:

$result = rb_ary_new2(size);
for (int i = 0; i < size; ++i)
RARRAY($result)->ptr = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.


There is a gotcha to this though.
rb_ary_new2(size) returns an array with length==0 and capacity==size.
The example you give above never increases length.
You could fix this with
RARRAY($result)->len = size;
However, this is also a gotcha. If you put it before the loop then the
array is filled with a bunch of garabage references which will crash
Ruby if the GC is run when rb_float_new() is called. If you put it
after he loop then all those floats you create could be destroyed by
the GC, causing Ruby to crash later.
rb_ary_store() is the simplest and safest solution. You could also do:

$result = rb_ary_new2(size);
for ( ; RARRAY($result)->len < size; RARRAY($result)->len++) {
int i = RARRAY($result)->len;
RARRAY($result)->ptr = rb_float_new((double) p(i+1)));
}


-Charlie
 
A

Asbjørn Reglund Thorsen

Thank you all for the response. :)

I think comp.lang.ruby is a great newsgroup with friendly and
highly competent people. I really enjoy reading the postings of my
interesst, and that`s a lot. I spend nearly an hour reading this newsgroup
each day, and have allready posted at least 3 mail to it myselfe.

I am missing a site for n00bs to program extending Ruby though, does there
exist any ? I have read README.EXT and I have bought the wonderful
Pickaxe2.

What about "extending" the Ruby exam site
(http://www.rubygarden.org/ruby?RubyExam) with an "extending Ruby" part ?

Tim said:
)
As an alternative to rb_ary_store(), you can access the buffer underlying
the Array directly:

$result = rb_ary_new2(size);
for (int i = 0; i < size; ++i)
RARRAY($result)->ptr = rb_float_new((double) p(i+1)));

The latter is faster since it doesn't have to check things like
- 'Do we need to increase the buffer size'
- 'Is the buffer shared with another Array'
- 'Is the Array frozen'
...etc.


There is a gotcha to this though.
rb_ary_new2(size) returns an array with length==0 and capacity==size.
The example you give above never increases length.
You could fix this with
RARRAY($result)->len = size;
However, this is also a gotcha. If you put it before the loop then the
array is filled with a bunch of garabage references which will crash
Ruby if the GC is run when rb_float_new() is called. If you put it
after he loop then all those floats you create could be destroyed by
the GC, causing Ruby to crash later.
rb_ary_store() is the simplest and safest solution. You could also do:

$result = rb_ary_new2(size);
for ( ; RARRAY($result)->len < size; RARRAY($result)->len++) {
int i = RARRAY($result)->len;
RARRAY($result)->ptr = rb_float_new((double) p(i+1)));
}


-Charlie
 

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

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top