rice 4.3.3 → 4.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -26
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7291 -4430
  6. data/include/rice/stl.hpp +769 -222
  7. data/lib/mkmf-rice.rb +37 -95
  8. data/rice/Address_Registration_Guard.hpp +72 -3
  9. data/rice/Arg.hpp +19 -5
  10. data/rice/Arg.ipp +24 -0
  11. data/rice/Callback.hpp +21 -0
  12. data/rice/Callback.ipp +13 -0
  13. data/rice/Constructor.hpp +4 -27
  14. data/rice/Constructor.ipp +79 -0
  15. data/rice/Data_Object.hpp +74 -3
  16. data/rice/Data_Object.ipp +324 -32
  17. data/rice/Data_Type.hpp +215 -3
  18. data/rice/Data_Type.ipp +125 -64
  19. data/rice/Director.hpp +0 -2
  20. data/rice/Enum.hpp +4 -6
  21. data/rice/Enum.ipp +101 -57
  22. data/rice/Exception.hpp +62 -2
  23. data/rice/Exception.ipp +7 -12
  24. data/rice/JumpException.hpp +44 -0
  25. data/rice/JumpException.ipp +48 -0
  26. data/rice/MemoryView.hpp +11 -0
  27. data/rice/MemoryView.ipp +43 -0
  28. data/rice/Return.hpp +6 -26
  29. data/rice/Return.ipp +10 -16
  30. data/rice/detail/DefaultHandler.hpp +12 -0
  31. data/rice/detail/DefaultHandler.ipp +8 -0
  32. data/rice/detail/HandlerRegistry.hpp +5 -35
  33. data/rice/detail/HandlerRegistry.ipp +7 -11
  34. data/rice/detail/InstanceRegistry.hpp +1 -4
  35. data/rice/detail/MethodInfo.hpp +15 -5
  36. data/rice/detail/MethodInfo.ipp +78 -6
  37. data/rice/detail/Native.hpp +32 -0
  38. data/rice/detail/Native.ipp +129 -0
  39. data/rice/detail/NativeAttributeGet.hpp +51 -0
  40. data/rice/detail/NativeAttributeGet.ipp +51 -0
  41. data/rice/detail/NativeAttributeSet.hpp +43 -0
  42. data/rice/detail/NativeAttributeSet.ipp +82 -0
  43. data/rice/detail/NativeCallbackFFI.hpp +55 -0
  44. data/rice/detail/NativeCallbackFFI.ipp +151 -0
  45. data/rice/detail/NativeCallbackSimple.hpp +30 -0
  46. data/rice/detail/NativeCallbackSimple.ipp +29 -0
  47. data/rice/detail/NativeFunction.hpp +20 -21
  48. data/rice/detail/NativeFunction.ipp +199 -64
  49. data/rice/detail/NativeIterator.hpp +8 -11
  50. data/rice/detail/NativeIterator.ipp +27 -31
  51. data/rice/detail/NativeRegistry.hpp +24 -15
  52. data/rice/detail/NativeRegistry.ipp +23 -48
  53. data/rice/detail/Proc.hpp +4 -0
  54. data/rice/detail/Proc.ipp +85 -0
  55. data/rice/detail/Registries.hpp +0 -7
  56. data/rice/detail/Registries.ipp +0 -18
  57. data/rice/detail/RubyFunction.hpp +0 -3
  58. data/rice/detail/RubyFunction.ipp +4 -8
  59. data/rice/detail/RubyType.hpp +19 -0
  60. data/rice/detail/RubyType.ipp +187 -0
  61. data/rice/detail/TupleIterator.hpp +14 -0
  62. data/rice/detail/Type.hpp +5 -6
  63. data/rice/detail/Type.ipp +150 -33
  64. data/rice/detail/TypeRegistry.hpp +15 -7
  65. data/rice/detail/TypeRegistry.ipp +105 -12
  66. data/rice/detail/Wrapper.hpp +6 -5
  67. data/rice/detail/Wrapper.ipp +45 -23
  68. data/rice/detail/cpp_protect.hpp +5 -6
  69. data/rice/detail/default_allocation_func.ipp +0 -2
  70. data/rice/detail/from_ruby.hpp +37 -3
  71. data/rice/detail/from_ruby.ipp +911 -454
  72. data/rice/detail/ruby.hpp +18 -0
  73. data/rice/detail/to_ruby.hpp +41 -3
  74. data/rice/detail/to_ruby.ipp +437 -113
  75. data/rice/global_function.hpp +0 -4
  76. data/rice/global_function.ipp +1 -2
  77. data/rice/rice.hpp +105 -22
  78. data/rice/ruby_mark.hpp +4 -3
  79. data/rice/stl.hpp +4 -0
  80. data/test/embed_ruby.cpp +4 -1
  81. data/test/extconf.rb +2 -0
  82. data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
  83. data/test/test_Address_Registration_Guard.cpp +5 -0
  84. data/test/test_Array.cpp +12 -1
  85. data/test/test_Attribute.cpp +103 -21
  86. data/test/test_Builtin_Object.cpp +5 -0
  87. data/test/test_Callback.cpp +231 -0
  88. data/test/test_Class.cpp +5 -31
  89. data/test/test_Constructor.cpp +69 -6
  90. data/test/test_Data_Object.cpp +9 -4
  91. data/test/test_Data_Type.cpp +428 -64
  92. data/test/test_Director.cpp +10 -5
  93. data/test/test_Enum.cpp +152 -40
  94. data/test/test_Exception.cpp +235 -0
  95. data/test/test_File.cpp +70 -0
  96. data/test/test_From_Ruby.cpp +542 -0
  97. data/test/test_Hash.cpp +5 -0
  98. data/test/test_Identifier.cpp +5 -0
  99. data/test/test_Inheritance.cpp +6 -1
  100. data/test/test_Iterator.cpp +5 -0
  101. data/test/test_JumpException.cpp +22 -0
  102. data/test/test_Keep_Alive.cpp +6 -1
  103. data/test/test_Keep_Alive_No_Wrapper.cpp +5 -0
  104. data/test/test_Memory_Management.cpp +5 -0
  105. data/test/test_Module.cpp +118 -64
  106. data/test/test_Native_Registry.cpp +2 -33
  107. data/test/test_Object.cpp +5 -0
  108. data/test/test_Overloads.cpp +631 -0
  109. data/test/test_Ownership.cpp +67 -4
  110. data/test/test_Proc.cpp +45 -0
  111. data/test/test_Self.cpp +5 -0
  112. data/test/test_Stl_Exception.cpp +109 -0
  113. data/test/test_Stl_Map.cpp +22 -8
  114. data/test/test_Stl_Optional.cpp +5 -0
  115. data/test/test_Stl_Pair.cpp +7 -2
  116. data/test/test_Stl_Reference_Wrapper.cpp +5 -0
  117. data/test/test_Stl_SmartPointer.cpp +210 -5
  118. data/test/test_Stl_String.cpp +5 -0
  119. data/test/test_Stl_String_View.cpp +5 -0
  120. data/test/test_Stl_Type.cpp +147 -0
  121. data/test/test_Stl_Unordered_Map.cpp +18 -7
  122. data/test/test_Stl_Variant.cpp +5 -0
  123. data/test/test_Stl_Vector.cpp +130 -8
  124. data/test/test_String.cpp +5 -0
  125. data/test/test_Struct.cpp +5 -0
  126. data/test/test_Symbol.cpp +5 -0
  127. data/test/test_Template.cpp +192 -0
  128. data/test/test_To_Ruby.cpp +152 -0
  129. data/test/test_Tracking.cpp +1 -0
  130. data/test/test_Type.cpp +100 -0
  131. data/test/test_global_functions.cpp +53 -6
  132. data/test/unittest.cpp +8 -0
  133. metadata +37 -20
  134. data/lib/version.rb +0 -3
  135. data/rice/Address_Registration_Guard_defn.hpp +0 -79
  136. data/rice/Data_Object_defn.hpp +0 -84
  137. data/rice/Data_Type_defn.hpp +0 -190
  138. data/rice/Exception_defn.hpp +0 -68
  139. data/rice/HandlerRegistration.hpp +0 -15
  140. data/rice/Identifier.hpp +0 -50
  141. data/rice/Identifier.ipp +0 -29
  142. data/rice/detail/ExceptionHandler.hpp +0 -8
  143. data/rice/detail/ExceptionHandler.ipp +0 -28
  144. data/rice/detail/ExceptionHandler_defn.hpp +0 -77
  145. data/rice/detail/Jump_Tag.hpp +0 -21
  146. data/rice/detail/NativeAttribute.hpp +0 -64
  147. data/rice/detail/NativeAttribute.ipp +0 -112
  148. data/rice/detail/from_ruby_defn.hpp +0 -38
  149. data/rice/detail/to_ruby_defn.hpp +0 -48
  150. data/test/test_Jump_Tag.cpp +0 -17
  151. 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
- for (typename Instances::iterator it = unbound_instances().begin(),
72
- end = unbound_instances().end();
73
- it != end;
74
- unbound_instances().erase(it++))
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
- unbound_instances().insert(this);
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...Arg_Ts>
141
- inline Data_Type<T>& Data_Type<T>::define_constructor(Constructor_T constructor, Arg_Ts const& ...args)
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
- // Define an initialize function that will create the C++ object
149
- this->define_method("initialize", &Constructor_T::construct, args...);
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)) + " is not bound";
188
- throw std::runtime_error(message.c_str());
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, typename Base_T>
193
- inline Data_Type<T> define_class_under(Object module, char const* name)
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
- return Data_Type<T>();
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
- Class superKlass;
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
- superKlass = rb_cObject;
235
+ result = rb_cObject;
205
236
  }
206
237
  else
207
238
  {
208
- superKlass = Data_Type<Base_T>::klass();
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
- Class c = define_class_under(module, name, superKlass);
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> define_class(char const* name)
248
+ inline Data_Type<T> define_class_under(Object parent, Identifier id, Class superKlass)
218
249
  {
219
- if (detail::Registries::instance.types.isDefined<T>())
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
- if constexpr (std::is_void_v<Base_T>)
226
- {
227
- superKlass = rb_cObject;
228
- }
229
- else
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
- superKlass = Data_Type<Base_T>::klass();
275
+ return Data_Type<T>();
232
276
  }
233
277
 
234
- Class c = define_class(name, superKlass);
235
- c.undef_creation_funcs();
236
- return Data_Type<T>::template bind<Base_T>(c);
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
- detail::NativeAttribute<Attribute_T>::define(klass_, name, std::forward<Attribute_T>(attribute), access);
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
- detail::NativeAttribute<Attribute_T>::define(singleton, name, std::forward<Attribute_T>(attribute), access);
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
@@ -1,8 +1,6 @@
1
1
  #ifndef Rice__Director__hpp_
2
2
  #define Rice__Director__hpp_
3
3
 
4
- #include "cpp_api/Object.hpp"
5
-
6
4
  namespace Rice
7
5
  {
8
6
  /**
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, Module module = rb_cObject);
63
- } // namespace Rice
59
+ Enum<T> define_enum(char const* name);
64
60
 
65
- #include "Enum.ipp"
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
- klass.define_method("to_s", [](Enum_T& self)
37
- {
38
- // We have to return string because we don't know if std::string support has
39
- // been included by the user
40
- return String(valuesToNames_[self]);
41
- })
42
- .define_method("to_i", [](Enum_T& self) -> Underlying_T
43
- {
44
- return (Underlying_T)self;
45
- })
46
- .define_method("inspect", [](Enum_T& self)
47
- {
48
- std::stringstream result;
49
- VALUE rubyKlass = Enum<Enum_T>::klass().value();
50
- result << "#<" << detail::protect(rb_class2name, rubyKlass)
51
- << "::" << Enum<Enum_T>::valuesToNames_[self] << ">";
52
-
53
- // We have to return string because we don't know if std::string support has
54
- // been included by the user
55
- return String(result.str());
56
- })
57
- .define_method("hash", [](Enum_T& self) -> Underlying_T
58
- {
59
- return (Underlying_T)self;
60
- })
61
- .define_method("eql?", [](Enum_T& self, Enum_T& other)
62
- {
63
- return self == other;
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
- return -1;
80
- }
81
- else
82
- {
83
- return 1;
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
- 0, nullptr, 0);
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
- }, Return().setValue())
106
- .define_singleton_method("from_int", [](VALUE ruby_klass, int32_t value) -> Object
113
+ }, Return().setValue());
114
+
115
+ // Add bitwise operators
116
+ klass.define_method("&", [](Enum_T& self, Enum_T& other) -> Underlying_T
107
117
  {
108
- auto iter = Enum<Enum_T>::valuesToNames_.find((Enum_T)value);
109
- if (iter == Enum<Enum_T>::valuesToNames_.end())
110
- {
111
- throw std::runtime_error("Unknown enum value: " + std::to_string(value));
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
- std::string name = iter->second;
115
- return Object(ruby_klass).const_get(name);
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, Module module)
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 "Exception_defn.hpp"
5
- #include "Exception.ipp"
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
- #ifdef __GNUC__
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
- #ifdef __GNUC__
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_