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/detail/Type.ipp CHANGED
@@ -1,12 +1,3 @@
1
- #include "../traits/rice_traits.hpp"
2
-
3
- #include <iosfwd>
4
- #include <iterator>
5
- #include <numeric>
6
- #include <regex>
7
- #include <sstream>
8
- #include <tuple>
9
-
10
1
  #ifdef __GNUC__
11
2
  #include <cxxabi.h>
12
3
  #include <cstdlib>
@@ -15,6 +6,19 @@
15
6
 
16
7
  namespace Rice::detail
17
8
  {
9
+ template<typename T>
10
+ bool Type<T>::verify()
11
+ {
12
+ if constexpr (std::is_fundamental_v<T>)
13
+ {
14
+ return true;
15
+ }
16
+ else
17
+ {
18
+ return Registries::instance.types.verify<T>();
19
+ }
20
+ }
21
+
18
22
  template<>
19
23
  struct Type<void>
20
24
  {
@@ -89,13 +93,76 @@ namespace Rice::detail
89
93
  return demangle(typeInfo.name());
90
94
  }
91
95
 
92
- inline std::string makeClassName(const std::type_info& typeInfo)
96
+ inline std::string typeName(const std::type_index& typeIndex)
97
+ {
98
+ return demangle(typeIndex.name());
99
+ }
100
+
101
+ // Find text inside of < > taking into account nested groups.
102
+ //
103
+ // Example:
104
+ //
105
+ // std::vector<std::vector<int>, std::allocator<std::vector, std::allocator<int>>>
106
+ inline std::string findGroup(std::string& string, size_t offset)
107
+ {
108
+ int depth = 0;
109
+
110
+ auto begin = string.begin() + offset;
111
+ auto start = begin;
112
+ for (auto iter = begin; iter != string.end(); iter++)
113
+ {
114
+ if (*iter == '<')
115
+ {
116
+ if (depth == 0)
117
+ {
118
+ start = iter;
119
+ }
120
+ depth++;
121
+ }
122
+ else if (*iter == '>')
123
+ {
124
+ depth--;
125
+ if (depth == 0)
126
+ {
127
+ // Add + 1 to include current ">" character
128
+ return string.substr(offset + (start - begin), 1 + (iter - start));
129
+ }
130
+ else if (depth < 0)
131
+ {
132
+ throw std::runtime_error("Unbalanced Group");
133
+ }
134
+ }
135
+ }
136
+ throw std::runtime_error("Unbalanced Group");
137
+ }
138
+
139
+ inline void replaceAll(std::string& string, std::regex regex, std::string replacement)
93
140
  {
94
- std::string base = demangle(typeInfo.name());
141
+ std::smatch match;
142
+ while (std::regex_search(string, match, regex))
143
+ {
144
+ string = std::regex_replace(string, regex, replacement);
145
+ }
146
+ }
147
+
148
+ inline void removeGroup(std::string& string, std::regex regex)
149
+ {
150
+ std::smatch match;
151
+ while (std::regex_search(string, match, regex))
152
+ {
153
+ std::string group = findGroup(string, match.position());
154
+ group = match.str() + group;
155
+ string.erase(match.position(), group.length());
156
+ }
157
+ }
158
+
159
+ inline std::string makeClassName(const std::string& typeInfoName)
160
+ {
161
+ std::string base = typeInfoName;
95
162
 
96
163
  // Remove class keyword
97
164
  auto classRegex = std::regex("class +");
98
- base = std::regex_replace(base, classRegex, "");
165
+ base = std::regex_replace(typeInfoName, classRegex, "");
99
166
 
100
167
  // Remove struct keyword
101
168
  auto structRegex = std::regex("struct +");
@@ -109,31 +176,81 @@ namespace Rice::detail
109
176
  auto stdRegex = std::regex("std::");
110
177
  base = std::regex_replace(base, stdRegex, "");
111
178
 
112
- // Replace > >
113
- auto trailingAngleBracketSpaceRegex = std::regex(" >");
114
- base = std::regex_replace(base, trailingAngleBracketSpaceRegex, ">");
179
+ // Replace basic_string with string
180
+ auto basicStringRegex = std::regex(R"(basic_string)");
181
+ replaceAll(base, basicStringRegex, "string");
182
+
183
+ // Remove allocators
184
+ std::regex allocatorRegex(R"(,\s*allocator)");
185
+ removeGroup(base, allocatorRegex);
115
186
 
116
- // Replace < and >
117
- auto angleBracketRegex = std::regex("<|>");
118
- base = std::regex_replace(base, angleBracketRegex, "__");
187
+ // Remove char_traits
188
+ std::regex charTraitsRegex(R"(,\s*char_traits)");
189
+ removeGroup(base, charTraitsRegex);
119
190
 
120
- // Replace ,
121
- auto commaRegex = std::regex(", *");
122
- base = std::regex_replace(base, commaRegex, "_");
191
+ // Remove less (std::map)
192
+ std::regex lessRegex(R"(,\s*less)");
193
+ removeGroup(base, lessRegex);
123
194
 
124
- // Now create a vector of strings split on whitespace
125
- std::istringstream stream(base);
126
- std::vector<std::string> words{ std::istream_iterator<std::string>{stream},
127
- std::istream_iterator<std::string>{} };
195
+ // Remove hash (std::unordered_map)
196
+ std::regex hashRegex(R"(,\s*hash)");
197
+ removeGroup(base, hashRegex);
128
198
 
129
- std::string result = std::accumulate(words.begin(), words.end(), std::string(),
130
- [](const std::string& memo, const std::string& word) -> std::string
131
- {
132
- std::string capitalized = word;
133
- capitalized[0] = toupper(capitalized[0]);
134
- return memo + capitalized;
135
- });
199
+ // Remove equal_to (std::unordered_map)
200
+ std::regex equalRegex(R"(,\s*equal_to)");
201
+ removeGroup(base, equalRegex);
202
+
203
+ // Remove spaces before pointers
204
+ auto ptrRegex = std::regex(R"(\s+\*)");
205
+ base = std::regex_replace(base, ptrRegex, "*");
206
+
207
+ // Remove __ptr64
208
+ std::regex ptr64Regex(R"(\s*__ptr64\s*)");
209
+ base = std::regex_replace(base, ptr64Regex, "");
210
+
211
+ // Replace " >" with ">"
212
+ auto trailingAngleBracketSpaceRegex = std::regex(R"(\s+>)");
213
+ replaceAll(base, trailingAngleBracketSpaceRegex, ">");
214
+
215
+ // One space after a comma (MSVC has no spaces, GCC one space)
216
+ auto commaSpaceRegex = std::regex(R"(,(\S))");
217
+ replaceAll(base, commaSpaceRegex, ", $1");
218
+
219
+ // Capitalize first letter
220
+ base[0] = std::toupper(base[0]);
221
+
222
+ // Replace :: with unicode U+u02F8 (Modified Letter raised colon)
223
+ auto colonRegex = std::regex(R"(:)");
224
+ replaceAll(base, colonRegex, "\uA789");
225
+
226
+ // Replace _ and capitalize the next letter
227
+ std::regex namespaceRegex(R"(_(\w))");
228
+ std::smatch namespaceMatch;
229
+ while (std::regex_search(base, namespaceMatch, namespaceRegex))
230
+ {
231
+ std::string replacement = namespaceMatch[1];
232
+ std::transform(replacement.begin(), replacement.end(), replacement.begin(), ::toupper);
233
+ base.replace(namespaceMatch.position(), namespaceMatch.length(), replacement);
234
+ }
235
+
236
+ // Replace spaces with unicode U+u00A0 (Non breaking Space)
237
+ auto spaceRegex = std::regex(R"(\s+)");
238
+ replaceAll(base, spaceRegex, "\u00A0");
239
+
240
+ // Replace < with unicode U+227A (Precedes)
241
+ auto lessThanRegex = std::regex("<");
242
+ //replaceAll(base, lessThanRegex, u8"≺");
243
+ replaceAll(base, lessThanRegex, "\u227A");
244
+
245
+ // Replace > with unicode U+227B (Succeeds)
246
+ auto greaterThanRegex = std::regex(">");
247
+ //replaceAll(base, greaterThanRegex, u8"≻");
248
+ replaceAll(base, greaterThanRegex, "\u227B");
249
+
250
+ // Replace , with Unicode Character (U+066C) - Arabic Thousands Separator
251
+ auto commaRegex = std::regex(R"(,\s*)");
252
+ replaceAll(base, commaRegex, "\u201A");
136
253
 
137
- return result;
254
+ return base;
138
255
  }
139
256
  }
@@ -2,12 +2,10 @@
2
2
  #define Rice__TypeRegistry__hpp_
3
3
 
4
4
  #include <optional>
5
- #include <string>
6
- #include <typeindex>
7
- #include <typeinfo>
8
5
  #include <unordered_map>
6
+ #include <set>
7
+ #include <regex>
9
8
 
10
- #include "ruby.hpp"
11
9
 
12
10
  /* The type registry keeps track of all C++ types wrapped by Rice. When a native function returns
13
11
  an instance of a class/struct we look up its type to verity that it has been registered.
@@ -31,17 +29,27 @@ namespace Rice::detail
31
29
  bool isDefined();
32
30
 
33
31
  template <typename T>
34
- bool verifyDefined();
32
+ std::pair<VALUE, rb_data_type_t*> getType();
33
+
34
+ template <typename T>
35
+ bool verify();
35
36
 
36
37
  template <typename T>
37
38
  std::pair<VALUE, rb_data_type_t*> figureType(const T& object);
38
39
 
40
+ // Validate types and throw if any types are unverified
41
+ void validateTypes();
42
+
43
+ // Clear unverified types. This is mostly for unit tests
44
+ void clearUnverifiedTypes();
45
+
39
46
  private:
40
47
  std::optional<std::pair<VALUE, rb_data_type_t*>> lookup(const std::type_info& typeInfo);
48
+ void raiseUnverifiedType(const std::string& typeName);
49
+
41
50
  std::unordered_map<std::type_index, std::pair<VALUE, rb_data_type_t*>> registry_{};
51
+ std::set<std::type_index> unverified_{};
42
52
  };
43
53
  }
44
54
 
45
- #include "TypeRegistry.ipp"
46
-
47
55
  #endif // Rice__TypeRegistry__hpp_
@@ -1,8 +1,8 @@
1
+ #include <iostream>
1
2
  #include <stdexcept>
3
+ #include <sstream>
4
+ #include <typeindex>
2
5
 
3
- #include "ruby.hpp"
4
- #include "../traits/rice_traits.hpp"
5
- #include "Type.hpp"
6
6
 
7
7
  namespace Rice::detail
8
8
  {
@@ -13,6 +13,22 @@ namespace Rice::detail
13
13
  registry_[key] = std::pair(klass, rbType);
14
14
  }
15
15
 
16
+ /* Special case void. Rice defines classes using the class name not a pointer to the
17
+ class. Thus define_class<void> is more consistent with Rice then
18
+ define_class<void*>. However, the types of void and void* are different so we need
19
+ this special case.
20
+
21
+ It is possible to support define_class<void*>, but it requires changing the static
22
+ assertions on Data_Type and Data_Object and thus seems less desirable (and less
23
+ consistent as mentioned above).*/
24
+ template <>
25
+ inline void TypeRegistry::add<void>(VALUE klass, rb_data_type_t* rbType)
26
+ {
27
+ // The special case, use void*
28
+ std::type_index key(typeid(void*));
29
+ registry_[key] = std::pair(klass, rbType);
30
+ }
31
+
16
32
  template <typename T>
17
33
  inline void TypeRegistry::remove()
18
34
  {
@@ -29,14 +45,45 @@ namespace Rice::detail
29
45
  }
30
46
 
31
47
  template <typename T>
32
- inline bool TypeRegistry::verifyDefined()
48
+ std::pair<VALUE, rb_data_type_t*> TypeRegistry::getType()
33
49
  {
34
- if (!isDefined<T>())
50
+ std::type_index key(typeid(T));
51
+ auto iter = registry_.find(key);
52
+ if (iter != registry_.end())
35
53
  {
36
- std::string message = "Type is not defined with Rice: " + detail::typeName(typeid(T));
37
- throw std::invalid_argument(message);
54
+ return iter->second;
55
+ }
56
+ else
57
+ {
58
+ this->raiseUnverifiedType(typeid(T).name());
59
+ // Make compiler happy
60
+ return std::make_pair(Qnil, nullptr);
61
+ }
62
+ }
63
+
64
+ // Special case void. See comment for add above.
65
+ template <>
66
+ inline bool TypeRegistry::isDefined<void>()
67
+ {
68
+ std::type_index key(typeid(void*));
69
+ auto iter = registry_.find(key);
70
+ return iter != registry_.end();
71
+ }
72
+
73
+ template <typename T>
74
+ inline bool TypeRegistry::verify()
75
+ {
76
+ if (isDefined<T>())
77
+ {
78
+ return true;
79
+ }
80
+ else
81
+ {
82
+ const std::type_info& typeInfo = typeid(T);
83
+ std::type_index key(typeInfo);
84
+ this->unverified_.insert(key);
85
+ return false;
38
86
  }
39
- return true;
40
87
  }
41
88
 
42
89
  inline std::optional<std::pair<VALUE, rb_data_type_t*>> TypeRegistry::lookup(const std::type_info& typeInfo)
@@ -68,14 +115,60 @@ namespace Rice::detail
68
115
  // If not, then we are willing to accept an ancestor class specified by T. This is needed
69
116
  // to support Directors. Classes inherited from Directors are never actually registered
70
117
  // with Rice - and what we really want it to return the C++ class they inherit from.
71
- result = lookup(typeid(T));
118
+ const std::type_info& typeInfo = typeid(T);
119
+ result = lookup(typeInfo);
72
120
  if (result)
73
121
  {
74
122
  return result.value();
75
123
  }
76
124
 
77
- // Give up!
78
- std::string message = "Type " + typeName(typeid(object)) + " is not registered";
79
- throw std::runtime_error(message.c_str());
125
+ raiseUnverifiedType(detail::typeName(typeInfo));
126
+ // Make the compiler happy
127
+ return std::pair<VALUE, rb_data_type_t*>(Qnil, nullptr);
128
+ }
129
+
130
+ inline void TypeRegistry::validateTypes()
131
+ {
132
+ // Loop over the unverified types and delete each on that is found in the registry
133
+ // the registry and raise an exception for the first one that is not
134
+ for (auto iter = this->unverified_.begin(); iter != this->unverified_.end(); )
135
+ {
136
+ const std::type_index& typeIndex = *iter;
137
+ bool isDefined = this->registry_.find(typeIndex) != this->registry_.end();
138
+ if (isDefined)
139
+ {
140
+ iter = this->unverified_.erase(iter);
141
+ }
142
+ else
143
+ {
144
+ iter++;
145
+ }
146
+ }
147
+
148
+ if (this->unverified_.empty())
149
+ {
150
+ return;
151
+ }
152
+
153
+ std::stringstream stream;
154
+ stream << "The following types are not registered with Rice:" << "\n";
155
+
156
+ for (const std::type_index& typeIndex : this->unverified_)
157
+ {
158
+ stream << " " << typeName(typeIndex) << "\n";
159
+ }
160
+
161
+ throw std::invalid_argument(stream.str());
162
+ }
163
+
164
+ inline void TypeRegistry::clearUnverifiedTypes()
165
+ {
166
+ this->unverified_.clear();
167
+ }
168
+
169
+ inline void TypeRegistry::raiseUnverifiedType(const std::string& typeName)
170
+ {
171
+ std::string message = "Type is not registered with Rice: " + typeName;
172
+ throw std::invalid_argument(message);
80
173
  }
81
174
  }
@@ -1,8 +1,6 @@
1
1
  #ifndef Rice__detail__Wrapper__hpp_
2
2
  #define Rice__detail__Wrapper__hpp_
3
3
 
4
- #include "ruby.hpp"
5
-
6
4
  namespace Rice
7
5
  {
8
6
  namespace detail
@@ -11,11 +9,16 @@ namespace detail
11
9
  class Wrapper
12
10
  {
13
11
  public:
12
+ Wrapper(bool isOwner = false);
14
13
  virtual ~Wrapper() = default;
15
14
  virtual void* get() = 0;
16
15
 
17
16
  void ruby_mark();
18
17
  void addKeepAlive(VALUE value);
18
+ void setOwner(bool value);
19
+
20
+ protected:
21
+ bool isOwner_ = false;
19
22
 
20
23
  private:
21
24
  // We use a vector for speed and memory locality versus a set which does
@@ -31,7 +34,7 @@ template <typename T, typename Wrapper_T = void>
31
34
  VALUE wrap(VALUE klass, rb_data_type_t* rb_type, T* data, bool isOwner);
32
35
 
33
36
  template <typename T>
34
- T* unwrap(VALUE value, rb_data_type_t* rb_type);
37
+ T* unwrap(VALUE value, rb_data_type_t* rb_type, bool takeOwnership);
35
38
 
36
39
  Wrapper* getWrapper(VALUE value, rb_data_type_t* rb_type);
37
40
 
@@ -43,7 +46,5 @@ Wrapper* getWrapper(VALUE value);
43
46
  } // namespace detail
44
47
  } // namespace Rice
45
48
 
46
- #include "Wrapper.ipp"
47
-
48
49
  #endif // Rice__detail__Wrapper__hpp_
49
50
 
@@ -1,8 +1,11 @@
1
1
  #include <memory>
2
- #include "InstanceRegistry.hpp"
3
2
 
4
3
  namespace Rice::detail
5
4
  {
5
+ inline Wrapper::Wrapper(bool isOwner): isOwner_(isOwner)
6
+ {
7
+ }
8
+
6
9
  inline void Wrapper::ruby_mark()
7
10
  {
8
11
  for (VALUE value : this->keepAlive_)
@@ -16,6 +19,11 @@ namespace Rice::detail
16
19
  this->keepAlive_.push_back(value);
17
20
  }
18
21
 
22
+ inline void Wrapper::setOwner(bool value)
23
+ {
24
+ this->isOwner_ = value;
25
+ }
26
+
19
27
  template <typename T>
20
28
  class WrapperValue : public Wrapper
21
29
  {
@@ -64,7 +72,7 @@ namespace Rice::detail
64
72
  class WrapperPointer : public Wrapper
65
73
  {
66
74
  public:
67
- WrapperPointer(T* data, bool isOwner) : data_(data), isOwner_(isOwner)
75
+ WrapperPointer(T* data, bool isOwner) : Wrapper(isOwner), data_(data)
68
76
  {
69
77
  }
70
78
 
@@ -72,9 +80,12 @@ namespace Rice::detail
72
80
  {
73
81
  Registries::instance.instances.remove(this->get());
74
82
 
75
- if (this->isOwner_)
83
+ if constexpr (std::is_destructible_v<T>)
76
84
  {
77
- delete this->data_;
85
+ if (this->isOwner_)
86
+ {
87
+ delete this->data_;
88
+ }
78
89
  }
79
90
  }
80
91
 
@@ -85,7 +96,6 @@ namespace Rice::detail
85
96
 
86
97
  private:
87
98
  T* data_ = nullptr;
88
- bool isOwner_ = false;
89
99
  };
90
100
 
91
101
  // ---- Helper Functions -------
@@ -111,12 +121,20 @@ namespace Rice::detail
111
121
  wrapper = new Wrapper_T(data);
112
122
  result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
113
123
  }
114
- // Is this a pointer and it cannot copied? This is for std::unique_ptr
115
- // If ruby is the owner than copy the object
124
+ // If ruby is the owner than copy the object if possible
116
125
  else if (isOwner)
117
126
  {
118
- wrapper = new WrapperValue<T>(data);
119
- result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
127
+ if constexpr (std::is_copy_constructible_v<T> || std::is_move_constructible_v<T>)
128
+ {
129
+ wrapper = new WrapperValue<T>(data);
130
+ result = TypedData_Wrap_Struct(klass, rb_type, wrapper);
131
+ }
132
+ else
133
+ {
134
+ std::string message = "Ruby was directed to take ownership of a C++ object but it does not have an accessible copy or move constructor. Type: " +
135
+ typeName(typeid(T));
136
+ throw std::runtime_error(message);
137
+ }
120
138
  }
121
139
  // Ruby is not the owner so just wrap the reference
122
140
  else
@@ -156,9 +174,11 @@ namespace Rice::detail
156
174
  };
157
175
 
158
176
  template <typename T>
159
- inline T* unwrap(VALUE value, rb_data_type_t* rb_type)
177
+ inline T* unwrap(VALUE value, rb_data_type_t* rb_type, bool takeOwnership)
160
178
  {
161
179
  Wrapper* wrapper = getWrapper(value, rb_type);
180
+ if (takeOwnership)
181
+ wrapper->setOwner(false);
162
182
 
163
183
  if (wrapper == nullptr)
164
184
  {
@@ -179,6 +199,21 @@ namespace Rice::detail
179
199
  return wrapper;
180
200
  }
181
201
 
202
+ inline Wrapper* getWrapper(VALUE value)
203
+ {
204
+ // Turn off spurious warning on g++ 12
205
+ #if defined(__GNUC__) || defined(__clang__)
206
+ #pragma GCC diagnostic push
207
+ #pragma GCC diagnostic ignored "-Warray-bounds"
208
+ #endif
209
+
210
+ return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
211
+
212
+ #if defined(__GNUC__) || defined(__clang__)
213
+ #pragma GCC diagnostic pop
214
+ #endif
215
+ }
216
+
182
217
  template <typename T>
183
218
  inline void replace(VALUE value, rb_data_type_t* rb_type, T* data, bool isOwner)
184
219
  {
@@ -195,17 +230,4 @@ namespace Rice::detail
195
230
 
196
231
  Registries::instance.instances.add(data, value);
197
232
  }
198
-
199
- inline Wrapper* getWrapper(VALUE value)
200
- {
201
- // Turn off spurious warning on g++ 12
202
- #ifdef __GNUC__
203
- #pragma GCC diagnostic push
204
- #pragma GCC diagnostic ignored "-Warray-bounds"
205
- #endif
206
- return RTYPEDDATA_P(value) ? static_cast<Wrapper*>(RTYPEDDATA_DATA(value)) : nullptr;
207
- #ifdef __GNUC__
208
- #pragma GCC diagnostic pop
209
- #endif
210
- }
211
233
  } // namespace
@@ -14,8 +14,6 @@
14
14
  #error "no filesystem include found :'("
15
15
  #endif
16
16
 
17
- #include "Jump_Tag.hpp"
18
- #include "../Exception_defn.hpp"
19
17
 
20
18
  namespace Rice::detail
21
19
  {
@@ -30,13 +28,14 @@ namespace Rice::detail
30
28
  {
31
29
  try
32
30
  {
33
- detail::Registries::instance.handlers.handler()->handle();
31
+ std::function<void()> handler = detail::Registries::instance.handlers.handler();
32
+ handler();
34
33
  }
35
34
  catch (::Rice::Exception const& ex)
36
35
  {
37
36
  rb_exc_raise(ex.value());
38
37
  }
39
- catch (::Rice::Jump_Tag const& ex)
38
+ catch (::Rice::JumpException const& ex)
40
39
  {
41
40
  rb_jump_tag(ex.tag);
42
41
  }
@@ -61,11 +60,11 @@ namespace Rice::detail
61
60
  }
62
61
  catch (std::length_error const& ex)
63
62
  {
64
- rb_exc_raise(rb_exc_new2(rb_eRuntimeError, ex.what()));
63
+ rb_exc_raise(rb_exc_new2(rb_eIndexError, ex.what()));
65
64
  }
66
65
  catch (std::out_of_range const& ex)
67
66
  {
68
- rb_exc_raise(rb_exc_new2(rb_eRangeError, ex.what()));
67
+ rb_exc_raise(rb_exc_new2(rb_eIndexError, ex.what()));
69
68
  }
70
69
  catch (std::overflow_error const& ex)
71
70
  {
@@ -1,5 +1,3 @@
1
- #include "../Data_Object.hpp"
2
-
3
1
  namespace Rice::detail
4
2
  {
5
3
  template<typename T>
@@ -1,8 +1,42 @@
1
1
  #ifndef Rice__detail__from_ruby__hpp_
2
2
  #define Rice__detail__from_ruby__hpp_
3
3
 
4
- #include "from_ruby_defn.hpp"
5
- #include "from_ruby.ipp"
4
+ namespace Rice::detail
5
+ {
6
+ //! Convert a Ruby object to C++.
7
+ /*! If the Ruby object can be converted to an immediate value, returns a
8
+ * copy of the Ruby object. If the Ruby object is holding a C++
9
+ * object and the type specified is a pointer to that type, returns a
10
+ * pointer to that object.
11
+ *
12
+ * Conversions from ruby to a pointer type are automatically generated
13
+ * when a type is bound using Data_Type. If no conversion exists an
14
+ * exception is thrown.
15
+ *
16
+ * \param T the C++ type to which to convert.
17
+ * \param x the Ruby object to convert.
18
+ * \return a C++ representation of the Ruby object.
19
+ *
20
+ * Example:
21
+ * \code
22
+ * Object x = INT2NUM(42);
23
+ * std::cout << From_Ruby<int>::convert(x);
24
+ *
25
+ * Data_Object<Foo> foo(new Foo);
26
+ * std::cout << *From_Ruby<Foo *>(foo) << std::endl;
27
+ * \endcode
28
+ */
6
29
 
7
- #endif // Rice__detail__from_ruby__hpp_
30
+ template <typename T>
31
+ class From_Ruby;
8
32
 
33
+ enum class Convertible: uint8_t
34
+ {
35
+ None = 0b000,
36
+ Narrowable = 0b001,
37
+ Cast = 0b011,
38
+ Exact = 0b111,
39
+ };
40
+ }
41
+
42
+ #endif // Rice__detail__From_Ruby2__hpp_