├── .gitignore
├── benchmark_fibonacci.rb
├── benchmark_table.rb
├── benchmark_tarai.rb
├── Makefile
├── ruby_example.rb
└── extension_with_crystal.cr
/.gitignore:
--------------------------------------------------------------------------------
1 | *.bundle
2 | *.o
3 | bc_flags
4 |
--------------------------------------------------------------------------------
/benchmark_fibonacci.rb:
--------------------------------------------------------------------------------
1 | require 'benchmark'
2 | require_relative 'ruby_example'
3 | require_relative 'extension_with_crystal'
4 |
5 | Benchmark.bm 18 do |r|
6 | r.report "fibonacci (ruby)" do
7 | fibonacci(40)
8 | end
9 | r.report "fibonacci (crystal)" do
10 | fibonacci_cr(40)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/benchmark_table.rb:
--------------------------------------------------------------------------------
1 | require 'benchmark'
2 | require_relative 'ruby_example'
3 | require_relative 'extension_with_crystal'
4 |
5 | Benchmark.bm 16 do |r|
6 | r.report "table (ruby)" do
7 | Table.new.generate("woot", 100, 500)
8 | end
9 | r.report "table (crystal)" do
10 | TableCr.new.generate("woot", 100, 500)
11 | end
12 | end
13 |
--------------------------------------------------------------------------------
/benchmark_tarai.rb:
--------------------------------------------------------------------------------
1 | require 'benchmark'
2 | require_relative 'ruby_example'
3 | require_relative 'extension_with_crystal'
4 |
5 | Benchmark.bm 16 do |r|
6 | r.report "tarai (ruby)" do
7 | Takeuchi.tarai(15, 5, 1)
8 | end
9 | r.report "tarai (crystal)" do
10 | TakeuchiCr.tarai(15, 5, 1)
11 | end
12 | end
13 |
14 | # 356,426,301 times function call
15 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | CRYSTAL = crystal
2 | UNAME = "$(shell uname -ms)"
3 | LIBS = -levent -lpcl -lpcre -lgc -lpthread
4 | LDFLAGS = -Wl,-undefined,dynamic_lookup
5 |
6 | TARGET = extension_with_crystal.bundle
7 |
8 | $(TARGET): extension_with_crystal.o
9 | $(CC) -bundle -o $@ $^ $(LIBS) $(LDFLAGS)
10 |
11 | extension_with_crystal.o: extension_with_crystal.cr
12 | $(CRYSTAL) build --release --cross-compile $(UNAME) $<
13 |
14 | .PHONY: clean
15 | clean:
16 | rm -f bc_flags
17 | rm -f extension_with_crystal.o
18 | rm -f $(TARGET)
19 |
--------------------------------------------------------------------------------
/ruby_example.rb:
--------------------------------------------------------------------------------
1 | def fibonacci(n)
2 | return n if n <= 1
3 | fibonacci(n - 1) + fibonacci(n - 2)
4 | end
5 |
6 | class Takeuchi
7 | def self.tarai(x, y, z)
8 | if y < x
9 | tarai(
10 | tarai(x - 1, y, z),
11 | tarai(y - 1, z, x),
12 | tarai(z - 1, x, y)
13 | )
14 | else
15 | y
16 | end
17 | end
18 | end
19 |
20 | class Table
21 | def generate(value, col, row)
22 | table = "
"
23 |
24 | row.times do |row_i|
25 | table += "\n "
26 | col.times { |col_i| table += "\n | (#{col_i}) #{value} | " }
27 | table += "\n
"
28 | end
29 |
30 | table += "\n
"
31 | end
32 | end
33 |
34 | ### # -*- frozen_string_literal: true -*-
35 |
--------------------------------------------------------------------------------
/extension_with_crystal.cr:
--------------------------------------------------------------------------------
1 | lib LibRuby
2 | type VALUE = Void*
3 |
4 | $rb_cObject : VALUE
5 |
6 | fun rb_define_global_function(name : UInt8*, func : VALUE, VALUE -> VALUE, argc : Int32)
7 | fun rb_define_class(name : UInt8*, super : VALUE) : VALUE
8 | fun rb_define_method(klass : VALUE, name : UInt8*, func : VALUE, VALUE, VALUE, VALUE -> VALUE, argc : Int32)
9 | fun rb_define_module_function(klass : VALUE, name : UInt8*, func : VALUE, VALUE, VALUE, VALUE -> VALUE, argc : Int32)
10 | fun rb_str_to_str(str : VALUE) : VALUE
11 | fun rb_string_value_cstr(ptr : VALUE*) : UInt8*
12 | fun rb_str_new(ptr : UInt8*, len : Int32) : VALUE
13 | fun rb_num2int(value : VALUE) : Int32
14 | fun rb_int2inum(value : Int32) : VALUE
15 | end
16 |
17 | def fibonacci_cr(self : LibRuby::VALUE, value : LibRuby::VALUE)
18 | int_value = LibRuby.rb_num2int(value)
19 | LibRuby.rb_int2inum(fibonacci_cr2(int_value))
20 | end
21 |
22 | def fibonacci_cr2(n)
23 | return n if n <= 1
24 | fibonacci_cr2(n - 1) + fibonacci_cr2(n - 2)
25 | end
26 |
27 | def tarai(self : LibRuby::VALUE, x : LibRuby::VALUE, y : LibRuby::VALUE, z : LibRuby::VALUE)
28 | int_x = LibRuby.rb_num2int(x)
29 | int_y = LibRuby.rb_num2int(y)
30 | int_z = LibRuby.rb_num2int(z)
31 | LibRuby.rb_int2inum(tarai2(int_x, int_y, int_z))
32 | end
33 |
34 | def tarai2(x, y, z)
35 | if y < x
36 | tarai2(
37 | tarai2(x - 1, y, z),
38 | tarai2(y - 1, z, x),
39 | tarai2(z - 1, x, y)
40 | )
41 | else
42 | y
43 | end
44 | end
45 |
46 | def generate(self : LibRuby::VALUE, value : LibRuby::VALUE, col : LibRuby::VALUE, row : LibRuby::VALUE)
47 | rb_str = LibRuby.rb_str_to_str(value)
48 | c_str = LibRuby.rb_string_value_cstr(pointerof(rb_str))
49 | cr_str = String.new(c_str)
50 | int_col = LibRuby.rb_num2int(col)
51 | int_row = LibRuby.rb_num2int(row)
52 |
53 | table = ""
54 |
55 | int_row.times do |row_i|
56 | table += "\n "
57 | int_col.times { |col_i| table += "\n | (#{col_i}) #{cr_str} | " }
58 | table += "\n
"
59 | end
60 |
61 | table += "\n
"
62 | LibRuby.rb_str_new(table.to_unsafe, table.size)
63 | end
64 |
65 | fun init = Init_extension_with_crystal
66 | GC.init
67 | LibCrystalMain.__crystal_main(0, Pointer(Pointer(UInt8)).null)
68 |
69 | LibRuby.rb_define_global_function("fibonacci_cr", ->fibonacci_cr, 1);
70 |
71 | rb_class_table = LibRuby.rb_define_class("TableCr", LibRuby.rb_cObject)
72 | LibRuby.rb_define_method(rb_class_table, "generate", ->generate, 3);
73 |
74 | rb_class_takeuchi = LibRuby.rb_define_class("TakeuchiCr", LibRuby.rb_cObject)
75 | LibRuby.rb_define_module_function(rb_class_takeuchi, "tarai", ->tarai, 3);
76 | end
77 |
--------------------------------------------------------------------------------