rice 4.3.2 → 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.
Files changed (151) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -25
  3. data/README.md +7 -2
  4. data/Rakefile +7 -1
  5. data/include/rice/rice.hpp +7321 -4470
  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 -17
  52. data/rice/detail/NativeRegistry.ipp +23 -56
  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_