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.
@@ -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