rice 4.3.3 → 4.5.0
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 +4 -4
- data/CHANGELOG.md +63 -26
- data/README.md +7 -2
- data/Rakefile +7 -1
- data/include/rice/rice.hpp +7291 -4430
- data/include/rice/stl.hpp +769 -222
- data/lib/mkmf-rice.rb +37 -95
- data/rice/Address_Registration_Guard.hpp +72 -3
- data/rice/Arg.hpp +19 -5
- data/rice/Arg.ipp +24 -0
- data/rice/Callback.hpp +21 -0
- data/rice/Callback.ipp +13 -0
- data/rice/Constructor.hpp +4 -27
- data/rice/Constructor.ipp +79 -0
- data/rice/Data_Object.hpp +74 -3
- data/rice/Data_Object.ipp +324 -32
- data/rice/Data_Type.hpp +215 -3
- data/rice/Data_Type.ipp +125 -64
- data/rice/Director.hpp +0 -2
- data/rice/Enum.hpp +4 -6
- data/rice/Enum.ipp +101 -57
- data/rice/Exception.hpp +62 -2
- data/rice/Exception.ipp +7 -12
- data/rice/JumpException.hpp +44 -0
- data/rice/JumpException.ipp +48 -0
- data/rice/MemoryView.hpp +11 -0
- data/rice/MemoryView.ipp +43 -0
- data/rice/Return.hpp +6 -26
- data/rice/Return.ipp +10 -16
- data/rice/detail/DefaultHandler.hpp +12 -0
- data/rice/detail/DefaultHandler.ipp +8 -0
- data/rice/detail/HandlerRegistry.hpp +5 -35
- data/rice/detail/HandlerRegistry.ipp +7 -11
- data/rice/detail/InstanceRegistry.hpp +1 -4
- data/rice/detail/MethodInfo.hpp +15 -5
- data/rice/detail/MethodInfo.ipp +78 -6
- data/rice/detail/Native.hpp +32 -0
- data/rice/detail/Native.ipp +129 -0
- data/rice/detail/NativeAttributeGet.hpp +51 -0
- data/rice/detail/NativeAttributeGet.ipp +51 -0
- data/rice/detail/NativeAttributeSet.hpp +43 -0
- data/rice/detail/NativeAttributeSet.ipp +82 -0
- data/rice/detail/NativeCallbackFFI.hpp +55 -0
- data/rice/detail/NativeCallbackFFI.ipp +151 -0
- data/rice/detail/NativeCallbackSimple.hpp +30 -0
- data/rice/detail/NativeCallbackSimple.ipp +29 -0
- data/rice/detail/NativeFunction.hpp +20 -21
- data/rice/detail/NativeFunction.ipp +199 -64
- data/rice/detail/NativeIterator.hpp +8 -11
- data/rice/detail/NativeIterator.ipp +27 -31
- data/rice/detail/NativeRegistry.hpp +24 -15
- data/rice/detail/NativeRegistry.ipp +23 -48
- data/rice/detail/Proc.hpp +4 -0
- data/rice/detail/Proc.ipp +85 -0
- data/rice/detail/Registries.hpp +0 -7
- data/rice/detail/Registries.ipp +0 -18
- data/rice/detail/RubyFunction.hpp +0 -3
- data/rice/detail/RubyFunction.ipp +4 -8
- data/rice/detail/RubyType.hpp +19 -0
- data/rice/detail/RubyType.ipp +187 -0
- data/rice/detail/TupleIterator.hpp +14 -0
- data/rice/detail/Type.hpp +5 -6
- data/rice/detail/Type.ipp +150 -33
- data/rice/detail/TypeRegistry.hpp +15 -7
- data/rice/detail/TypeRegistry.ipp +105 -12
- data/rice/detail/Wrapper.hpp +6 -5
- data/rice/detail/Wrapper.ipp +45 -23
- data/rice/detail/cpp_protect.hpp +5 -6
- data/rice/detail/default_allocation_func.ipp +0 -2
- data/rice/detail/from_ruby.hpp +37 -3
- data/rice/detail/from_ruby.ipp +911 -454
- data/rice/detail/ruby.hpp +18 -0
- data/rice/detail/to_ruby.hpp +41 -3
- data/rice/detail/to_ruby.ipp +437 -113
- data/rice/global_function.hpp +0 -4
- data/rice/global_function.ipp +1 -2
- data/rice/rice.hpp +105 -22
- data/rice/ruby_mark.hpp +4 -3
- data/rice/stl.hpp +4 -0
- data/test/embed_ruby.cpp +4 -1
- data/test/extconf.rb +2 -0
- data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
- data/test/test_Address_Registration_Guard.cpp +5 -0
- data/test/test_Array.cpp +12 -1
- data/test/test_Attribute.cpp +103 -21
- data/test/test_Builtin_Object.cpp +5 -0
- data/test/test_Callback.cpp +231 -0
- data/test/test_Class.cpp +5 -31
- data/test/test_Constructor.cpp +69 -6
- data/test/test_Data_Object.cpp +9 -4
- data/test/test_Data_Type.cpp +428 -64
- data/test/test_Director.cpp +10 -5
- data/test/test_Enum.cpp +152 -40
- data/test/test_Exception.cpp +235 -0
- data/test/test_File.cpp +70 -0
- data/test/test_From_Ruby.cpp +542 -0
- data/test/test_Hash.cpp +5 -0
- data/test/test_Identifier.cpp +5 -0
- data/test/test_Inheritance.cpp +6 -1
- data/test/test_Iterator.cpp +5 -0
- data/test/test_JumpException.cpp +22 -0
- data/test/test_Keep_Alive.cpp +6 -1
- data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
- data/test/test_Memory_Management.cpp +5 -0
- data/test/test_Module.cpp +118 -64
- data/test/test_Native_Registry.cpp +2 -33
- data/test/test_Object.cpp +5 -0
- data/test/test_Overloads.cpp +631 -0
- data/test/test_Ownership.cpp +67 -4
- data/test/test_Proc.cpp +45 -0
- data/test/test_Self.cpp +5 -0
- data/test/test_Stl_Exception.cpp +109 -0
- data/test/test_Stl_Map.cpp +22 -8
- data/test/test_Stl_Optional.cpp +5 -0
- data/test/test_Stl_Pair.cpp +7 -2
- data/test/test_Stl_Reference_Wrapper.cpp +5 -0
- data/test/test_Stl_SmartPointer.cpp +210 -5
- data/test/test_Stl_String.cpp +5 -0
- data/test/test_Stl_String_View.cpp +5 -0
- data/test/test_Stl_Type.cpp +147 -0
- data/test/test_Stl_Unordered_Map.cpp +18 -7
- data/test/test_Stl_Variant.cpp +5 -0
- data/test/test_Stl_Vector.cpp +130 -8
- data/test/test_String.cpp +5 -0
- data/test/test_Struct.cpp +5 -0
- data/test/test_Symbol.cpp +5 -0
- data/test/test_Template.cpp +192 -0
- data/test/test_To_Ruby.cpp +152 -0
- data/test/test_Tracking.cpp +1 -0
- data/test/test_Type.cpp +100 -0
- data/test/test_global_functions.cpp +53 -6
- data/test/unittest.cpp +8 -0
- metadata +37 -20
- data/lib/version.rb +0 -3
- data/rice/Address_Registration_Guard_defn.hpp +0 -79
- data/rice/Data_Object_defn.hpp +0 -84
- data/rice/Data_Type_defn.hpp +0 -190
- data/rice/Exception_defn.hpp +0 -68
- data/rice/HandlerRegistration.hpp +0 -15
- data/rice/Identifier.hpp +0 -50
- data/rice/Identifier.ipp +0 -29
- data/rice/detail/ExceptionHandler.hpp +0 -8
- data/rice/detail/ExceptionHandler.ipp +0 -28
- data/rice/detail/ExceptionHandler_defn.hpp +0 -77
- data/rice/detail/Jump_Tag.hpp +0 -21
- data/rice/detail/NativeAttribute.hpp +0 -64
- data/rice/detail/NativeAttribute.ipp +0 -112
- data/rice/detail/from_ruby_defn.hpp +0 -38
- data/rice/detail/to_ruby_defn.hpp +0 -48
- data/test/test_Jump_Tag.cpp +0 -17
- data/test/test_To_From_Ruby.cpp +0 -399
data/rice/Data_Type.ipp
CHANGED
@@ -1,24 +1,9 @@
|
|
1
|
-
#ifndef Rice__Data_Type__ipp_
|
2
|
-
#define Rice__Data_Type__ipp_
|
3
|
-
|
4
|
-
#include "traits/attribute_traits.hpp"
|
5
|
-
#include "traits/method_traits.hpp"
|
6
|
-
#include "detail/NativeRegistry.hpp"
|
7
|
-
#include "detail/NativeAttribute.hpp"
|
8
|
-
#include "detail/default_allocation_func.hpp"
|
9
|
-
#include "detail/TypeRegistry.hpp"
|
10
|
-
#include "detail/Wrapper.hpp"
|
11
|
-
#include "detail/NativeIterator.hpp"
|
12
|
-
#include "cpp_api/Class.hpp"
|
13
|
-
#include "cpp_api/String.hpp"
|
14
|
-
#include "ruby_mark.hpp"
|
15
|
-
|
16
1
|
#include <stdexcept>
|
17
2
|
|
18
3
|
namespace Rice
|
19
4
|
{
|
20
5
|
template<typename T>
|
21
|
-
void ruby_mark_internal(detail::Wrapper* wrapper)
|
6
|
+
inline void ruby_mark_internal(detail::Wrapper* wrapper)
|
22
7
|
{
|
23
8
|
// Tell the wrapper to mark the objects its keeping alive
|
24
9
|
wrapper->ruby_mark();
|
@@ -29,17 +14,23 @@ namespace Rice
|
|
29
14
|
}
|
30
15
|
|
31
16
|
template<typename T>
|
32
|
-
void ruby_free_internal(detail::Wrapper* wrapper)
|
17
|
+
inline void ruby_free_internal(detail::Wrapper* wrapper)
|
33
18
|
{
|
34
19
|
delete wrapper;
|
35
20
|
}
|
36
21
|
|
37
22
|
template<typename T>
|
38
|
-
size_t ruby_size_internal(const T* data)
|
23
|
+
inline size_t ruby_size_internal(const T* data)
|
39
24
|
{
|
40
25
|
return sizeof(T);
|
41
26
|
}
|
42
27
|
|
28
|
+
template<>
|
29
|
+
inline size_t ruby_size_internal(const void* data)
|
30
|
+
{
|
31
|
+
return sizeof(void*);
|
32
|
+
}
|
33
|
+
|
43
34
|
template<typename T>
|
44
35
|
template <typename Base_T>
|
45
36
|
inline Data_Type<T> Data_Type<T>::bind(const Module& klass)
|
@@ -68,12 +59,11 @@ namespace Rice
|
|
68
59
|
// Now register with the type registry
|
69
60
|
detail::Registries::instance.types.add<T>(klass_, rb_data_type_);
|
70
61
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
(*it)->set_value(klass);
|
62
|
+
auto iter = Data_Type<T>::unbound_instances_.begin();
|
63
|
+
while (iter != Data_Type<T>::unbound_instances_.end())
|
64
|
+
{
|
65
|
+
(*iter)->set_value(klass);
|
66
|
+
iter = Data_Type<T>::unbound_instances_.erase(iter);
|
77
67
|
}
|
78
68
|
|
79
69
|
return Data_Type<T>();
|
@@ -99,7 +89,7 @@ namespace Rice
|
|
99
89
|
{
|
100
90
|
if (!is_bound())
|
101
91
|
{
|
102
|
-
|
92
|
+
this->unbound_instances_.insert(this);
|
103
93
|
}
|
104
94
|
}
|
105
95
|
|
@@ -109,12 +99,6 @@ namespace Rice
|
|
109
99
|
this->bind(klass);
|
110
100
|
}
|
111
101
|
|
112
|
-
template<typename T>
|
113
|
-
inline Data_Type<T>::~Data_Type()
|
114
|
-
{
|
115
|
-
unbound_instances().erase(this);
|
116
|
-
}
|
117
|
-
|
118
102
|
template<typename T>
|
119
103
|
inline rb_data_type_t* Data_Type<T>::ruby_data_type()
|
120
104
|
{
|
@@ -137,17 +121,50 @@ namespace Rice
|
|
137
121
|
}
|
138
122
|
|
139
123
|
template<typename T>
|
140
|
-
template<typename Constructor_T, typename...
|
141
|
-
inline Data_Type<T>& Data_Type<T>::define_constructor(Constructor_T constructor,
|
124
|
+
template<typename Constructor_T, typename...Rice_Arg_Ts>
|
125
|
+
inline Data_Type<T>& Data_Type<T>::define_constructor(Constructor_T constructor, Rice_Arg_Ts const& ...args)
|
142
126
|
{
|
143
127
|
check_is_bound();
|
144
128
|
|
145
129
|
// Define a Ruby allocator which creates the Ruby object
|
146
130
|
detail::protect(rb_define_alloc_func, static_cast<VALUE>(*this), detail::default_allocation_func<T>);
|
147
131
|
|
148
|
-
//
|
149
|
-
|
132
|
+
// We can't do anything with move constructors so blow up
|
133
|
+
static_assert(!Constructor_T::isMoveConstructor(), "Rice does not support move constructors");
|
134
|
+
|
135
|
+
// If this is a copy constructor then use it to support Ruby's Object#dup and Object#clone methods.
|
136
|
+
// Otherwise if a user calls #dup or #clone an error will occur because the newly cloned Ruby
|
137
|
+
// object will have a NULL ptr because the C++ object is never copied. This also prevents having
|
138
|
+
// very unlike Ruby code of:
|
139
|
+
//
|
140
|
+
// my_object_copy = MyObject.new(my_ojbect_original).
|
141
|
+
|
142
|
+
if constexpr (Constructor_T::isCopyConstructor())
|
143
|
+
{
|
144
|
+
// Define initialize_copy that will copy the C++ object
|
145
|
+
this->define_method("initialize_copy", &Constructor_T::initialize_copy, args...);
|
146
|
+
}
|
147
|
+
else if constexpr (Constructor_T::isMoveConstructor())
|
148
|
+
{
|
149
|
+
throw std::runtime_error("Rice does not support move constructors");
|
150
|
+
}
|
151
|
+
else
|
152
|
+
{
|
153
|
+
// Define an initialize function that will create the C++ object
|
154
|
+
this->define_method("initialize", &Constructor_T::initialize, args...);
|
155
|
+
}
|
156
|
+
|
157
|
+
return *this;
|
158
|
+
}
|
150
159
|
|
160
|
+
template<typename T>
|
161
|
+
template<typename Function_T>
|
162
|
+
inline Data_Type<T>& Data_Type<T>::define(Function_T func)
|
163
|
+
{
|
164
|
+
// The passed in this pointer is an RValue, so we need to keep it alive by
|
165
|
+
// assigning it to a const lvalue
|
166
|
+
const auto& dummy = *this;
|
167
|
+
func(*this);
|
151
168
|
return *this;
|
152
169
|
}
|
153
170
|
|
@@ -184,56 +201,84 @@ namespace Rice
|
|
184
201
|
{
|
185
202
|
if (!is_bound())
|
186
203
|
{
|
187
|
-
std::string message = "Type " + detail::typeName(typeid(T))
|
188
|
-
throw std::
|
204
|
+
std::string message = "Type is not defined with Rice: " + detail::typeName(typeid(T));
|
205
|
+
throw std::invalid_argument(message.c_str());
|
189
206
|
}
|
190
207
|
}
|
191
208
|
|
192
|
-
template<typename T
|
193
|
-
inline Data_Type<T
|
209
|
+
template<typename T>
|
210
|
+
inline bool Data_Type<T>::is_defined(Object parent, const std::string& name)
|
194
211
|
{
|
212
|
+
// Is the class already defined?
|
195
213
|
if (detail::Registries::instance.types.isDefined<T>())
|
196
214
|
{
|
197
|
-
|
215
|
+
Data_Type<T> result = Data_Type<T>();
|
216
|
+
|
217
|
+
// If this redefinition is a different name then create a new constant
|
218
|
+
if (result.name() != name)
|
219
|
+
{
|
220
|
+
detail::protect(rb_define_const, parent, name.c_str(), result.klass());
|
221
|
+
}
|
222
|
+
|
223
|
+
return true;
|
198
224
|
}
|
199
|
-
|
200
|
-
|
225
|
+
return false;
|
226
|
+
}
|
227
|
+
|
228
|
+
template<typename Base_T>
|
229
|
+
inline Class get_superklass()
|
230
|
+
{
|
231
|
+
Class result;
|
201
232
|
|
202
233
|
if constexpr (std::is_void_v<Base_T>)
|
203
234
|
{
|
204
|
-
|
235
|
+
result = rb_cObject;
|
205
236
|
}
|
206
237
|
else
|
207
238
|
{
|
208
|
-
|
239
|
+
// This gives a chance for to auto-register classes such as std::exception
|
240
|
+
detail::verifyType<Base_T>();
|
241
|
+
result = Data_Type<Base_T>::klass();
|
209
242
|
}
|
210
|
-
|
211
|
-
|
212
|
-
c.undef_creation_funcs();
|
213
|
-
return Data_Type<T>::template bind<Base_T>(c);
|
243
|
+
|
244
|
+
return result;
|
214
245
|
}
|
215
246
|
|
216
247
|
template<typename T, typename Base_T>
|
217
|
-
inline Data_Type<T>
|
248
|
+
inline Data_Type<T> define_class_under(Object parent, Identifier id, Class superKlass)
|
218
249
|
{
|
219
|
-
if (
|
250
|
+
if (Rice::Data_Type<T>::is_defined(parent, id.str()))
|
220
251
|
{
|
221
252
|
return Data_Type<T>();
|
222
253
|
}
|
223
254
|
|
224
|
-
Class superKlass;
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
255
|
+
Class klass = define_class_under(parent, id, superKlass);
|
256
|
+
klass.undef_creation_funcs();
|
257
|
+
return Data_Type<T>::template bind<Base_T>(klass);
|
258
|
+
}
|
259
|
+
|
260
|
+
template<typename T, typename Base_T>
|
261
|
+
inline Data_Type<T> define_class_under(Object parent, char const* name)
|
262
|
+
{
|
263
|
+
Identifier id(name);
|
264
|
+
Class superKlass = get_superklass<Base_T>();
|
265
|
+
return define_class_under<T, Base_T>(parent, id, superKlass);
|
266
|
+
}
|
267
|
+
|
268
|
+
template<typename T, typename Base_T>
|
269
|
+
inline Data_Type<T> define_class(char const* name)
|
270
|
+
{
|
271
|
+
std::string klassName(name);
|
272
|
+
|
273
|
+
if (Rice::Data_Type<T>::is_defined(rb_cObject, klassName))
|
230
274
|
{
|
231
|
-
|
275
|
+
return Data_Type<T>();
|
232
276
|
}
|
233
277
|
|
234
|
-
Class
|
235
|
-
|
236
|
-
|
278
|
+
Class superKlass = get_superklass<Base_T>();
|
279
|
+
Class klass = define_class(name, superKlass);
|
280
|
+
klass.undef_creation_funcs();
|
281
|
+
return Data_Type<T>::template bind<Base_T>(klass);
|
237
282
|
}
|
238
283
|
|
239
284
|
template<typename T>
|
@@ -256,8 +301,18 @@ namespace Rice
|
|
256
301
|
// Make sure the Attribute type has been previously seen by Rice
|
257
302
|
detail::verifyType<typename detail::attribute_traits<Attribute_T>::attr_type>();
|
258
303
|
|
259
|
-
// Define native attribute
|
260
|
-
|
304
|
+
// Define native attribute getter
|
305
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
|
306
|
+
detail::NativeAttributeGet<Attribute_T>::define(klass_, name, std::forward<Attribute_T>(attribute));
|
307
|
+
|
308
|
+
using Attr_T = typename detail::NativeAttributeSet<Attribute_T>::Attr_T;
|
309
|
+
if constexpr (!std::is_const_v<Attr_T> &&
|
310
|
+
(std::is_fundamental_v<Attr_T> || std::is_assignable_v<Attr_T, Attr_T>))
|
311
|
+
{
|
312
|
+
// Define native attribute setter
|
313
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
|
314
|
+
detail::NativeAttributeSet<Attribute_T>::define(klass_, name, std::forward<Attribute_T>(attribute));
|
315
|
+
}
|
261
316
|
|
262
317
|
return *this;
|
263
318
|
}
|
@@ -271,7 +326,14 @@ namespace Rice
|
|
271
326
|
|
272
327
|
// Define native attribute
|
273
328
|
VALUE singleton = detail::protect(rb_singleton_class, this->value());
|
274
|
-
|
329
|
+
|
330
|
+
// Define native attribute getter
|
331
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Read)
|
332
|
+
detail::NativeAttributeGet<Attribute_T>::define(singleton, name, std::forward<Attribute_T>(attribute));
|
333
|
+
|
334
|
+
// Define native attribute setter
|
335
|
+
if (access == AttrAccess::ReadWrite || access == AttrAccess::Write)
|
336
|
+
detail::NativeAttributeSet<Attribute_T>::define(singleton, name, std::forward<Attribute_T>(attribute));
|
275
337
|
|
276
338
|
return *this;
|
277
339
|
}
|
@@ -289,4 +351,3 @@ namespace Rice
|
|
289
351
|
detail::NativeFunction<T, Function_T, IsMethod>::define(klass, name, std::forward<Function_T>(function), methodInfo);
|
290
352
|
}
|
291
353
|
}
|
292
|
-
#endif
|
data/rice/Director.hpp
CHANGED
data/rice/Enum.hpp
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
#ifndef Rice__Enum__hpp_
|
2
2
|
#define Rice__Enum__hpp_
|
3
3
|
|
4
|
-
#include "Data_Type.hpp"
|
5
|
-
#include <map>
|
6
|
-
|
7
4
|
namespace Rice
|
8
5
|
{
|
9
6
|
/*!
|
@@ -59,9 +56,10 @@ namespace Rice
|
|
59
56
|
};
|
60
57
|
|
61
58
|
template<typename T>
|
62
|
-
Enum<T> define_enum(char const* name
|
63
|
-
} // namespace Rice
|
59
|
+
Enum<T> define_enum(char const* name);
|
64
60
|
|
65
|
-
|
61
|
+
template<typename T>
|
62
|
+
Enum<T> define_enum_under(char const* name, Module module );
|
63
|
+
} // namespace Rice
|
66
64
|
|
67
65
|
#endif // Rice__Enum__hpp_
|
data/rice/Enum.ipp
CHANGED
@@ -1,6 +1,3 @@
|
|
1
|
-
#include "detail/TypeRegistry.hpp"
|
2
|
-
#include "Data_Object.hpp"
|
3
|
-
#include "cpp_api/String.hpp"
|
4
1
|
|
5
2
|
#include <stdexcept>
|
6
3
|
|
@@ -32,57 +29,68 @@ namespace Rice
|
|
32
29
|
// First we need a constructor
|
33
30
|
klass.define_constructor(Constructor<Enum_T>());
|
34
31
|
|
35
|
-
// Instance methods
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
.define_method("
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
32
|
+
// Instance methods. The self parameter is confusing because it is really a Data_Object<Enum_T>.
|
33
|
+
// However, if we make that the type then the From_Ruby code will consider it a
|
34
|
+
// Data_Type<Data_Object<Enum_T>>>. But in define class above it was actually bound as
|
35
|
+
// Data_Type<Enum_T>. Thus the static_casts in the methods below.
|
36
|
+
klass.define_method("to_s", [](Enum_T& notSelf)
|
37
|
+
{
|
38
|
+
// We have to return string because we don't know if std::string support has
|
39
|
+
// been included by the user
|
40
|
+
Data_Object<Enum_T> self = static_cast<Data_Object<Enum_T>>(notSelf);
|
41
|
+
return String(valuesToNames_[*self]);
|
42
|
+
})
|
43
|
+
.define_method("to_int", [](Enum_T& notSelf) -> Underlying_T
|
44
|
+
{
|
45
|
+
Data_Object<Enum_T> self = static_cast<Data_Object<Enum_T>>(notSelf);
|
46
|
+
return static_cast<Underlying_T>(*self);
|
47
|
+
})
|
48
|
+
.define_method("inspect", [](Enum_T& notSelf)
|
49
|
+
{
|
50
|
+
Data_Object<Enum_T> self = static_cast<Data_Object<Enum_T>>(notSelf);
|
51
|
+
|
52
|
+
std::stringstream result;
|
53
|
+
VALUE rubyKlass = Enum<Enum_T>::klass().value();
|
54
|
+
result << "#<" << detail::protect(rb_class2name, rubyKlass)
|
55
|
+
<< "::" << Enum<Enum_T>::valuesToNames_[*self] << ">";
|
56
|
+
|
57
|
+
// We have to return string because we don't know if std::string support has
|
58
|
+
// been included by the user
|
59
|
+
return String(result.str());
|
60
|
+
})
|
61
|
+
.define_method("hash", [](Enum_T& notSelf) -> Underlying_T
|
62
|
+
{
|
63
|
+
Data_Object<Enum_T> self = static_cast<Data_Object<Enum_T>>(notSelf);
|
64
|
+
return (Underlying_T)*self;
|
65
|
+
})
|
66
|
+
.define_method("eql?", [](Enum_T& notSelf, Enum_T& notOther)
|
67
|
+
{
|
68
|
+
Data_Object<Enum_T> self = static_cast<Data_Object<Enum_T>>(notSelf);
|
69
|
+
Data_Object<Enum_T> other = static_cast<Data_Object<Enum_T>>(notOther);
|
70
|
+
return self == other;
|
71
|
+
});
|
65
72
|
|
66
73
|
// Add aliases
|
67
74
|
rb_define_alias(klass, "===", "eql?");
|
75
|
+
rb_define_alias(klass, "to_i", "to_int");
|
68
76
|
|
69
77
|
// Add comparable support
|
70
78
|
klass.include_module(rb_mComparable)
|
71
79
|
.define_method("<=>", [](Enum_T& self, Enum_T& other)
|
72
|
-
{
|
73
|
-
if (self == other)
|
74
|
-
{
|
75
|
-
return 0;
|
76
|
-
}
|
77
|
-
else if (self < other)
|
78
80
|
{
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
81
|
+
if (self == other)
|
82
|
+
{
|
83
|
+
return 0;
|
84
|
+
}
|
85
|
+
else if (self < other)
|
86
|
+
{
|
87
|
+
return -1;
|
88
|
+
}
|
89
|
+
else
|
90
|
+
{
|
91
|
+
return 1;
|
92
|
+
}
|
93
|
+
});
|
86
94
|
|
87
95
|
// Add enumerable support
|
88
96
|
klass.include_module(rb_mEnumerable)
|
@@ -91,7 +99,7 @@ namespace Rice
|
|
91
99
|
if (!rb_block_given_p())
|
92
100
|
{
|
93
101
|
return rb_enumeratorize_with_size(ruby_klass, Identifier("each").to_sym(),
|
94
|
-
|
102
|
+
0, nullptr, 0);
|
95
103
|
}
|
96
104
|
|
97
105
|
for (auto& pair : valuesToNames_)
|
@@ -102,22 +110,58 @@ namespace Rice
|
|
102
110
|
}
|
103
111
|
|
104
112
|
return ruby_klass;
|
105
|
-
|
106
|
-
|
113
|
+
}, Return().setValue());
|
114
|
+
|
115
|
+
// Add bitwise operators
|
116
|
+
klass.define_method("&", [](Enum_T& self, Enum_T& other) -> Underlying_T
|
107
117
|
{
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
118
|
+
return (Underlying_T)self & (Underlying_T)other;
|
119
|
+
})
|
120
|
+
.define_method("|", [](Enum_T& self, Enum_T& other) -> Underlying_T
|
121
|
+
{
|
122
|
+
return (Underlying_T)self | (Underlying_T)other;
|
123
|
+
})
|
124
|
+
.define_method("^", [](Enum_T& self, Enum_T& other) -> Underlying_T
|
125
|
+
{
|
126
|
+
return (Underlying_T)self ^ (Underlying_T)other;
|
127
|
+
})
|
128
|
+
.define_method("~", [](Enum_T& self) -> Underlying_T
|
129
|
+
{
|
130
|
+
return ~(Underlying_T)self;
|
131
|
+
});
|
132
|
+
|
133
|
+
// Add shift operators
|
134
|
+
klass.define_method("<<", [](Enum_T& self, int shift) -> Underlying_T
|
135
|
+
{
|
136
|
+
return (Underlying_T)self << shift;
|
137
|
+
})
|
138
|
+
.define_method(">>", [](Enum_T& self, int shift) -> Underlying_T
|
139
|
+
{
|
140
|
+
return (Underlying_T)self >> shift;
|
141
|
+
});
|
142
|
+
|
143
|
+
// Add conversions from int
|
144
|
+
klass.define_singleton_method("from_int", [](VALUE ruby_klass, int32_t value) -> Object
|
145
|
+
{
|
146
|
+
auto iter = Enum<Enum_T>::valuesToNames_.find((Enum_T)value);
|
147
|
+
if (iter == Enum<Enum_T>::valuesToNames_.end())
|
148
|
+
{
|
149
|
+
throw std::runtime_error("Unknown enum value: " + std::to_string(value));
|
150
|
+
}
|
113
151
|
|
114
|
-
|
115
|
-
|
152
|
+
std::string name = iter->second;
|
153
|
+
return Object(ruby_klass).const_get(name);
|
116
154
|
});
|
117
155
|
}
|
118
156
|
|
119
157
|
template<typename Enum_T>
|
120
|
-
Enum<Enum_T> define_enum(char const* name
|
158
|
+
Enum<Enum_T> define_enum(char const* name)
|
159
|
+
{
|
160
|
+
return define_enum_under<Enum_T>(name, rb_cObject);
|
161
|
+
}
|
162
|
+
|
163
|
+
template<typename Enum_T>
|
164
|
+
Enum<Enum_T> define_enum_under(char const* name, Module module)
|
121
165
|
{
|
122
166
|
if (detail::Registries::instance.types.isDefined<Enum_T>())
|
123
167
|
{
|
data/rice/Exception.hpp
CHANGED
@@ -1,7 +1,67 @@
|
|
1
1
|
#ifndef Rice__Exception__hpp_
|
2
2
|
#define Rice__Exception__hpp_
|
3
3
|
|
4
|
-
#include
|
5
|
-
|
4
|
+
#include <stdexcept>
|
5
|
+
|
6
|
+
namespace Rice
|
7
|
+
{
|
8
|
+
//! A placeholder for Ruby exceptions.
|
9
|
+
/*! You can use this to safely throw a Ruby exception using C++ syntax:
|
10
|
+
* \code
|
11
|
+
* VALUE foo(VALUE self) {
|
12
|
+
* RUBY_TRY {
|
13
|
+
* throw Rice::Exception(rb_eMyException, "uh oh!");
|
14
|
+
* RUBY_CATCH
|
15
|
+
* }
|
16
|
+
* \endcode
|
17
|
+
*/
|
18
|
+
class Exception
|
19
|
+
: public std::exception
|
20
|
+
{
|
21
|
+
public:
|
22
|
+
//! Construct a Exception with a Ruby exception instance
|
23
|
+
explicit Exception(VALUE exception);
|
24
|
+
|
25
|
+
//! Construct a Exception with printf-style formatting.
|
26
|
+
/*! \param exc either an exception object or a class that inherits
|
27
|
+
* from Exception.
|
28
|
+
* \param fmt a printf-style format string
|
29
|
+
* \param ... the arguments to the format string.
|
30
|
+
*/
|
31
|
+
template <typename... Arg_Ts>
|
32
|
+
Exception(const Exception& other, char const* fmt, Arg_Ts&&...args);
|
33
|
+
|
34
|
+
//! Construct a Exception with printf-style formatting.
|
35
|
+
/*! \param exc either an exception object or a class that inherits
|
36
|
+
* from Exception.
|
37
|
+
* \param fmt a printf-style format string
|
38
|
+
* \param ... the arguments to the format string.
|
39
|
+
*/
|
40
|
+
template <typename... Arg_Ts>
|
41
|
+
Exception(const VALUE exceptionType, char const* fmt, Arg_Ts&&...args);
|
42
|
+
|
43
|
+
//! Destructor
|
44
|
+
virtual ~Exception() noexcept = default;
|
45
|
+
|
46
|
+
//! Get message as a char const *.
|
47
|
+
/*! If message is a non-string object, then this function will attempt
|
48
|
+
* to throw an exception (which it can't do because of the no-throw
|
49
|
+
* specification).
|
50
|
+
* \return the underlying C pointer of the underlying message object.
|
51
|
+
*/
|
52
|
+
virtual char const* what() const noexcept override;
|
53
|
+
|
54
|
+
//! Returns the Ruby exception class
|
55
|
+
VALUE class_of() const;
|
56
|
+
|
57
|
+
//! Returns an instance of a Ruby exception
|
58
|
+
VALUE value() const;
|
59
|
+
|
60
|
+
private:
|
61
|
+
// TODO: Do we need to tell the Ruby gc about an exception instance?
|
62
|
+
mutable VALUE exception_ = Qnil;
|
63
|
+
mutable std::string message_;
|
64
|
+
};
|
65
|
+
} // namespace Rice
|
6
66
|
|
7
67
|
#endif // Rice__Exception__hpp_
|
data/rice/Exception.ipp
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
#ifndef Rice__Exception__ipp_
|
2
|
-
#define Rice__Exception__ipp_
|
3
|
-
|
4
|
-
#include "detail/from_ruby.hpp"
|
5
1
|
|
6
2
|
namespace Rice
|
7
3
|
{
|
@@ -18,10 +14,10 @@ namespace Rice
|
|
18
14
|
template <typename... Arg_Ts>
|
19
15
|
inline Exception::Exception(const VALUE exceptionClass, char const* fmt, Arg_Ts&&...args)
|
20
16
|
{
|
21
|
-
#
|
22
|
-
#pragma GCC diagnostic push
|
23
|
-
#pragma GCC diagnostic ignored "-Wformat-security"
|
24
|
-
#endif
|
17
|
+
#if defined(__GNUC__) || defined(__clang__)
|
18
|
+
#pragma GCC diagnostic push
|
19
|
+
#pragma GCC diagnostic ignored "-Wformat-security"
|
20
|
+
#endif
|
25
21
|
|
26
22
|
size_t size = std::snprintf(nullptr, 0, fmt, std::forward<Arg_Ts>(args)...);
|
27
23
|
this->message_ = std::string(size, '\0');
|
@@ -31,9 +27,9 @@ namespace Rice
|
|
31
27
|
// will add a null character internally at n + 1
|
32
28
|
std::snprintf(&this->message_[0], size + 1, fmt, std::forward<Arg_Ts>(args)...);
|
33
29
|
|
34
|
-
#
|
35
|
-
#pragma GCC diagnostic pop
|
36
|
-
#endif
|
30
|
+
#if defined(__GNUC__) || defined(__clang__)
|
31
|
+
#pragma GCC diagnostic pop
|
32
|
+
#endif
|
37
33
|
|
38
34
|
// Now create the Ruby exception
|
39
35
|
this->exception_ = detail::protect(rb_exc_new2, exceptionClass, this->message_.c_str());
|
@@ -61,4 +57,3 @@ namespace Rice
|
|
61
57
|
return this->exception_;
|
62
58
|
}
|
63
59
|
}
|
64
|
-
#endif // Rice__Exception__ipp_
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#ifndef Rice__JumpException__hpp_
|
2
|
+
#define Rice__JumpException__hpp_
|
3
|
+
|
4
|
+
namespace Rice
|
5
|
+
{
|
6
|
+
//! A placeholder for Ruby longjmp data.
|
7
|
+
/*! When a Ruby exception is caught, the tag used for the longjmp is stored in
|
8
|
+
* a Jump_Tag, then later passed to rb_jump_tag() when there is no more
|
9
|
+
* C++ code to pass over.
|
10
|
+
*/
|
11
|
+
class JumpException : public std::exception
|
12
|
+
{
|
13
|
+
public:
|
14
|
+
// Copied from vm_core.h
|
15
|
+
enum ruby_tag_type {
|
16
|
+
RUBY_TAG_NONE = 0x0,
|
17
|
+
RUBY_TAG_RETURN = 0x1,
|
18
|
+
RUBY_TAG_BREAK = 0x2,
|
19
|
+
RUBY_TAG_NEXT = 0x3,
|
20
|
+
RUBY_TAG_RETRY = 0x4,
|
21
|
+
RUBY_TAG_REDO = 0x5,
|
22
|
+
RUBY_TAG_RAISE = 0x6,
|
23
|
+
RUBY_TAG_THROW = 0x7,
|
24
|
+
RUBY_TAG_FATAL = 0x8,
|
25
|
+
RUBY_TAG_MASK = 0xf
|
26
|
+
};
|
27
|
+
|
28
|
+
public:
|
29
|
+
JumpException(ruby_tag_type tag);
|
30
|
+
virtual const char* what() const noexcept override;
|
31
|
+
|
32
|
+
public:
|
33
|
+
//! The tag being held.
|
34
|
+
ruby_tag_type tag;
|
35
|
+
|
36
|
+
private:
|
37
|
+
void createMessage();
|
38
|
+
|
39
|
+
private:
|
40
|
+
std::string message_;
|
41
|
+
};
|
42
|
+
} // namespace Rice
|
43
|
+
|
44
|
+
#endif // Rice__JumpException__hpp_
|