extpp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,28 @@
1
+ #include "function.hpp"
2
+
3
+ namespace rb {
4
+ FunctionWithoutArgument::FunctionWithoutArgument(const MethodWithoutArguments &function) :
5
+ function_(function) {
6
+ }
7
+
8
+ VALUE FunctionWithoutArgument::call(VALUE self, int argc, VALUE *argv) {
9
+ return function_(self);
10
+ };
11
+
12
+
13
+ FunctionWithArguments::FunctionWithArguments(const MethodWithArguments &function) :
14
+ function_(function) {
15
+ }
16
+
17
+ VALUE FunctionWithArguments::call(VALUE self, int argc, VALUE *argv) {
18
+ return function_(self, argc, argv);
19
+ };
20
+
21
+ FunctionWithArgumentsCompatible::FunctionWithArgumentsCompatible(const MethodWithArgumentsCompatible &function) :
22
+ function_(function) {
23
+ }
24
+
25
+ VALUE FunctionWithArgumentsCompatible::call(VALUE self, int argc, VALUE *argv) {
26
+ return function_(argc, argv, self);
27
+ };
28
+ }
@@ -0,0 +1,45 @@
1
+ #include <ruby/object.hpp>
2
+
3
+ namespace {
4
+ VALUE call_block(RB_BLOCK_CALL_FUNC_ARGLIST(rb_data, rb_block)) {
5
+ auto block = reinterpret_cast<rb::MethodWithoutArguments>(rb_block);
6
+ return block(rb_data);
7
+ }
8
+ }
9
+
10
+ namespace rb {
11
+ Object Object::send(ID name_id) {
12
+ VALUE rb_result = rb_funcall(rb_object_, name_id, 0);
13
+ return Object(rb_result);
14
+ }
15
+
16
+ Object Object::send(ID name_id,
17
+ std::initializer_list<VALUE> args) {
18
+ size_t n = args.size();
19
+ VALUE rb_args[n];
20
+ int i = 0;
21
+ for (auto arg : args) {
22
+ rb_args[i++] = arg;
23
+ }
24
+ VALUE rb_result = rb_funcallv(rb_object_, name_id, n, rb_args);
25
+ return Object(rb_result);
26
+ }
27
+
28
+ Object Object::send(ID name_id,
29
+ std::initializer_list<VALUE> args,
30
+ MethodWithoutArguments block) {
31
+ size_t n = args.size();
32
+ VALUE rb_args[n];
33
+ int i = 0;
34
+ for (auto arg : args) {
35
+ rb_args[i++] = arg;
36
+ }
37
+ VALUE rb_result = rb_block_call(rb_object_,
38
+ name_id,
39
+ n,
40
+ rb_args,
41
+ reinterpret_cast<MethodFunc>(call_block),
42
+ reinterpret_cast<VALUE>(block));
43
+ return Object(rb_result);
44
+ }
45
+ }
@@ -0,0 +1,10 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ #define RB_BEGIN_DECLS extern "C" {
6
+ #define RB_END_DECLS }
7
+
8
+ #include <ruby/cast.hpp>
9
+ #include <ruby/class.hpp>
10
+ #include <ruby/object.hpp>
@@ -0,0 +1,74 @@
1
+ #pragma once
2
+
3
+ #include <ruby/object.hpp>
4
+
5
+ namespace rb {
6
+ template <typename RETURN_TYPE, typename ARGUMENT_TYPE>
7
+ inline RETURN_TYPE cast(ARGUMENT_TYPE object);
8
+
9
+ template <typename RETURN_TYPE,
10
+ typename ARGUMENT_TYPE,
11
+ typename ADDTIONAL_DATA_TYPE1>
12
+ inline RETURN_TYPE cast(ARGUMENT_TYPE object,
13
+ ADDTIONAL_DATA_TYPE1 data1);
14
+
15
+ template <>
16
+ inline int32_t cast<int32_t, Object>(Object rb_object) {
17
+ return NUM2INT(rb_object);
18
+ }
19
+
20
+ template <>
21
+ inline Object cast<Object, int32_t>(int32_t n) {
22
+ return Object(INT2NUM(n));
23
+ }
24
+
25
+
26
+ template <>
27
+ inline int64_t cast<int64_t, Object>(Object rb_object) {
28
+ return NUM2LONG(rb_object);
29
+ }
30
+
31
+ template <>
32
+ inline Object cast<Object, int64_t>(int64_t n) {
33
+ return Object(LONG2NUM(n));
34
+ }
35
+
36
+
37
+ template <>
38
+ inline uint32_t cast<uint32_t, Object>(Object rb_object) {
39
+ return NUM2UINT(rb_object);
40
+ }
41
+
42
+ template <>
43
+ inline Object cast<Object, uint32_t>(uint32_t n) {
44
+ return Object(UINT2NUM(n));
45
+ }
46
+
47
+
48
+ template <>
49
+ inline uint64_t cast<uint64_t, Object>(Object rb_object) {
50
+ return NUM2ULONG(rb_object);
51
+ }
52
+
53
+ template <>
54
+ inline Object cast<Object, uint64_t>(uint64_t n) {
55
+ return Object(ULONG2NUM(n));
56
+ }
57
+
58
+
59
+ template <>
60
+ inline const char *cast<const char *, Object>(Object rb_object) {
61
+ VALUE rb_object_raw = rb_object;
62
+ return StringValueCStr(rb_object_raw);
63
+ }
64
+
65
+ template <>
66
+ inline Object cast<Object, const char *>(const char *c_string) {
67
+ return Object(rb_str_new_cstr(c_string));
68
+ }
69
+
70
+ template <>
71
+ inline Object cast<Object, const char *, long>(const char *data, long size) {
72
+ return Object(rb_str_new(data, size));
73
+ }
74
+ }
@@ -0,0 +1,25 @@
1
+ #pragma once
2
+
3
+ #include <ruby/object.hpp>
4
+
5
+ namespace rb {
6
+ class Class: public Object {
7
+ public:
8
+ Class(const char *name, VALUE parent=rb_cObject);
9
+ Class(VALUE klass);
10
+ ~Class();
11
+
12
+ Class &define_method(const char *name,
13
+ MethodWithoutArguments body);
14
+ Class &define_method(const char *name,
15
+ MethodWithArguments body);
16
+ Class &define_method(const char *name,
17
+ MethodWithArgumentsCompatible body);
18
+
19
+ Class &enable_lazy_define_method();
20
+
21
+ private:
22
+ class ClassImpl;
23
+ ClassImpl *impl_;
24
+ };
25
+ }
@@ -0,0 +1,96 @@
1
+ #pragma once
2
+
3
+ #include <ruby/type.hpp>
4
+
5
+ #include <initializer_list>
6
+
7
+ namespace rb {
8
+ class Object {
9
+ public:
10
+ explicit Object(VALUE rb_object=Qnil) :
11
+ rb_object_(rb_object),
12
+ is_gc_guarding_(false) {
13
+ }
14
+
15
+ explicit Object(const char *name) :
16
+ rb_object_(rb_const_get(rb_cObject, rb_intern(name))),
17
+ is_gc_guarding_(false) {
18
+ }
19
+
20
+ Object(Object const &object) :
21
+ rb_object_(object),
22
+ is_gc_guarding_(false) {
23
+ }
24
+
25
+ virtual ~Object() {
26
+ if (is_gc_guarding_) {
27
+ rb_gc_unregister_address(&rb_object_);
28
+ }
29
+ }
30
+
31
+ inline explicit operator bool() const {
32
+ return RTEST(rb_object_);
33
+ }
34
+
35
+ inline VALUE to_ruby() const {
36
+ return rb_object_;
37
+ }
38
+
39
+ inline operator VALUE() const {
40
+ return rb_object_;
41
+ }
42
+
43
+ inline bool is_nil() const {
44
+ return NIL_P(rb_object_);
45
+ }
46
+
47
+ inline void guard_from_gc() {
48
+ if (!is_gc_guarding_) {
49
+ return;
50
+ }
51
+
52
+ is_gc_guarding_ = true;
53
+ rb_gc_register_address(&rb_object_);
54
+ }
55
+
56
+ Object send(ID name_id);
57
+
58
+ inline Object send(const char *name) {
59
+ return send(rb_intern(name));
60
+ }
61
+
62
+ inline Object send(Object name) {
63
+ return send(rb_intern_str(name));
64
+ }
65
+
66
+ Object send(ID name_id, std::initializer_list<VALUE> args);
67
+
68
+ inline Object send(const char *name, std::initializer_list<VALUE> args) {
69
+ return send(rb_intern(name), args);
70
+ }
71
+
72
+ inline Object send(Object name, std::initializer_list<VALUE> args) {
73
+ return send(rb_intern_str(name), args);
74
+ }
75
+
76
+ Object send(ID name_id,
77
+ std::initializer_list<VALUE> args,
78
+ MethodWithoutArguments block);
79
+
80
+ inline Object send(const char *name,
81
+ std::initializer_list<VALUE> args,
82
+ MethodWithoutArguments block) {
83
+ return send(rb_intern(name), args, block);
84
+ }
85
+
86
+ inline Object send(Object name,
87
+ std::initializer_list<VALUE> args,
88
+ MethodWithoutArguments block) {
89
+ return send(rb_intern_str(name), args, block);
90
+ }
91
+
92
+ private:
93
+ VALUE rb_object_;
94
+ bool is_gc_guarding_;
95
+ };
96
+ }
@@ -0,0 +1,12 @@
1
+ #pragma once
2
+
3
+ #include <ruby.h>
4
+
5
+ namespace rb {
6
+ using MethodFunc = VALUE (*)(ANYARGS);
7
+
8
+ using MethodWithoutArguments = VALUE (*)(VALUE self);
9
+ using MethodWithArguments = VALUE (*)(VALUE self, int argc, VALUE *argv);
10
+ using MethodWithArgumentsCompatible =
11
+ VALUE (*)(int argc, VALUE *argv, VALUE self);
12
+ }
@@ -0,0 +1,36 @@
1
+ require "extpp/compiler"
2
+
3
+ compiler = Extpp::Compiler.new($CXXFLAGS)
4
+ compiler.check
5
+ $CXXFLAGS = compiler.cxx_flags
6
+
7
+ include_path = File.expand_path(File.join(__dir__, "..", "include"))
8
+ $INCFLAGS += " -I#{include_path.quote}"
9
+
10
+ header_files = Dir.chdir(include_path) do
11
+ Dir.glob("**/*.*").collect do |path|
12
+ File.join(include_path, path)
13
+ end
14
+ end
15
+ header_files_dependency_injector = Module.new do
16
+ define_method(:create_makefile) do |*args, &block|
17
+ super(*args, &block)
18
+ File.open("Makefile", "ab") do |makefile|
19
+ makefile.print <<-MAKEFILE
20
+
21
+ extpp_headers = #{header_files.join(" ")}
22
+ $(OBJS): $(extpp_headers)
23
+ MAKEFILE
24
+ end
25
+ end
26
+ end
27
+ extend(header_files_dependency_injector)
28
+
29
+ [
30
+ File.join(__dir__, "..", "ext", "extpp"),
31
+ __dir__,
32
+ ].each do |candidate_dir|
33
+ so_name = "libruby-extpp.#{RbConfig::CONFIG["DLEXT"]}"
34
+ lib_path = File.expand_path(File.join(candidate_dir, so_name))
35
+ $LIBS += " #{lib_path.quote}" if File.exist?(lib_path)
36
+ end
@@ -0,0 +1,69 @@
1
+ require "mkmf"
2
+
3
+ module Extpp
4
+ class Compiler
5
+ attr_reader :cxx_flags
6
+ def initialize(cxx_flags)
7
+ @cxx_flags = cxx_flags
8
+ end
9
+
10
+ def gcc?
11
+ RbConfig::CONFIG["GCC"] == "yes"
12
+ end
13
+
14
+ def check
15
+ check_debug_build
16
+ check_version
17
+ end
18
+
19
+ private
20
+ def check_debug_build
21
+ checking_for(checking_message("--enable-debug-build option")) do
22
+ enable_debug_build = enable_config("debug-build", false)
23
+ if enable_debug_build
24
+ @cxx_flags = disable_optimization_build_flag(@cxx_flags)
25
+ @cxx_flags = enable_debug_build_flag(@cxx_flags)
26
+ end
27
+ enable_debug_build
28
+ end
29
+ end
30
+
31
+ def check_version
32
+ return unless gcc?
33
+ checking_for(checking_message("g++ version"), "%g%s") do
34
+ version = nil
35
+ std = nil
36
+ if /\Ag\+\+ .+ (\d\.\d)\.\d/ =~ `#{RbConfig.expand("$(CXX) --version")}`
37
+ version = Float($1)
38
+ if version < 5.1
39
+ std = "gnu++11"
40
+ elsif version < 6.1
41
+ std = "gnu++14"
42
+ end
43
+ end
44
+ if std
45
+ @cxx_flags += " -std=#{std}"
46
+ [version, " (#{std})"]
47
+ else
48
+ [version, ""]
49
+ end
50
+ end
51
+ end
52
+
53
+ def disable_optimization_build_flag(flags)
54
+ if gcc?
55
+ flags.gsub(/(^|\s)-O\d(\s|$)/, '\\1-O0\\2')
56
+ else
57
+ flags
58
+ end
59
+ end
60
+
61
+ def enable_debug_build_flag(flags)
62
+ if gcc?
63
+ flags.gsub(/(^|\s)(?:-g|-g\d|-ggdb\d?)(\s|$)/, '\\1-g3\\2')
64
+ else
65
+ flags
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,3 @@
1
+ module ExtPP
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,32 @@
1
+ #include <ruby.hpp>
2
+
3
+ extern "C" void
4
+ Init_cast(void)
5
+ {
6
+ rb::Class("Caster").
7
+ define_method("cast_int32", [](VALUE self, int argc, VALUE *argv) -> VALUE {
8
+ VALUE rb_n;
9
+ rb_scan_args(argc, argv, "1", &rb_n);
10
+ return rb::cast<rb::Object>(rb::cast<int32_t>(rb::Object(rb_n)));
11
+ }).
12
+ define_method("cast_int64", [](VALUE self, int argc, VALUE *argv) -> VALUE {
13
+ VALUE rb_n;
14
+ rb_scan_args(argc, argv, "1", &rb_n);
15
+ return rb::cast<rb::Object>(rb::cast<int64_t>(rb::Object(rb_n)));
16
+ }).
17
+ define_method("cast_uint32", [](VALUE self, int argc, VALUE *argv) -> VALUE {
18
+ VALUE rb_n;
19
+ rb_scan_args(argc, argv, "1", &rb_n);
20
+ return rb::cast<rb::Object>(rb::cast<uint32_t>(rb::Object(rb_n)));
21
+ }).
22
+ define_method("cast_uint64", [](VALUE self, int argc, VALUE *argv) -> VALUE {
23
+ VALUE rb_n;
24
+ rb_scan_args(argc, argv, "1", &rb_n);
25
+ return rb::cast<rb::Object>(rb::cast<uint64_t>(rb::Object(rb_n)));
26
+ }).
27
+ define_method("cast_string", [](VALUE self, int argc, VALUE *argv) -> VALUE {
28
+ VALUE rb_string;
29
+ rb_scan_args(argc, argv, "1", &rb_string);
30
+ return rb::cast<rb::Object>(rb::cast<const char *>(rb::Object(rb_string)));
31
+ });
32
+ }
@@ -0,0 +1,4 @@
1
+ require "mkmf"
2
+ require "extpp"
3
+
4
+ create_makefile("cast")