rice 4.0.4 → 4.2.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/CONTRIBUTORS.md +2 -0
  4. data/Rakefile +1 -1
  5. data/include/rice/rice.hpp +2851 -1955
  6. data/include/rice/stl.hpp +1654 -287
  7. data/lib/mkmf-rice.rb +5 -2
  8. data/lib/version.rb +1 -1
  9. data/rice/Arg.hpp +6 -6
  10. data/rice/Arg.ipp +8 -9
  11. data/rice/Constructor.hpp +2 -2
  12. data/rice/Data_Object.ipp +69 -15
  13. data/rice/Data_Object_defn.hpp +1 -15
  14. data/rice/Data_Type.ipp +56 -86
  15. data/rice/Data_Type_defn.hpp +14 -17
  16. data/rice/Director.hpp +0 -1
  17. data/rice/Enum.ipp +31 -22
  18. data/rice/Exception.ipp +2 -3
  19. data/rice/Exception_defn.hpp +5 -5
  20. data/rice/HandlerRegistration.hpp +15 -0
  21. data/rice/Return.hpp +5 -4
  22. data/rice/Return.ipp +8 -3
  23. data/rice/detail/ExceptionHandler.hpp +8 -0
  24. data/rice/detail/ExceptionHandler.ipp +28 -0
  25. data/rice/detail/{Exception_Handler_defn.hpp → ExceptionHandler_defn.hpp} +17 -21
  26. data/rice/detail/HandlerRegistry.hpp +51 -0
  27. data/rice/detail/HandlerRegistry.ipp +20 -0
  28. data/rice/detail/InstanceRegistry.hpp +34 -0
  29. data/rice/detail/InstanceRegistry.ipp +50 -0
  30. data/rice/detail/MethodInfo.ipp +1 -1
  31. data/rice/detail/NativeAttribute.hpp +26 -15
  32. data/rice/detail/NativeAttribute.ipp +76 -47
  33. data/rice/detail/NativeFunction.hpp +64 -14
  34. data/rice/detail/NativeFunction.ipp +138 -86
  35. data/rice/detail/NativeIterator.hpp +49 -0
  36. data/rice/detail/NativeIterator.ipp +102 -0
  37. data/rice/detail/NativeRegistry.hpp +31 -0
  38. data/rice/detail/{method_data.ipp → NativeRegistry.ipp} +20 -16
  39. data/rice/detail/Registries.hpp +26 -0
  40. data/rice/detail/Registries.ipp +23 -0
  41. data/rice/detail/RubyFunction.hpp +6 -11
  42. data/rice/detail/RubyFunction.ipp +10 -22
  43. data/rice/detail/Type.hpp +1 -1
  44. data/rice/detail/Type.ipp +2 -2
  45. data/rice/detail/TypeRegistry.hpp +8 -11
  46. data/rice/detail/TypeRegistry.ipp +3 -28
  47. data/rice/detail/Wrapper.hpp +0 -2
  48. data/rice/detail/Wrapper.ipp +74 -24
  49. data/rice/detail/cpp_protect.hpp +93 -0
  50. data/rice/detail/default_allocation_func.ipp +1 -1
  51. data/rice/detail/from_ruby.ipp +206 -2
  52. data/rice/detail/to_ruby.ipp +39 -5
  53. data/rice/detail/to_ruby_defn.hpp +1 -1
  54. data/rice/forward_declares.ipp +6 -0
  55. data/rice/global_function.hpp +0 -4
  56. data/rice/global_function.ipp +0 -6
  57. data/rice/rice.hpp +29 -24
  58. data/rice/stl.hpp +6 -1
  59. data/sample/callbacks/extconf.rb +0 -1
  60. data/sample/enum/extconf.rb +0 -1
  61. data/sample/inheritance/extconf.rb +0 -1
  62. data/sample/map/extconf.rb +0 -1
  63. data/test/embed_ruby.cpp +6 -15
  64. data/test/ext/t1/extconf.rb +0 -1
  65. data/test/ext/t2/extconf.rb +0 -1
  66. data/test/extconf.rb +0 -1
  67. data/test/test_Array.cpp +20 -24
  68. data/test/test_Attribute.cpp +6 -6
  69. data/test/test_Class.cpp +8 -47
  70. data/test/test_Constructor.cpp +0 -2
  71. data/test/test_Data_Object.cpp +25 -11
  72. data/test/test_Data_Type.cpp +124 -28
  73. data/test/test_Director.cpp +12 -13
  74. data/test/test_Enum.cpp +65 -26
  75. data/test/test_Inheritance.cpp +9 -9
  76. data/test/test_Iterator.cpp +134 -5
  77. data/test/test_Keep_Alive.cpp +7 -7
  78. data/test/test_Keep_Alive_No_Wrapper.cpp +80 -0
  79. data/test/test_Memory_Management.cpp +1 -1
  80. data/test/test_Module.cpp +25 -62
  81. data/test/test_Object.cpp +75 -3
  82. data/test/test_Ownership.cpp +12 -13
  83. data/test/test_Self.cpp +12 -13
  84. data/test/test_Stl_Map.cpp +696 -0
  85. data/test/test_Stl_Optional.cpp +3 -3
  86. data/test/test_Stl_Pair.cpp +38 -2
  87. data/test/test_Stl_Reference_Wrapper.cpp +102 -0
  88. data/test/test_Stl_SmartPointer.cpp +49 -9
  89. data/test/test_Stl_String.cpp +5 -2
  90. data/test/test_Stl_Unordered_Map.cpp +697 -0
  91. data/test/test_Stl_Variant.cpp +346 -0
  92. data/test/test_Stl_Vector.cpp +200 -41
  93. data/test/test_Struct.cpp +3 -3
  94. data/test/test_To_From_Ruby.cpp +8 -2
  95. data/test/test_Tracking.cpp +239 -0
  96. data/test/unittest.hpp +21 -4
  97. metadata +24 -13
  98. data/rice/detail/Exception_Handler.hpp +0 -8
  99. data/rice/detail/Exception_Handler.ipp +0 -28
  100. data/rice/detail/Iterator.hpp +0 -23
  101. data/rice/detail/Iterator.ipp +0 -47
  102. data/rice/detail/function_traits.hpp +0 -124
  103. data/rice/detail/method_data.hpp +0 -29
  104. data/rice/detail/rice_traits.hpp +0 -116
  105. data/rice/ruby_try_catch.hpp +0 -86
@@ -1,4 +1,5 @@
1
1
  #include <memory>
2
+ #include "InstanceRegistry.hpp"
2
3
 
3
4
  namespace Rice::detail
4
5
  {
@@ -23,6 +24,11 @@ namespace Rice::detail
23
24
  {
24
25
  }
25
26
 
27
+ ~WrapperValue()
28
+ {
29
+ Registries::instance.instances.remove(this->get());
30
+ }
31
+
26
32
  void* get() override
27
33
  {
28
34
  return (void*)&this->data_;
@@ -36,8 +42,13 @@ namespace Rice::detail
36
42
  class WrapperReference : public Wrapper
37
43
  {
38
44
  public:
39
- WrapperReference(const T& data): data_(data)
45
+ WrapperReference(T& data): data_(data)
46
+ {
47
+ }
48
+
49
+ ~WrapperReference()
40
50
  {
51
+ Registries::instance.instances.remove(this->get());
41
52
  }
42
53
 
43
54
  void* get() override
@@ -46,7 +57,7 @@ namespace Rice::detail
46
57
  }
47
58
 
48
59
  private:
49
- const T& data_;
60
+ T& data_;
50
61
  };
51
62
 
52
63
  template <typename T>
@@ -59,6 +70,8 @@ namespace Rice::detail
59
70
 
60
71
  ~WrapperPointer()
61
72
  {
73
+ Registries::instance.instances.remove(this->get());
74
+
62
75
  if (this->isOwner_)
63
76
  {
64
77
  delete this->data_;
@@ -79,53 +92,76 @@ namespace Rice::detail
79
92
  template <typename T, typename Wrapper_T>
80
93
  inline VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T& data, bool isOwner)
81
94
  {
95
+ VALUE result = Registries::instance.instances.lookup(&data);
96
+
97
+ if (result != Qnil)
98
+ return result;
99
+
100
+ Wrapper* wrapper = nullptr;
101
+
82
102
  if constexpr (!std::is_void_v<Wrapper_T>)
83
103
  {
84
- Wrapper_T* wrapper = new Wrapper_T(data);
85
- return TypedData_Wrap_Struct(klass, rb_type, wrapper);
104
+ wrapper = new Wrapper_T(data);
105
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
86
106
  }
87
107
  else if (isOwner)
88
108
  {
89
- WrapperValue<T>* wrapper = new WrapperValue<T>(data);
90
- return TypedData_Wrap_Struct(klass, rb_type, wrapper);
109
+ wrapper = new WrapperValue<T>(data);
110
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
91
111
  }
92
112
  else
93
113
  {
94
- WrapperReference<T>* wrapper = new WrapperReference<T>(data);
95
- return TypedData_Wrap_Struct(klass, rb_type, wrapper);
114
+ wrapper = new WrapperReference<T>(data);
115
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
96
116
  }
117
+
118
+ Registries::instance.instances.add(wrapper->get(), result);
119
+
120
+ return result;
97
121
  };
98
122
 
99
123
  template <typename T, typename Wrapper_T>
100
124
  inline VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T* data, bool isOwner)
101
125
  {
126
+ VALUE result = Registries::instance.instances.lookup(data);
127
+
128
+ if (result != Qnil)
129
+ return result;
130
+
131
+ Wrapper* wrapper = nullptr;
132
+
102
133
  if constexpr (!std::is_void_v<Wrapper_T>)
103
134
  {
104
- Wrapper_T* wrapper = new Wrapper_T(data);
105
- return TypedData_Wrap_Struct(klass, rb_type, wrapper);
135
+ wrapper = new Wrapper_T(data);
136
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
106
137
  }
107
138
  else
108
139
  {
109
- WrapperPointer<T>* wrapper = new WrapperPointer<T>(data, isOwner);
110
- return TypedData_Wrap_Struct(klass, rb_type, wrapper);
140
+ wrapper = new WrapperPointer<T>(data, isOwner);
141
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
111
142
  }
143
+
144
+ Registries::instance.instances.add(wrapper->get(), result);
145
+ return result;
112
146
  };
113
147
 
114
148
  template <typename T>
115
149
  inline T* unwrap(VALUE value, rb_data_type_t* rb_type)
116
150
  {
117
151
  Wrapper* wrapper = getWrapper(value, rb_type);
118
- TypedData_Get_Struct(value, Wrapper, rb_type, wrapper);
119
- return static_cast<T*>(wrapper->get());
120
- }
121
152
 
122
- inline void* unwrap(VALUE value)
123
- {
124
- // Direct access to avoid any type checking
125
- Wrapper* wrapper = (Wrapper*)RTYPEDDATA_DATA(value);
126
- return wrapper->get();
127
- }
153
+ if (wrapper == nullptr)
154
+ {
155
+ std::string message = "Wrapped C++ object is nil. Did you override " +
156
+ std::string(detail::protect(rb_obj_classname, value)) +
157
+ "#initialize and forget to call super?";
128
158
 
159
+ throw std::runtime_error(message);
160
+ }
161
+
162
+ return static_cast<T*>(wrapper->get());
163
+ }
164
+
129
165
  inline Wrapper* getWrapper(VALUE value, rb_data_type_t* rb_type)
130
166
  {
131
167
  Wrapper* wrapper = nullptr;
@@ -138,14 +174,28 @@ namespace Rice::detail
138
174
  {
139
175
  WrapperPointer<T>* wrapper = nullptr;
140
176
  TypedData_Get_Struct(value, WrapperPointer<T>, rb_type, wrapper);
141
- delete wrapper;
177
+ if (wrapper)
178
+ {
179
+ Registries::instance.instances.remove(wrapper->get());
180
+ delete wrapper;
181
+ }
142
182
 
143
- wrapper = new WrapperPointer<T>(data, true);
183
+ wrapper = new WrapperPointer<T>(data, isOwner);
144
184
  RTYPEDDATA_DATA(value) = wrapper;
185
+
186
+ Registries::instance.instances.add(data, value);
145
187
  }
146
188
 
147
189
  inline Wrapper* getWrapper(VALUE value)
148
190
  {
149
- return static_cast<Wrapper*>(RTYPEDDATA_DATA(value));
191
+ // Turn off spurious warning on g++ 12
192
+ #ifdef __GNUC__
193
+ #pragma GCC diagnostic push
194
+ #pragma GCC diagnostic ignored "-Warray-bounds"
195
+ #endif
196
+ return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
197
+ #ifdef __GNUC__
198
+ #pragma GCC diagnostic pop
199
+ #endif
150
200
  }
151
201
  } // namespace
@@ -0,0 +1,93 @@
1
+ #ifndef Rice__detail__cpp_protect__hpp_
2
+ #define Rice__detail__cpp_protect__hpp_
3
+
4
+ #include <regex>
5
+ #include <filesystem>
6
+ #include <stdexcept>
7
+
8
+ #include "Jump_Tag.hpp"
9
+ #include "../Exception_defn.hpp"
10
+
11
+ namespace Rice::detail
12
+ {
13
+ template <typename Callable_T>
14
+ auto cpp_protect(Callable_T&& func)
15
+ {
16
+ try
17
+ {
18
+ return func();
19
+ }
20
+ catch (...)
21
+ {
22
+ try
23
+ {
24
+ detail::Registries::instance.handlers.handler()->handle();
25
+ }
26
+ catch (::Rice::Exception const& ex)
27
+ {
28
+ rb_exc_raise(ex.value());
29
+ }
30
+ catch (::Rice::Jump_Tag const& ex)
31
+ {
32
+ rb_jump_tag(ex.tag);
33
+ }
34
+ catch (std::bad_alloc const& ex)
35
+ {
36
+ /* This won't work quite right if the rb_exc_new2 fails; not
37
+ much we can do about that, since Ruby doesn't give us access
38
+ to a pre-allocated NoMemoryError object */
39
+ rb_exc_raise(rb_exc_new2(rb_eNoMemError, ex.what()));
40
+ }
41
+ catch (std::domain_error const& ex)
42
+ {
43
+ rb_exc_raise(rb_exc_new2(rb_eFloatDomainError, ex.what()));
44
+ }
45
+ catch (std::invalid_argument const& ex)
46
+ {
47
+ rb_exc_raise(rb_exc_new2(rb_eArgError, ex.what()));
48
+ }
49
+ catch (std::filesystem::filesystem_error const& ex)
50
+ {
51
+ rb_exc_raise(rb_exc_new2(rb_eIOError, ex.what()));
52
+ }
53
+ catch (std::length_error const& ex)
54
+ {
55
+ rb_exc_raise(rb_exc_new2(rb_eRuntimeError, ex.what()));
56
+ }
57
+ catch (std::out_of_range const& ex)
58
+ {
59
+ rb_exc_raise(rb_exc_new2(rb_eRangeError, ex.what()));
60
+ }
61
+ catch (std::overflow_error const& ex)
62
+ {
63
+ rb_exc_raise(rb_exc_new2(rb_eRangeError, ex.what()));
64
+ }
65
+ catch (std::range_error const& ex)
66
+ {
67
+ rb_exc_raise(rb_exc_new2(rb_eRangeError, ex.what()));
68
+ }
69
+ catch (std::regex_error const& ex)
70
+ {
71
+ rb_exc_raise(rb_exc_new2(rb_eRegexpError, ex.what()));
72
+ }
73
+ catch (std::system_error const& ex)
74
+ {
75
+ rb_exc_raise(rb_exc_new2(rb_eSystemCallError, ex.what()));
76
+ }
77
+ catch (std::underflow_error const& ex)
78
+ {
79
+ rb_exc_raise(rb_exc_new2(rb_eRangeError, ex.what()));
80
+ }
81
+ catch (std::exception const& ex)
82
+ {
83
+ rb_exc_raise(rb_exc_new2(rb_eRuntimeError, ex.what()));
84
+ }
85
+ catch (...)
86
+ {
87
+ rb_exc_raise(rb_exc_new2(rb_eRuntimeError, "Unknown C++ exception thrown"));
88
+ }
89
+ throw std::runtime_error("Should never get here - just making compilers happy");
90
+ }
91
+ }
92
+ }
93
+ #endif // Rice__detail__cpp_protect__hpp_
@@ -7,6 +7,6 @@ namespace Rice::detail
7
7
  {
8
8
  // Create a new Ruby object but since we do not yet have a C++ object
9
9
  // just pass a nullptr. It will be set via the Constructor call
10
- return TypedData_Wrap_Struct(klass, Data_Type<T>::rb_type(), nullptr);
10
+ return TypedData_Wrap_Struct(klass, Data_Type<T>::ruby_data_type(), nullptr);
11
11
  }
12
12
  }