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’s 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.
Why would you want to write one in 2016?
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.
Writing C Extension….
Sharing my personal experience, writing C extension is a tough job and it an it advisable to go with FFI – don’t use it, until you have no other option. But, frankly speaking, I was scared of writing C into widely used application.
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.
clean C - rtosc
Considering several OSC and canonical implementations, it made me use macros and structs,which I didn’t completely understand at the time. I was about to give up and fortunately I stumbled on the rtosc
library. It is consisted with two files rtosc.h
and rtosc.c
. 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!
This helped me to try writing a C extension and trust me I’m glad that I did.
Source Code – https://www.xavierriley.co.uk/writing-a-c-extension-for-ruby-in-2016/”sif”, [“This is a string”, 123, 3.14]
So here you can have a look at the type of the arguments corresponds to a tag – 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.
>> FastOsc.encode_single_message("/foo", ["baz", 1, 2.0]) => "/foo\x00\x00\x00\x00,sif\x00\x00\x00\x00baz\x00\x00\x00\x00\x01@\x00\x00\x00"
It’s a tag string and an output array of the encoded versions.
Partner with us to turbocharge your entrepreneurial journey with a master-blaster Rails Mobile App.
The ideal Ruby on Rails Development Company Awaits you!
Ruby’s C API
Working out the type
switch(TYPE(current_arg))
Ints and Longs
case T_FIXNUM
Floats
case T_FLOAT:
To convert from Ruby to C NUM2DBL
Strings and Symbols
case T_STRING:
To convert Ruby symbols use rb_sym_to_s()
.
Unicode Strings
I had broken Unicode strings. However it needs to be fixed so did my job this way.
string_arg = rb_str_new2(string_from_c); enc = rb_enc_find_index("UTF-8"); rb_enc_associate_index(string_arg, enc);
Ruby Time
objects
Start with the object type
case T_DATA:
It means you have Ruby object and you can specifically check using
if (CLASS_OF(current_arg) == rb_cTime)
OSC Timestamps (NTP)
#define JAN_1970 2208988800.0 /* 2208988800 time from 1900 to 1970 in seconds */ uint64_t ruby_time_to_osc_timetag(VALUE rubytime) { uint64_t timetag; double floattime; uint32_t sec; uint32_t frac; switch(TYPE(rubytime)) { case T_NIL: timetag = 1; break; default: // convert Time object to ntp floattime = JAN_1970 + NUM2DBL(rb_funcall(rubytime, rb_intern("to_f"), 0)); sec = floor(floattime); frac = (uint32_t)(fmod(floattime, 1.0) * 4294967296); // * (2 ** 32) // printf("\nsec: %04x\n", sec); // printf("\nfrac: %04x\n", frac); timetag = (uint64_t)((uint64_t)sec << 32 | (uint64_t)frac); // printf("\ntimetag: %08llx\n", timetag); break; } return timetag; }
further reading
Encoding ------------------------------------------------- fast_osc 909.680k (±21.4%) i/s - 4.328M samsosc 271.908k (±19.3%) i/s - 1.327M oscruby 94.678k (±14.5%) i/s - 468.968k Decoding ------------------------------------------------- fast_osc 2.635M (±22.2%) i/s - 12.435M samsosc 264.614k (±16.1%) i/s - 1.304M oscruby 36.362k (±16.3%) i/s - 179.622k
oscruby
non-optimised library for Ruby.
samosc
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.
The code is available here: https://github.com/xavriley/fast_osc.
Inspired to write your own extension, or have any valuable feedback for my C extension. I would love to hear from you. I am @bacancytech Twitter. Thanks for reading.