extpp 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0a6f11af116da3bf20bffbb10008e43f8f03e41f
4
+ data.tar.gz: adf0040c8f4c3e15aa60093b96a774530f9a09d2
5
+ SHA512:
6
+ metadata.gz: '0927493217502f10fc9f96a54ff1970a992ad4eec539c2ce8f5c03a35c22f917f20183c76ee3557ac245c9e033afc5289976a275267299abcb24983048473e94'
7
+ data.tar.gz: c1b5f0e6710d8abcc2a97a5912176b9536fcd7652870d636b443949f408bbf14dd58711feb174630a84337379868190a6f820efd0e37c2bec26ed481dce2e392
@@ -0,0 +1,22 @@
1
+ Copyright (C) 2017 Kouhei Sutou. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,29 @@
1
+ # README
2
+
3
+ ## Name
4
+
5
+ Ext++
6
+
7
+ ## Description
8
+
9
+ Ext++ is a Ruby extension that provides C++ API for writing Ruby extension.
10
+
11
+ You can write your Ruby extension easier than Ruby's C API. Because
12
+ Ext++'s C++ API reduces duplicated code needed for Ruby's C API.
13
+
14
+ You can use all Ruby's C API without any adapter layer. Because you
15
+ can use C API directory from C++.
16
+
17
+ ## Install
18
+
19
+ TODO
20
+
21
+ ## How to use
22
+
23
+ TODO
24
+
25
+ ## License
26
+
27
+ Copyright (C) 2017 Kouhei Sutou
28
+
29
+ The 2-Clause BSD License. See [LICENSE.txt](LICENSE.txt) for details.
@@ -0,0 +1,48 @@
1
+ # -*- ruby -*-
2
+
3
+ require "rubygems"
4
+ require "bundler/gem_helper"
5
+ require "packnga"
6
+
7
+ base_dir = File.join(File.dirname(__FILE__))
8
+
9
+ helper = Bundler::GemHelper.new(base_dir)
10
+ def helper.version_tag
11
+ version
12
+ end
13
+
14
+ helper.install
15
+ spec = helper.gemspec
16
+
17
+ Packnga::DocumentTask.new(spec) do |task|
18
+ task.original_language = "en"
19
+ task.translate_language = "ja"
20
+ end
21
+
22
+ Packnga::ReleaseTask.new(spec) do
23
+ end
24
+
25
+ def run_extconf(*arguments)
26
+ cd("ext/extpp") do
27
+ ruby("extconf.rb", *arguments)
28
+ end
29
+ end
30
+
31
+ desc "Configure"
32
+ task :configure do
33
+ run_extconf
34
+ end
35
+
36
+ namespace :configure do
37
+ desc "Configure for debug"
38
+ task :debug do
39
+ run_extconf("--enable-debug-build")
40
+ end
41
+ end
42
+
43
+ desc "Run tests"
44
+ task :test do
45
+ ruby("test/run-test.rb")
46
+ end
47
+
48
+ task default: ["configure:debug", :test]
@@ -0,0 +1,5 @@
1
+ # News
2
+
3
+ ## 0.0.1 - 2018-02-16
4
+
5
+ The first release!!!
@@ -0,0 +1,261 @@
1
+ #include "function.hpp"
2
+
3
+ #include <unordered_map>
4
+ #include <vector>
5
+
6
+ namespace rb {
7
+ using MethodTable = std::unordered_map<ID, Function *>;
8
+
9
+ struct MethodDefinition {
10
+ MethodDefinition(std::string name_, Function *function_) :
11
+ name(name_),
12
+ function(function_) {
13
+ }
14
+
15
+ std::string name;
16
+ Function *function;
17
+ };
18
+ using MethodDefinitions = std::vector<MethodDefinition>;
19
+ }
20
+
21
+ namespace {
22
+ VALUE MethodTable = Qnil;
23
+
24
+ void free_method_table(void *data) {
25
+ auto method_table = static_cast<rb::MethodTable *>(data);
26
+ delete method_table;
27
+ }
28
+
29
+ const rb_data_type_t MethodTableType = {
30
+ "MethodTable",
31
+ {nullptr, free_method_table, nullptr,},
32
+ nullptr,
33
+ nullptr,
34
+ RUBY_TYPED_FREE_IMMEDIATELY,
35
+ };
36
+
37
+ rb::MethodTable *method_table_from_ruby(VALUE rb_method_table) {
38
+ rb::MethodTable *method_table;
39
+ TypedData_Get_Struct(rb_method_table,
40
+ rb::MethodTable,
41
+ &MethodTableType,
42
+ method_table);
43
+ return method_table;
44
+ }
45
+
46
+ VALUE method_table_to_ruby(rb::MethodTable *method_table) {
47
+ if (NIL_P(MethodTable)) {
48
+ MethodTable = rb_define_class("MethodTable", rb_cData);
49
+ }
50
+ return TypedData_Wrap_Struct(MethodTable, &MethodTableType, method_table);
51
+ }
52
+
53
+ VALUE MethodDefinitions = Qnil;
54
+
55
+ void free_method_definitions(void *data) {
56
+ auto method_definitions = static_cast<rb::MethodDefinitions *>(data);
57
+ delete method_definitions;
58
+ }
59
+
60
+ const rb_data_type_t MethodDefinitionsType = {
61
+ "MethodDefinitions",
62
+ {nullptr, free_method_definitions, nullptr,},
63
+ nullptr,
64
+ nullptr,
65
+ RUBY_TYPED_FREE_IMMEDIATELY,
66
+ };
67
+
68
+ rb::MethodDefinitions *method_definitions_from_ruby(VALUE rb_definitions) {
69
+ rb::MethodDefinitions *definitions;
70
+ TypedData_Get_Struct(rb_definitions,
71
+ rb::MethodDefinitions,
72
+ &MethodDefinitionsType,
73
+ definitions);
74
+ return definitions;
75
+ }
76
+
77
+ VALUE method_definitions_to_ruby(rb::MethodDefinitions *definitions) {
78
+ if (NIL_P(MethodDefinitions)) {
79
+ MethodDefinitions = rb_define_class("MethodDefinitions", rb_cData);
80
+ }
81
+ return TypedData_Wrap_Struct(MethodDefinitions,
82
+ &MethodDefinitionsType,
83
+ definitions);
84
+ }
85
+
86
+ VALUE call_func(int argc, VALUE *argv, VALUE self) {
87
+ auto rb_method_table =
88
+ rb_ivar_get(rb_obj_class(self), rb_intern("__method_table__"));
89
+ auto method_table = method_table_from_ruby(rb_method_table);
90
+ auto method_name_symbol = rb_funcall(self, rb_intern("__method__"), 0);
91
+ auto function = (*method_table)[rb_sym2id(method_name_symbol)];
92
+ return function->call(self, argc, argv);
93
+ }
94
+
95
+ bool flush_method_definitions(VALUE klass) {
96
+ ID id_method_definitions = rb_intern("__method_definitions__");
97
+ auto rb_definitions = rb_ivar_get(klass, id_method_definitions);
98
+ if (NIL_P(rb_definitions)) {
99
+ return false;
100
+ }
101
+
102
+ auto definitions = method_definitions_from_ruby(rb_definitions);
103
+ auto rb_method_table = rb_ivar_get(klass, rb_intern("__method_table__"));
104
+ auto method_table = method_table_from_ruby(rb_method_table);
105
+ for (const auto &definition : *definitions) {
106
+ ID name_id = rb_intern(definition.name.c_str());
107
+ (*method_table)[name_id] = definition.function;
108
+ rb_define_method(klass,
109
+ definition.name.c_str(),
110
+ reinterpret_cast<rb::MethodFunc>(call_func),
111
+ -1);
112
+ }
113
+ rb_ivar_set(klass, id_method_definitions, Qnil);
114
+ return true;
115
+ }
116
+
117
+ VALUE method_missing(int argc, VALUE *argv, VALUE self) {
118
+ auto klass = rb_obj_class(self);
119
+
120
+ if (flush_method_definitions(klass)) {
121
+ auto rb_method_table = rb_ivar_get(klass, rb_intern("__method_table__"));
122
+ auto method_table = method_table_from_ruby(rb_method_table);
123
+
124
+ VALUE rb_name_symbol;
125
+ VALUE rb_args;
126
+ rb_scan_args(argc, argv, "1*", &rb_name_symbol, &rb_args);
127
+ auto function = (*method_table)[rb_sym2id(rb_name_symbol)];
128
+ if (function) {
129
+ return function->call(self, RARRAY_LEN(rb_args), RARRAY_PTR(rb_args));
130
+ }
131
+ }
132
+
133
+ return rb_call_super(argc, argv);
134
+ }
135
+
136
+ VALUE respond_to_missing_p(VALUE self,
137
+ VALUE rb_name_symbol,
138
+ VALUE rb_include_private) {
139
+ auto klass = rb_obj_class(self);
140
+
141
+ if (flush_method_definitions(klass)) {
142
+ auto rb_method_table = rb_ivar_get(klass, rb_intern("__method_table__"));
143
+ auto method_table = method_table_from_ruby(rb_method_table);
144
+
145
+ auto function = (*method_table)[rb_sym2id(rb_name_symbol)];
146
+ if (function) {
147
+ return Qtrue;
148
+ }
149
+ }
150
+
151
+ VALUE rb_args[] = {rb_name_symbol, rb_include_private};
152
+ return rb_call_super(2, rb_args);
153
+ }
154
+ }
155
+
156
+ namespace rb {
157
+ class Class::ClassImpl {
158
+ public:
159
+ ClassImpl(VALUE klass) :
160
+ class_(klass),
161
+ method_table_(new MethodTable()),
162
+ lazy_define_method_(false),
163
+ method_definitions_(nullptr) {
164
+ rb_iv_set(class_, "__method_table__", method_table_to_ruby(method_table_));
165
+ rb_iv_set(class_, "__method_definitions__", Qnil);
166
+ }
167
+
168
+ void enable_lazy_define_method() {
169
+ if (lazy_define_method_) {
170
+ return;
171
+ }
172
+
173
+ lazy_define_method_ = true;
174
+ method_definitions_ = new MethodDefinitions();
175
+ rb_iv_set(class_, "__method_definitions__",
176
+ method_definitions_to_ruby(method_definitions_));
177
+ rb_define_method(class_,
178
+ "method_missing",
179
+ reinterpret_cast<MethodFunc>(method_missing),
180
+ -1);
181
+ rb_define_method(class_,
182
+ "respond_to_missing?",
183
+ reinterpret_cast<MethodFunc>(respond_to_missing_p),
184
+ -1);
185
+ }
186
+
187
+ void define_method(const char *name, VALUE (*body)(VALUE self)) {
188
+ rb_define_method(class_,
189
+ name,
190
+ reinterpret_cast<MethodFunc>(body),
191
+ 0);
192
+ }
193
+
194
+ void define_method(const char *name,
195
+ VALUE (*body)(int argc, VALUE *argv, VALUE self)) {
196
+ rb_define_method(class_,
197
+ name,
198
+ reinterpret_cast<MethodFunc>(body),
199
+ -1);
200
+ }
201
+
202
+ void define_method(const char *name, Function *function) {
203
+ if (lazy_define_method_) {
204
+ method_definitions_->emplace_back(name, function);
205
+ } else {
206
+ ID name_id = rb_intern(name);
207
+ (*method_table_)[name_id] = function;
208
+ rb_define_method(class_,
209
+ name,
210
+ reinterpret_cast<MethodFunc>(call_func),
211
+ -1);
212
+ }
213
+ }
214
+
215
+ private:
216
+ VALUE class_;
217
+ MethodTable *method_table_;
218
+ bool lazy_define_method_;
219
+ MethodDefinitions *method_definitions_;
220
+ };
221
+
222
+ Class::Class(const char *name, VALUE parent) :
223
+ Object(rb_define_class(name, parent)),
224
+ impl_(new ClassImpl(this->to_ruby())) {
225
+ }
226
+
227
+ Class::Class(VALUE klass) :
228
+ Object(klass),
229
+ impl_(new ClassImpl(this->to_ruby())) {
230
+ }
231
+
232
+ Class::~Class() {
233
+ delete impl_;
234
+ }
235
+
236
+ Class &Class::define_method(const char *name,
237
+ MethodWithoutArguments body) {
238
+ auto function = new FunctionWithoutArgument(body);
239
+ impl_->define_method(name, function);
240
+ return (Class &)*this;
241
+ }
242
+
243
+ Class &Class::define_method(const char *name,
244
+ MethodWithArguments body) {
245
+ auto function = new FunctionWithArguments(body);
246
+ impl_->define_method(name, function);
247
+ return (Class &)*this;
248
+ }
249
+
250
+ Class &Class::define_method(const char *name,
251
+ MethodWithArgumentsCompatible body) {
252
+ auto function = new FunctionWithArgumentsCompatible(body);
253
+ impl_->define_method(name, function);
254
+ return (Class &)*this;
255
+ }
256
+
257
+ Class &Class::enable_lazy_define_method() {
258
+ impl_->enable_lazy_define_method();
259
+ return (Class &)*this;
260
+ }
261
+ }
@@ -0,0 +1,75 @@
1
+ require_relative "../../lib/extpp/compiler"
2
+
3
+ cxxflags = RbConfig::CONFIG["CXXFLAGS"]
4
+ compiler = Extpp::Compiler.new(cxxflags)
5
+ compiler.check
6
+ cxxflags = compiler.cxx_flags
7
+
8
+ sources = Dir.chdir(__dir__) do
9
+ Dir.glob("*.cpp").collect do |cpp_source|
10
+ File.join(__dir__, cpp_source)
11
+ end
12
+ end
13
+ objects = sources.collect do |source|
14
+ source.gsub(/\.cpp\z/, ".o")
15
+ end
16
+
17
+ def collect_headers(dir)
18
+ Dir.chdir(dir) do
19
+ Dir.glob("**/*.hpp").collect do |header|
20
+ File.join(dir, header)
21
+ end
22
+ end
23
+ end
24
+
25
+ include_dir = File.expand_path(File.join(__dir__, "..", "..", "include"))
26
+ public_headers = collect_headers(include_dir)
27
+ private_headers = collect_headers(__dir__)
28
+ headers = public_headers + private_headers
29
+
30
+ File.open("Makefile", "w") do |makefile|
31
+ makefile.puts(<<-MAKEFILE)
32
+ LIBRARY = libruby-extpp.#{RbConfig::CONFIG["DLEXT"]}
33
+
34
+ SOURCES = #{sources.collect(&:quote).join(" ")}
35
+ OBJECTS = #{objects.collect(&:quote).join(" ")}
36
+ HEADERS = #{headers.collect(&:quote).join(" ")}
37
+
38
+ INCLUDE_DIR = #{include_dir.quote}
39
+
40
+ CXX = #{RbConfig::CONFIG["CXX"].quote}
41
+
42
+ RUBY = #{RbConfig.ruby.quote}
43
+ RUBY_HEADER_DIR = #{RbConfig::CONFIG["rubyhdrdir"].quote}
44
+ RUBY_ARCH_HEADER_DIR = #{RbConfig::CONFIG["rubyarchhdrdir"].quote}
45
+ LDSHAREDXX = #{RbConfig::CONFIG["LDSHAREDXX"]}
46
+ CCDLFLAGS = #{RbConfig::CONFIG["CCDLFLAGS"]}
47
+
48
+ INCLUDEFLAGS = \
49
+ -I$(INCLUDE_DIR) \
50
+ -I$(RUBY_HEADER_DIR) \
51
+ -I$(RUBY_ARCH_HEADER_DIR)
52
+ CPPFLAGS = #{RbConfig::CONFIG["CPPFLAGS"]}
53
+ CXXFLAGS = $(CCDLFLAGS) #{cxxflags}
54
+
55
+ all: $(LIBRARY)
56
+
57
+ clean:
58
+ rm -rf $(OBJECTS) $(LIBRARY)
59
+
60
+ dist-clean:
61
+ $(MAKE) clean
62
+ rm -rf Makefile
63
+
64
+ install: $(LIBRARY)
65
+ "$(RUBY)" -run -e install -- $(LIBRARY) $(DESTDIR)/tmp/local/lib/
66
+
67
+ $(LIBRARY): $(OBJECTS)
68
+ $(LDSHAREDXX) -o $@ $^
69
+
70
+ .cpp.o:
71
+ $(CXX) $(INCLUDEFLAGS) $(CPPFLAGS) $(CXXFLAGS) -o $@ -c $<
72
+
73
+ $(OBJECTS): $(HEADERS)
74
+ MAKEFILE
75
+ end