使用RubyInline gem创建C结构

Dev*_*vin 5 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)
Run Code Online (Sandbox Code Playgroud)

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

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

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

builder.struct_name = 'MyStruct' 
builder.accessor :title,        'char *' 
builder.accessor :stream_index, 'int',   :index
Run Code Online (Sandbox Code Playgroud)

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

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'
Run Code Online (Sandbox Code Playgroud)

不幸的是,我甚至无法做到这一点

*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'Data_Get_Struct'(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:错误:使用未声明的标识符'MyStruct'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏扩展'Data_Get_Struct'(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:3:错误:预期表达式Data_Get_Struct(self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏扩展'Data_Get_Struct'(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:错误:使用未声明的标识符'指针'返回(rb_str_new2(指针- >标题)); ^*/.rbenv/versions/2.1.2/include/ruby​​-2.1.0/ruby​​/intern.h:786:27:注意:从宏'rb_str_new_cstr'扩展(__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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby​​-2.1.0/ruby​​/intern.h:787:14:注意:从宏扩展'rb_str_new_cstr'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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby​​-2.1.0/ruby​​/intern.h:787:33:注意:从宏'rb_str_new_cstr'扩展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:错误:使用未声明的标识符'指针'*/.rbenv/versions/2.1.2/include/ruby​​-2.1.0/ruby​​/intern.h:788:18:注意:从宏'rb_str_new_cstr'扩展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:错误:从函数返回'void'与不兼容的结果类型'VALUE'(又名'unsigned long')返回(rb_str_new2(pointer-> title)); ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:3:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'Data_Get_Struct'(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:错误:使用未声明的标识符'MyStruct'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏扩展'Data_Get_Struct'(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:3:错误:预期表达式Data_Get_Struct(self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏扩展'Data_Get_Struct'(sval)=(type)DATA_PTR(obj);\^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:482:3:错误:使用未声明的标识符'指针'指针 - > title = StringValuePtr(value); ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3:错误:使用未声明的标识符'MyStruct'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符'指针'MyStruct*指针; ^*/.rbenv/versions/2.1.2/lib/ruby​​/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符'指针'Data_Get_Struct (self,MyStruct,指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏扩展'Data_Get_Struct'(sval)=(type)DATA_PTR(obj);\^致命错误:发出太多错误,现在停止[-ferror-limit =]

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

builder.c '
  typedef struct
  {
    char *title;
    int index;
  } MyStruct;
'
Run Code Online (Sandbox Code Playgroud)

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

mat*_*att 4

如果您正在做比基础知识更复杂的事情,RubyInline 似乎假设您知道编写 Ruby 扩展的方法。

\n\n

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

\n\n

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

\n\n
class Foo\n  inline do |builder|\n\n    # First define the struct that will be wrapped in the\n    # class.\n    builder.prefix <<-DEFINE_STRUCT\n      typedef struct {\n        char* bar;\n      } MyStruct;\n    DEFINE_STRUCT\n\n    # Next define the allocation function that will\n    # allocate and wrap a MyStruct struct when creating a\n    # new Foo object. You might want to initialize the values\n    # to avoid possible segfaults.\n    builder.c_singleton <<-ALLOCATE\n      VALUE allocate() {\n        MyStruct* pointer = ALLOC(MyStruct);\n        return Data_Wrap_Struct(self, NULL, free, pointer);\n      }\n    ALLOCATE\n\n    # Finally we can use the struct_name and accessor methods.\n    builder.struct_name = \'MyStruct\'\n    builder.accessor \'bar\', \'char *\' \n  end\n\nend\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n