[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

How to correctly create ruby objects from C extensions.

Brian Schröder

1/27/2005 2:53:00 PM

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


9 Answers

Yoshiki Tsunesada

1/27/2005 4:05:00 PM

0

On Thu, 27 Jan 2005 23:52:48 +0900, Brian Schröder wrote:
> 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/...

> 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.



Asbjørn Reglund Thorsen

1/27/2005 4:56:00 PM

0

Lyle Johnson

1/27/2005 5:37:00 PM

0

On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen
<asbjoert@ifi.uio.no> wrote:

> 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



Asbjørn Reglund Thorsen

1/27/2005 5:42:00 PM

0

Charles Mills

1/27/2005 5:50:00 PM

0

Brian Schröder wrote:
> 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

510046470588-0001

1/27/2005 8:05:00 PM

0

Brian =?ISO-8859-15?Q?Schr=F6der?= writes:

> 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


timsuth

1/27/2005 10:20:00 PM

0

In article <d4cf71b0050127093664c9bf7b@mail.gmail.com>, Lyle Johnson wrote:
>On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen
><asbjoert@ifi.uio.no> wrote:
>
>> 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().

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[i] = 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.

Charles Mills

1/27/2005 10:42:00 PM

0

Tim Sutherland wrote:
> In article <d4cf71b0050127093664c9bf7b@mail.gmail.com>, Lyle Johnson
wrote:
> >On Fri, 28 Jan 2005 01:56:24 +0900, Asbjørn Reglund Thorsen
> ><asbjoert@ifi.uio.no> wrote:
> >
(...)
> 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[i] = 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[i] = rb_float_new((double) p(i+1)));
}


-Charlie

Asbjørn Reglund Thorsen

1/28/2005 9:22:00 AM

0