使用RubyInline gem创建C结构

时间:2015-04-18 17:27:34

标签: c ruby

我有一个需要显示蒙特卡罗SIM卡结果的Rails应用程序,而且Ruby第一次没有足够快的速度满足我的需求。所以,我开始四处寻找是否可以在C中重写我的模拟并在Ruby中使用这些结果,并且一些谷歌搜索出现了RubyInline gem,可以直接在Ruby中编写更快的C代码。做一些简单的东西很有用,例如,用Ruby和C编写的一些基本函数:

class FasterFunctions
  inline do |builder|
    builder.c '
    double rand_sum(int trials)
    {
      double sum = 0.0;
      for (int i = 0; i<trials; i++)
      {
        sum += (double)rand()/(double)RAND_MAX;
      }
      return sum;
    }'

    builder.c '
    long loop_sum(long trials)
    {
      long sum = 0;
      for (long i = 0; i<trials; i++)
      {
        sum+=i;
      }
      return sum;
    }'
  end
end

#the C version is 4 orders of magnitude faster
trials = 1_000_000
ruby_sum = 0
trials.times {|i| ruby_sum += i}
c_sum = FasterRand.new.loop_sum(trials)

# the C version is 1 order of magnitude faster
ruby_sum = 0.0
trials.times {ruby_sum += rand}
c_sum = FasterRand.new.rand_sum(trials)

所以,很好,它肯定会加速我的SIM卡,因为它几乎只是生成随机数并根据这些结果添加内容。不幸的是,除了这样的基本内容之外,我无法弄清楚如何实际编写我的程序。我需要传递一些结构来充当状态变量,所以业务的第一顺序是弄清楚如何创建一个C结构。阅读the documentation,似乎应该相当简单。

  

访问者(方法,类型,成员=方法)

     

为包裹的C结构成员添加读写器   Data_Wrap_Struct。 method是给出访问者类型的ruby名称   是C型。除非C成员名称被成员覆盖,否则   方法名称用作结构成员。

builder.struct_name = 'MyStruct' 
builder.accessor :title,        'char *' 
builder.accessor :stream_index, 'int',   :index

文档对我来说并不完全清楚,但我认为我会像以前一样把它放在一个类中并执行以下操作来访问它:

class MyStructClass
  inline do |builder|
    builder.struct_name = 'MyStruct'
    builder.accessor :title, 'char *'
    builder.accessor :stream_index, 'int', :index
  end
end

#possible this
struct = MyStructClass.new.MyStruct
struct.title = 'A Title'

#or maybe
struct = MyStructClass.new
struct.title = 'A Title'

不幸的是,我甚至无法做到那么远

  。

* / rbenv /版本/ 2.1.2 / LIB /红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / LIB / inline.rb:456:3:   错误:使用未声明的标识符         &#39; MYSTRUCT&#39; MyStruct *指针; ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:456:13:错误:使用未声明的标识符         &#39;指针&#39; MyStruct *指针;               ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:458:35:错误:使用未声明的标识符         &#39;指针&#39; Data_Get_Struct(self,MyStruct,pointer);                                     ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:6:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \        ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:458:25:错误:使用未声明的标识符         &#39; MYSTRUCT&#39; Data_Get_Struct(self,MyStruct,pointer);                           ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:15:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \                 ^   * / rbenv /版本/ 2.1.2 / lib中/红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / lib目录/ inline.rb:458:3:   错误:期望表达式Data_Get_Struct(self,MyStruct,pointer);   ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:20:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \                      ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:460:23:错误:使用未声明的标识符         &#39;指针&#39; return(rb_str_new2(pointer-&gt; title));                         ^   * / .rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / intern.h:786:27:注意:从宏扩展&r; rb_str_new_cstr&#39;       (__builtin_constant_p(str))? \                             ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:460:23:错误:使用未声明的标识符         &#39;指针&#39;   * / .rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / intern.h:787:14:注意:从宏扩展&r; rb_str_new_cstr&#39;           rb_str_new((str),(long)strlen(str)):\                       ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:460:23:错误:使用未声明的标识符         &#39;指针&#39;   * / .rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / intern.h:787:33:注意:从宏扩展&r; rb_str_new_cstr&#39;           rb_str_new((str),(long)strlen(str)):\                                          ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:460:23:错误:使用未声明的标识符         &#39;指针&#39;   * / .rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / intern.h:788:18:注意:从宏扩展&r; rb_str_new_cstr&#39;           rb_str_new_cstr(STR); \                           ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:460:10:错误:返回&#39; void&#39;来自a         功能与不兼容的结果类型&#39; VALUE&#39; (又名&#39; unsigned long&#39;)return(rb_str_new2(pointer-&gt; title));            ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~   * / rbenv /版本/ 2.1.2 / lib中/红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / lib目录/ inline.rb:478:3:   错误:使用未声明的标识符         &#39; MYSTRUCT&#39; MyStruct *指针; ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:478:13:错误:使用未声明的标识符         &#39;指针&#39; MyStruct *指针;               ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:480:35:错误:使用未声明的标识符         &#39;指针&#39; Data_Get_Struct(self,MyStruct,pointer);                                     ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:6:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \        ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:480:25:错误:使用未声明的标识符         &#39; MYSTRUCT&#39; Data_Get_Struct(self,MyStruct,pointer);                           ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:15:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \                 ^   * / rbenv /版本/ 2.1.2 / lib中/红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / lib目录/ inline.rb:480:3:   错误:期望表达式Data_Get_Struct(self,MyStruct,pointer);   ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:20:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \                      ^   * / rbenv /版本/ 2.1.2 / lib中/红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / lib目录/ inline.rb:482:3:   错误:使用未声明的标识符         &#39;指针&#39; pointer-&gt; title = StringValuePtr(value); ^   * / rbenv /版本/ 2.1.2 / LIB /红宝石/宝石/ 2.1.0 /宝石/了RubyInline-3.12.4 / LIB / inline.rb:456:3:   错误:使用未声明的标识符         &#39; MYSTRUCT&#39; MyStruct *指针; ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:456:13:错误:使用未声明的标识符         &#39;指针&#39; MyStruct *指针;               ^   * / .rbenv / versions / 2.1.2 / lib / ruby​​ / gems / 2.1.0 / gems / RubyInline-3.12.4 / lib / inline.rb:458:35:错误:使用未声明的标识符         &#39;指针&#39; Data_Get_Struct(self,MyStruct,pointer);                                     ^    /.rbenv / versions / 2.1.2 / include / ruby​​-2.1.0 / ruby​​ / ruby​​.h:1038:6:注意:从宏扩展&#39; Data_Get_Struct&#39;       (sval)=(type )DATA_PTR(obj); \        ^致命错误:发出的错误太多,现在停止[-ferror-limit =]

我已经完成了一堆谷歌搜索,但几乎我发现的每个例子都只涉及我最初概述的简单用例。吐出的第一个错误是MyStruct未声明,所以我尝试在访问器方法之前添加结构定义,如下所示:

builder.c '
  typedef struct
  {
    char *title;
    int index;
  } MyStruct;
'

这没有做任何事情,文档似乎很清楚c方法仅用于声明函数,而不是结构。我不确定下一步该尝试什么,其他人是否有过这方面的经验?

1 个答案:

答案 0 :(得分:4)

如果你做的事情比基础知识更复杂的话,RubyInline似乎假设你已经知道如何编写Ruby扩展。

需要在尝试时自己定义结构,但是你应该使用prefix method而不是c method(用于定义方法)。您还需要为类定义分配方法。您可以使用c_singleton method添加一个名为allocate的函数来执行此操作,RubyInline将识别该函数并将其用作分配函数(这似乎没有记录,我通过查看源代码找到它)

将它们放在一起看起来像这样。

class Foo
  inline do |builder|

    # First define the struct that will be wrapped in the
    # class.
    builder.prefix <<-DEFINE_STRUCT
      typedef struct {
        char* bar;
      } MyStruct;
    DEFINE_STRUCT

    # Next define the allocation function that will
    # allocate and wrap a MyStruct struct when creating a
    # new Foo object. You might want to initialize the values
    # to avoid possible segfaults.
    builder.c_singleton <<-ALLOCATE
      VALUE allocate() {
        MyStruct* pointer = ALLOC(MyStruct);
        return Data_Wrap_Struct(self, NULL, free, pointer);
      }
    ALLOCATE

    # Finally we can use the struct_name and accessor methods.
    builder.struct_name = 'MyStruct'
    builder.accessor 'bar', 'char *' 
  end

end

请注意,如果查看主目录中的.ruby_inline目录,就可以看到生成的C代码。