extpp 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +48 -0
- data/doc/text/news.md +5 -0
- data/ext/extpp/class.cpp +261 -0
- data/ext/extpp/extconf.rb +75 -0
- data/ext/extpp/function.cpp +28 -0
- data/ext/extpp/object.cpp +45 -0
- data/include/ruby.hpp +10 -0
- data/include/ruby/cast.hpp +74 -0
- data/include/ruby/class.hpp +25 -0
- data/include/ruby/object.hpp +96 -0
- data/include/ruby/type.hpp +12 -0
- data/lib/extpp.rb +36 -0
- data/lib/extpp/compiler.rb +69 -0
- data/lib/extpp/version.rb +3 -0
- data/test/fixtures/cast/cast.cpp +32 -0
- data/test/fixtures/cast/extconf.rb +4 -0
- data/test/fixtures/class/class.cpp +46 -0
- data/test/fixtures/class/extconf.rb +4 -0
- data/test/fixtures/object/extconf.rb +4 -0
- data/test/fixtures/object/object.cpp +78 -0
- data/test/helper.rb +9 -0
- data/test/run-test.rb +23 -0
- data/test/test-cast.rb +42 -0
- data/test/test-class.rb +47 -0
- data/test/test-object.rb +52 -0
- metadata +169 -0
@@ -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
|
+
}
|
data/include/ruby.hpp
ADDED
@@ -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
|
+
}
|
data/lib/extpp.rb
ADDED
@@ -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,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
|
+
}
|