{"id":4156,"date":"2016-11-21T13:17:01","date_gmt":"2016-11-21T13:17:01","guid":{"rendered":"https:\/\/www.bacancytechnology.com\/blog\/?p=4156"},"modified":"2025-03-05T09:14:32","modified_gmt":"2025-03-05T09:14:32","slug":"a-real-world-need-for-c-extension-in-the-ruby","status":"publish","type":"post","link":"https:\/\/www.bacancytechnology.com\/blog\/a-real-world-need-for-c-extension-in-the-ruby","title":{"rendered":"A Real-World need for C extension in the Ruby"},"content":{"rendered":"<p>I seriously want to start this relationship with you, the readership with pure honesty: I completely agree with the incredibility of C. However, before we get stuck into the detail, do you have any idea about C extension and why you should write one in 2016?<\/p>\n<p>Here\u2019s a discussion of a real-world need for a C extension in the Ruby language and how a non-C developer can get it done right.<\/p>\n<h2>Why would you want to write one in 2016?<\/h2>\n<p>There are two reasons behind it. One of them is speed and another is leverage. If there is a well defined problem and if there is a need for speed, then writing an extension can be a way to go. <\/p>\n<h2>Writing C Extension&#8230;.<\/h2>\n<p>Sharing my personal experience, writing C extension is a tough job and it an it advisable to go with FFI \u2013 don\u2019t use it, until you have no other option. But, frankly speaking, I was scared of writing C into widely used application.<\/p>\n<p>Apart from FFI, there were great options like for writing Ruby Extensions in Go, Crystal, Rust and many other languages where C bindings can be exposed. Anyways All I wanted to do is Go with C extension.<\/p>\n<h2>clean C <code>- rtosc<\/code><\/h2>\n<p>Considering several OSC and canonical implementations, it made me use macros and structs,which I didn&#8217;t completely understand at the time. I was about to give up and fortunately I stumbled on the <code>rtosc<\/code> library. It is consisted with two files <code>rtosc.h<\/code> and <code>rtosc.c<\/code>. Wishing the best spirit of open source, I enquired on GitHub issue and within few hours got a thoughtful and polite response -viva la internet!<\/p>\n<p>This helped me to try writing a C extension and trust me I&#8217;m glad that I did.<\/p>\n<p>Source Code &#8211; <strong>https:\/\/www.xavierriley.co.uk\/writing-a-c-extension-for-ruby-in-2016\/&#8221;sif&#8221;, [&#8220;This is a string&#8221;, 123, 3.14]<\/code><\/p>\n<p>So here you can have a look at the type of the arguments corresponds to a tag &#8211; s for a string, i for an int and for the Ruby API I decided to hide this so you do not consider about types.<\/p>\n<pre>\r\n>> FastOsc.encode_single_message(\"\/foo\", [\"baz\", 1, 2.0])\r\n=> \"\/foo\\x00\\x00\\x00\\x00,sif\\x00\\x00\\x00\\x00baz\\x00\\x00\\x00\\x00\\x01@\\x00\\x00\\x00\"\r\n<\/pre>\n<p>It\u2019s a tag string and an output array of the encoded versions.<\/p>\n<p class=\"boxed bg--secondary\" style=\"border: 1px solid #c7c7c7; box-shadow: 0 0 40px rgba(0, 0, 0, 0.2);\"><strong><i><span style=\"font-size:22px; color:#000;\">Partner with us to turbocharge your entrepreneurial journey with a master-blaster Rails Mobile App.<\/span><br \/>\nThe ideal <a href=\"https:\/\/www.bacancytechnology.com\/ruby-on-rails-development-company\" target=\"_blank\" rel=\"noopener\">Ruby on Rails Development Company<\/a> Awaits you!<\/i><\/strong><\/p>\n<h2>Ruby&#8217;s C API<\/h2>\n<p><strong><br \/>\nWorking out the type<\/strong><\/p>\n<pre>\r\nswitch(TYPE(current_arg))\r\n<\/pre>\n<p><strong>Ints and Longs<\/strong><\/p>\n<pre>\r\ncase T_FIXNUM\r\n<\/pre>\n<p><strong>Floats<\/strong><\/p>\n<pre>\r\ncase T_FLOAT:\r\n<\/pre>\n<p>To convert from Ruby to C NUM2DBL<\/p>\n<p><strong>Strings and Symbols<\/strong><\/p>\n<pre>\r\ncase T_STRING:\r\n<\/pre>\n<p>To convert Ruby symbols use <code>rb_sym_to_s()<\/code>.<\/p>\n<h2>Unicode Strings<\/h2>\n<p>I had broken Unicode strings. However it needs to be fixed so did my job this way.<\/p>\n<pre>\r\nstring_arg = rb_str_new2(string_from_c);  \r\n\r\nenc = rb_enc_find_index(\"UTF-8\");  \r\n\r\nrb_enc_associate_index(string_arg, enc);  \r\n<\/pre>\n<p><strong>Ruby <code>Time<\/code> objects<\/strong><\/p>\n<p><strong> Start with the object type<\/strong><\/p>\n<pre>\r\ncase T_DATA:\r\n<\/pre>\n<p>It means you have \tRuby object and you can specifically check using<\/p>\n<pre>if (CLASS_OF(current_arg) == rb_cTime)<\/pre>\n<h2>OSC Timestamps (NTP)<\/h2>\n<pre>\r\n#define JAN_1970 2208988800.0     \/* 2208988800 time from 1900 to 1970 in seconds *\/\r\n\r\nuint64_t ruby_time_to_osc_timetag(VALUE rubytime) {  \r\n  uint64_t timetag;\r\n  double floattime;\r\n  uint32_t sec;\r\n  uint32_t frac;\r\n\r\n  switch(TYPE(rubytime)) {\r\n    case T_NIL:\r\n      timetag = 1;\r\n      break;\r\n    default:\r\n      \/\/ convert Time object to ntp\r\n      floattime = JAN_1970 + NUM2DBL(rb_funcall(rubytime, rb_intern(\"to_f\"), 0));\r\n\r\n      sec = floor(floattime);\r\n      frac = (uint32_t)(fmod(floattime, 1.0) * 4294967296); \/\/ * (2 ** 32)\r\n      \/\/ printf(\"\\nsec: %04x\\n\", sec);\r\n      \/\/ printf(\"\\nfrac: %04x\\n\", frac);\r\n      timetag = (uint64_t)((uint64_t)sec << 32 | (uint64_t)frac);\r\n      \/\/ printf(\"\\ntimetag: %08llx\\n\", timetag);\r\n      break;\r\n  }\r\n\r\n  return timetag;\r\n}\r\n<\/pre>\n<h2>further reading<\/h2>\n<pre>\r\nEncoding  \r\n-------------------------------------------------\r\n            fast_osc    909.680k (\u00b121.4%) i\/s -      4.328M\r\n\r\n             samsosc    271.908k (\u00b119.3%) i\/s -      1.327M\r\n\r\n             oscruby     94.678k (\u00b114.5%) i\/s -    468.968k\r\n\r\nDecoding  \r\n-------------------------------------------------\r\n            fast_osc      2.635M (\u00b122.2%) i\/s -     12.435M\r\n\r\n             samsosc    264.614k (\u00b116.1%) i\/s -      1.304M\r\n\r\n             oscruby     36.362k (\u00b116.3%) i\/s -    179.622k\r\n<\/pre>\n<h2><code>oscruby<\/code>  non-optimised library for Ruby.<\/h2>\n<p><code>samosc<\/code> is hand rolled optimization for pure Ruby version and fast_osc is this C extension. So it is like 4x improvement in Encoding to OSC and a 10x improvement in Decoding over the fastest pure Ruby implementation. It was done completely in a successful way.<\/p>\n<p>The code is available here: <a href=\"https:\/\/github.com\/xavriley\/fast_osc\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/xavriley\/fast_osc<\/a>.<\/p>\n<p>Inspired to write your own extension, or have any valuable feedback for my C extension. I would love to hear from you. I am <a href=\"https:\/\/twitter.com\/bacancytech\" target=\"_blank\" rel=\"noopener\">@bacancytech<\/a> Twitter. Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I seriously want to start this relationship with you, the readership with pure honesty: I completely agree with the incredibility of C. However, before we get stuck into the detail, do you have any idea about C extension and why you should write one in 2016? Here\u2019s a discussion of a real-world need for a [&hellip;]<\/p>\n","protected":false},"author":169,"featured_media":4164,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"_lmt_disableupdate":"no","_lmt_disable":"","footnotes":""},"categories":[35,1265],"tags":[],"coauthors":[2426],"class_list":["post-4156","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ruby-on-rails","category-web-development"],"acf":[],"modified_by":"Binal Prajapati","_links":{"self":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts\/4156","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/users\/169"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/comments?post=4156"}],"version-history":[{"count":0,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/posts\/4156\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/media\/4164"}],"wp:attachment":[{"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/media?parent=4156"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/categories?post=4156"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/tags?post=4156"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.bacancytechnology.com\/blog\/wp-json\/wp\/v2\/coauthors?post=4156"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}