Forum: Ruby Compiling Ruby Inline C code - resolving errors

386571a6fd12fc72ff39593da1af15c3?d=identicon&s=25 Martin Hansen (maasha)
on 2011-11-08 09:04
I am trying to get this Ruby inline C code http://pastie.org/2825882 to
work. The code works in vanilla C, but here I get errors and warnings.
What causes this error?

./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

Also, why do I get the following error?

./backtrack_inline.rb:73: error: too few arguments to function
'backtrack'

Inspecting the resulting C code ( http://pastie.org/2826036) I fail to
see anything wrong with the arguments. But I do also get the following
warnings:

./backtrack_inline.rb:73: warning: passing argument 1 of 'backtrack'
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 2 of 'backtrack'
makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 3 of 'backtrack'
makes integer from pointer without a cast


Cheers,


Martin
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2011-11-08 09:49
(Received via mailing list)
It is generally best to send these types of questions to a more targeted
medium, like writing the author directly or filing a support ticket on
github.

On Nov 8, 2011, at 00:04 , Martin Hansen wrote:

> I am trying to get this Ruby inline C code http://pastie.org/2825882 to
> work. The code works in vanilla C, but here I get errors and warnings.
> What causes this error?
>
> ./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

This one took me a bit...

    #define StringValuePtr(v) rb_string_value_ptr(&(v))

and you're using it in:

    char* s = StringValuePtr(rb_iv_get(self, "@seq"));

so you're essentially doing:

    char* s = rb_string_value_ptr(&rb_iv_get(self, "@seq"));

which you can't really do in C.

> Also, why do I get the following error?
>
> ./backtrack_inline.rb:73: error: too few arguments to function
> 'backtrack'

Because you're passing too few arguments to the function (6 to 7 arity
function):

static
 VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm,
VALUE _ins, VALUE _del)

vs:

    backtrack(ss, s + 1, p + 1, mm - 1, ins, del)))

Since you're not actually using self for anything, there is no reason
for this to be a registered method. You might want to add this to the
prefix section.

> Inspecting the resulting C code ( http://pastie.org/2826036) I fail to
> see anything wrong with the arguments. But I do also get the following
> warnings:
>
> ./backtrack_inline.rb:73: warning: passing argument 1 of 'backtrack'
> makes integer from pointer without a cast
> ./backtrack_inline.rb:73: warning: passing argument 2 of 'backtrack'
> makes integer from pointer without a cast
> ./backtrack_inline.rb:73: warning: passing argument 3 of 'backtrack'
> makes integer from pointer without a cast

This is simply because of the above lack of self, I assume.

I changed your code (with the above) like so:

    # above w/ prefixens
    builder.add_static "id_seq", 'rb_intern("@seq")', "ID"

    # in patscan:
    VALUE seq = rb_ivar_get(self, id_seq);
    char* s = StringValuePtr(seq);

and got '14' as the output (off by 1?).
386571a6fd12fc72ff39593da1af15c3?d=identicon&s=25 Martin Hansen (maasha)
on 2011-11-08 12:10
I was in doubt whether to use:

char* s = StringValuePtr(rb_iv_get(self, "@seq"));

or

char* s = RSTRING_PTR(rb_iv_get(self, "@seq"))

I see now that the first is plain wrong, but what about the latter? When
is that used?

I tried to apply the suggested changes, but the C code still have "VALUE
self" as first argument in the functions. How did you get rid of that?
24ad906535e7c0ea9355b6442233888a?d=identicon&s=25 Sylvester Keil (Guest)
on 2011-11-08 14:43
(Received via mailing list)
On Nov 8, 2011, at 12:10 PM, Martin Hansen wrote:

>
> I tried to apply the suggested changes, but the C code still have "VALUE
> self" as first argument in the functions. How did you get rid of that?

Did you change line 38 in http://pastie.org/2825882 from

"builder.c %{" to "builder.prefix %{"

?

If you don't define backtrack as an instance method, self will not be
expected to be passed as first argument.
386571a6fd12fc72ff39593da1af15c3?d=identicon&s=25 Martin Hansen (maasha)
on 2011-11-08 15:50
Sylvester Keil wrote in post #1030842:

How could I know that bulder.c -> builder.prefix changed the function an
instance method to a "function"? I am pretty desperate for some reading
- and examples - on this matter! Something modern (i. e. Ruby 1.9) and
something that is about inline C and not necessarily all of Ruby's API.

I changed the code and cleaned up a few things:

Ruby code: http://pastie.org/2831055
Inline code: http://pastie.org/2831058

Now I get a warning - and the wrong output:

/Users/maasha/.ruby_inline/Inline_Scan_5319.c: In function 'backtrack':
/Users/maasha/.ruby_inline/Inline_Scan_5319.c:38: warning: implicit
conversion shortens 64-bit value into a 32-bit value
false


Cheers,


Martin


> On Nov 8, 2011, at 12:10 PM, Martin Hansen wrote:
>
>>
>> I tried to apply the suggested changes, but the C code still have "VALUE
>> self" as first argument in the functions. How did you get rid of that?
>
> Did you change line 38 in http://pastie.org/2825882 from
>
> "builder.c %{" to "builder.prefix %{"
>
> ?
>
> If you don't define backtrack as an instance method, self will not be
> expected to be passed as first argument.
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2011-11-08 20:49
(Received via mailing list)
On Nov 8, 2011, at 03:10 , Martin Hansen wrote:

> I was in doubt whether to use:
>
> char* s = StringValuePtr(rb_iv_get(self, "@seq"));
>
> or
>
> char* s = RSTRING_PTR(rb_iv_get(self, "@seq"))
>
> I see now that the first is plain wrong, but what about the latter? When
> is that used?

No... it is NOT plain wrong. Trying to use the result of a return value
as an lvalue is plain wrong. By putting it in it's own variable, you can
use StringValuePtr just fine (and should).

> I tried to apply the suggested changes, but the C code still have "VALUE
> self" as first argument in the functions. How did you get rid of that?

As Sylvester pointed out, you missed my suggestion to make that function
a prefixed function.
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2011-11-08 21:37
(Received via mailing list)
On Nov 8, 2011, at 06:50 , Martin Hansen wrote:

> Sylvester Keil wrote in post #1030842:
>
> How could I know that bulder.c -> builder.prefix changed the function an
> instance method to a "function"?

Well, first, because I showed you:

>> Because you're passing too few arguments to the function (6 to 7 arity
function):
>>
>> static
>> VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm, VALUE
_ins, VALUE _del)
>>
>> vs:
>>
>>    backtrack(ss, s + 1, p + 1, mm - 1, ins, del)))
>>
>> Since you're not actually using self for anything, there is no reason for this
to be a registered method. You might want to add this to the prefix section.

> I am pretty desperate for some reading
> - and examples - on this matter! Something modern (i. e. Ruby 1.9) and
> something that is about inline C and not necessarily all of Ruby's API.

If you find the documentation insufficient in some way, please file a
ticket. I can only improve what I  know about.

> false
I don't. Here is what I wound up with:

#!/usr/bin/env ruby

require 'pp'
require 'inline'

class Scan
  def initialize(seq)
    @seq = seq
  end

  inline do |builder|
    builder.prefix %{
      #define MATCH(A,B) ((equal[(A)] & equal[(B)]) != 0)
    }

    builder.add_static "id_seq", 'rb_intern("@seq")', "ID"

    builder.prefix %{
      int equal[256] = {
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 1,14, 4,11, 0, 0, 8, 7, 0, 0,10, 0, 5,15, 0,
          0, 0, 9,12, 2, 2,13, 3, 0, 6, 0, 0, 0, 0, 0, 0,
          0, 1,14, 4,11, 0, 0, 8, 7, 0, 0,10, 0, 5,15, 0,
          0, 0, 9,12, 2, 2,13, 3, 0, 6, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
          0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
      };
    }

    # ss is the start of the string, used only for reporting the match
endpoints.
    builder.prefix %{
      int backtrack(char* ss, char* s, char* p, int mm, int ins, int
del)
      {
          int r = 0;

          while (*s && MATCH(*s, *p)) ++s, ++p;    // OK to always match
longest segment

          if (!*p)
              return (s - ss) - 1;
          else
          {
              if (mm && *s && *p && (r = backtrack(ss, s + 1, p + 1, mm
- 1, ins, del))) return r;
              if (ins && *s &&      (r = backtrack(ss, s + 1, p, mm, ins
- 1, del)))     return r;
              if (del && *p &&      (r = backtrack(ss, s, p + 1, mm,
ins, del - 1)))     return r;
          }

          return 0;
      }
    }

    # Find all occurrences of p starting at any position in s, with at
most
    # mm mismatches, ins insertions and del deletions.
    builder.c %{
      int patscan(char* p, int mm, int ins, int del)
      {
          VALUE seq = rb_ivar_get(self, id_seq);
          char* s = StringValuePtr(seq);
          char* ss;
          int   nnd;

          for (ss = s; *s; ++s)
          {
              nnd = backtrack(ss, s, p, mm, ins, del);

              if (nnd)
                 return nnd;
          }
       }
    }
  end
end

seq = "tcatcgagtcatcgatcgatcgatcgatcga"
pat = "gtcatcga"

scanner = Scan.new(seq)

puts scanner.patscan(pat, 0, 0, 0)
386571a6fd12fc72ff39593da1af15c3?d=identicon&s=25 Martin Hansen (maasha)
on 2011-11-09 10:25
OK, it works now. However, I still get a warning:

    warning: implicit conversion shortens 64-bit value into a 32-bit
value

The offending line is return (s - ss) - 1;  where I expect an int. How
to make this portable?

And I'd like to contribute with suggestions and ideas. Where is the best
place? Github, rubyforge, a mailing list?

Many thanks!


Martin
24ad906535e7c0ea9355b6442233888a?d=identicon&s=25 Sylvester Keil (Guest)
on 2011-11-09 10:50
(Received via mailing list)
On Nov 9, 2011, at 10:25 AM, Martin Hansen wrote:

> OK, it works now. However, I still get a warning:
>
>    warning: implicit conversion shortens 64-bit value into a 32-bit
> value
>
> The offending line is return (s - ss) - 1;  where I expect an int. How
> to make this portable?

IIRC s and ss are pointers to a (the same?) string, right? If they are,
then this difference here will easily fit into 32bit so you could cast
to int explicitly:

return (int)((s - ss) - 1)

Or you could change the function definition to return a long instead of
int and return a 64bit value on 64bit systems.
386571a6fd12fc72ff39593da1af15c3?d=identicon&s=25 Martin Hansen (maasha)
on 2011-11-09 14:48
> IIRC s and ss are pointers to a (the same?) string, right? If they are,
> then this difference here will easily fit into 32bit so you could cast
> to int explicitly:
>
> return (int)((s - ss) - 1)
>
> Or you could change the function definition to return a long instead of
> int and return a 64bit value on 64bit systems.

Yes, that will do. Thanks!


Martin
5a837592409354297424994e8d62f722?d=identicon&s=25 Ryan Davis (Guest)
on 2011-11-09 22:54
(Received via mailing list)
On Nov 9, 2011, at 01:25 , Martin Hansen wrote:

> OK, it works now. However, I still get a warning:
>
>    warning: implicit conversion shortens 64-bit value into a 32-bit
> value
>
> The offending line is return (s - ss) - 1;  where I expect an int. How
> to make this portable?

It shouldn't expect an int. You're returning a measurement. They can't
be negative. You should be returning a size_t if anything.

> And I'd like to contribute with suggestions and ideas. Where is the best
> place? Github, rubyforge, a mailing list?

All my stuff is mirrored to github.
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.