rice 4.3.1 → 4.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9c1c38f3ecf4a82df0f710ebcddb90f42152a4329e375ff8ea7afaf1eddade33
4
- data.tar.gz: 3ae4a9a648313b45f2efe37fd370aa6442bd6e042b72384f980ac2ae8ada6ddc
3
+ metadata.gz: 4f1560a877de281b9d1fb0538591d606dc0fe312a6fbbaaf9d15448028836fad
4
+ data.tar.gz: 0af73222a775ef41799404a26c4cd69290330ce41184b512ecfb1a2d05925900
5
5
  SHA512:
6
- metadata.gz: 32208880275388fa976f4a848d483daa2190425e0b7272d09557af7a5ee1b28ef95fa45f3b280b4c2aff35daf9e745b2069bfcf7aa2e7827f81d36f15d1aaead
7
- data.tar.gz: 81351aa2c5d1fca2f51bbdb519375623983c23a5fd10162aa6bcfe3b653110a59edfa5e8d56c8172dd8ef542e9bb223d428ddbd66c6a1787fcc9bfd241c0740b
6
+ metadata.gz: 426d8192d42f45b177a4f8639dc7d329143c2a5874b3ead5ab71bdcf0299d46d0e0d707cb616e57c33f2c2896aba7497baaba3191d02ab846ac2b2b49abe3071
7
+ data.tar.gz: d3cab1776f0817e76ee2d0576c8addf3412bf16d0da5fbcb64232d5aa9887b7f9c3607878e201cc9677e387ec4253a61add0be845e46bfa6751d261b4d596815
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 4.3.2
2
+
3
+ * Improve NativeRegistry to reduce possible hash collisions and weird "bad any cast" errors.
4
+
1
5
  ## 4.3.1
2
6
 
3
7
  * Update links and related references to the new repo and docs location: ruby-rice.github.io.
data/CONTRIBUTORS.md CHANGED
@@ -16,7 +16,7 @@ I'd like to thank the following people for their help in making Rice what it is
16
16
  * [nobu](https://github.com/nobu) for [PR #122](https://github.com/jasonroelofs/rice/pull/122)
17
17
  * [Charlie Savage (cfis)](https://github.com/cfis) for multiple improvements and modernizations: [#130](https://github.com/jasonroelofs/rice/pull/130), [#131](https://github.com/jasonroelofs/rice/pull/131), [#133](https://github.com/jasonroelofs/rice/pull/133), [#134](https://github.com/jasonroelofs/rice/pull/134), [#136](https://github.com/jasonroelofs/rice/pull/136), [#137](https://github.com/jasonroelofs/rice/pull/137), [#140](https://github.com/jasonroelofs/rice/pull/140), [#141](https://github.com/jasonroelofs/rice/pull/141) and many others, including the work to make Rice header-only.
18
18
  * [Atsushi Tatsuma (yoshoku)](https://github.com/yoshoku) for [#135](https://github.com/jasonroelofs/rice/pull/135)
19
- * [Andrew Kane (ankane)](https://github.com/ankane) for helping [test Rice 4](https://github.com/jasonroelofs/rice/issues/149).
19
+ * [Andrew Kane (ankane)](https://github.com/ankane) for helping [test Rice 4](https://github.com/jasonroelofs/rice/issues/149), [#208](https://github.com/ruby-rice/rice/pull/208), [#209](https://github.com/ruby-rice/rice/pull/208).
20
20
  * [Maxim Samsonov (maxirmx)](https://github.com/maxirmx) for [#193](https://github.com/jasonroelofs/rice/issues/193) and [#194](https://github.com/jasonroelofs/rice/pull/194)
21
21
  * [kvtb](https://github.com/kvtb) for [#191](https://github.com/jasonroelofs/rice/issues/191)
22
22
  * [thekendalmiller](https://github.com/thekendalmiller) for [#201](https://github.com/jasonroelofs/rice/pull/201)
@@ -1075,6 +1075,7 @@ namespace Rice::detail
1075
1075
 
1076
1076
  #include <unordered_map>
1077
1077
  #include <any>
1078
+ #include <tuple>
1078
1079
 
1079
1080
 
1080
1081
  namespace Rice::detail
@@ -1094,9 +1095,9 @@ namespace Rice::detail
1094
1095
 
1095
1096
  private:
1096
1097
  size_t key(VALUE klass, ID method_id);
1097
- std::unordered_map<size_t, std::any> natives_ = {};
1098
+ std::unordered_multimap<size_t, std::tuple<VALUE, ID, std::any>> natives_ = {};
1098
1099
  };
1099
- }
1100
+ }
1100
1101
 
1101
1102
  // --------- NativeRegistry.ipp ---------
1102
1103
 
@@ -1114,19 +1115,30 @@ namespace Rice::detail
1114
1115
  // https://stackoverflow.com/a/2634715
1115
1116
  inline size_t NativeRegistry::key(VALUE klass, ID id)
1116
1117
  {
1117
- if (rb_type(klass) == T_ICLASS)
1118
- {
1119
- klass = detail::protect(rb_class_of, klass);
1120
- }
1121
-
1122
1118
  uint32_t prime = 53;
1123
1119
  return (prime + klass) * prime + id;
1124
1120
  }
1125
1121
 
1126
1122
  inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable)
1127
1123
  {
1128
- // Now store data about it
1129
- this->natives_[key(klass, method_id)] = callable;
1124
+ if (rb_type(klass) == T_ICLASS)
1125
+ {
1126
+ klass = detail::protect(rb_class_of, klass);
1127
+ }
1128
+
1129
+ auto range = this->natives_.equal_range(key(klass, method_id));
1130
+ for (auto it = range.first; it != range.second; ++it)
1131
+ {
1132
+ const auto [k, m, d] = it->second;
1133
+
1134
+ if (k == klass && m == method_id)
1135
+ {
1136
+ std::get<2>(it->second) = callable;
1137
+ return;
1138
+ }
1139
+ }
1140
+
1141
+ this->natives_.emplace(std::make_pair(key(klass, method_id), std::make_tuple(klass, method_id, callable)));
1130
1142
  }
1131
1143
 
1132
1144
  template <typename Return_T>
@@ -1145,14 +1157,28 @@ namespace Rice::detail
1145
1157
  template <typename Return_T>
1146
1158
  inline Return_T NativeRegistry::lookup(VALUE klass, ID method_id)
1147
1159
  {
1148
- auto iter = this->natives_.find(key(klass, method_id));
1149
- if (iter == this->natives_.end())
1160
+ if (rb_type(klass) == T_ICLASS)
1161
+ {
1162
+ klass = detail::protect(rb_class_of, klass);
1163
+ }
1164
+
1165
+ auto range = this->natives_.equal_range(key(klass, method_id));
1166
+ for (auto it = range.first; it != range.second; ++it)
1150
1167
  {
1151
- rb_raise(rb_eRuntimeError, "Could not find data for klass and method id");
1168
+ const auto [k, m, d] = it->second;
1169
+
1170
+ if (k == klass && m == method_id)
1171
+ {
1172
+ auto* ptr = std::any_cast<Return_T>(&d);
1173
+ if (!ptr)
1174
+ {
1175
+ rb_raise(rb_eRuntimeError, "Unexpected return type for %s#%s", rb_class2name(klass), rb_id2name(method_id));
1176
+ }
1177
+ return *ptr;
1178
+ }
1152
1179
  }
1153
1180
 
1154
- std::any data = iter->second;
1155
- return std::any_cast<Return_T>(data);
1181
+ rb_raise(rb_eRuntimeError, "Could not find data for klass and method id");
1156
1182
  }
1157
1183
  }
1158
1184
 
@@ -6242,6 +6268,9 @@ namespace Rice
6242
6268
  //! Construct a Symbol from an std::string.
6243
6269
  Symbol(std::string const& s);
6244
6270
 
6271
+ //! Construct a Symbol from an std::string_view.
6272
+ Symbol(std::string_view const& s);
6273
+
6245
6274
  //! Return a string representation of the Symbol.
6246
6275
  char const* c_str() const;
6247
6276
 
@@ -6273,7 +6302,12 @@ namespace Rice
6273
6302
  }
6274
6303
 
6275
6304
  inline Symbol::Symbol(std::string const& s)
6276
- : Object(detail::protect(rb_id2sym, detail::protect(rb_intern2, s.c_str(), s.size())))
6305
+ : Object(detail::protect(rb_id2sym, detail::protect(rb_intern2, s.c_str(), (long)s.length())))
6306
+ {
6307
+ }
6308
+
6309
+ inline Symbol::Symbol(std::string_view const& view)
6310
+ : Object(detail::protect(rb_id2sym, detail::protect(rb_intern2, view.data(), (long)view.length())))
6277
6311
  {
6278
6312
  }
6279
6313
 
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rice
2
- VERSION = "4.3.1"
2
+ VERSION = "4.3.2"
3
3
  end
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <unordered_map>
5
5
  #include <any>
6
+ #include <tuple>
6
7
 
7
8
  #include "ruby.hpp"
8
9
 
@@ -23,9 +24,9 @@ namespace Rice::detail
23
24
 
24
25
  private:
25
26
  size_t key(VALUE klass, ID method_id);
26
- std::unordered_map<size_t, std::any> natives_ = {};
27
+ std::unordered_multimap<size_t, std::tuple<VALUE, ID, std::any>> natives_ = {};
27
28
  };
28
- }
29
+ }
29
30
  #include "NativeRegistry.ipp"
30
31
 
31
- #endif // Rice__detail__NativeRegistry__hpp
32
+ #endif // Rice__detail__NativeRegistry__hpp
@@ -14,19 +14,30 @@ namespace Rice::detail
14
14
  // https://stackoverflow.com/a/2634715
15
15
  inline size_t NativeRegistry::key(VALUE klass, ID id)
16
16
  {
17
- if (rb_type(klass) == T_ICLASS)
18
- {
19
- klass = detail::protect(rb_class_of, klass);
20
- }
21
-
22
17
  uint32_t prime = 53;
23
18
  return (prime + klass) * prime + id;
24
19
  }
25
20
 
26
21
  inline void NativeRegistry::add(VALUE klass, ID method_id, std::any callable)
27
22
  {
28
- // Now store data about it
29
- this->natives_[key(klass, method_id)] = callable;
23
+ if (rb_type(klass) == T_ICLASS)
24
+ {
25
+ klass = detail::protect(rb_class_of, klass);
26
+ }
27
+
28
+ auto range = this->natives_.equal_range(key(klass, method_id));
29
+ for (auto it = range.first; it != range.second; ++it)
30
+ {
31
+ const auto [k, m, d] = it->second;
32
+
33
+ if (k == klass && m == method_id)
34
+ {
35
+ std::get<2>(it->second) = callable;
36
+ return;
37
+ }
38
+ }
39
+
40
+ this->natives_.emplace(std::make_pair(key(klass, method_id), std::make_tuple(klass, method_id, callable)));
30
41
  }
31
42
 
32
43
  template <typename Return_T>
@@ -45,13 +56,27 @@ namespace Rice::detail
45
56
  template <typename Return_T>
46
57
  inline Return_T NativeRegistry::lookup(VALUE klass, ID method_id)
47
58
  {
48
- auto iter = this->natives_.find(key(klass, method_id));
49
- if (iter == this->natives_.end())
59
+ if (rb_type(klass) == T_ICLASS)
50
60
  {
51
- rb_raise(rb_eRuntimeError, "Could not find data for klass and method id");
61
+ klass = detail::protect(rb_class_of, klass);
62
+ }
63
+
64
+ auto range = this->natives_.equal_range(key(klass, method_id));
65
+ for (auto it = range.first; it != range.second; ++it)
66
+ {
67
+ const auto [k, m, d] = it->second;
68
+
69
+ if (k == klass && m == method_id)
70
+ {
71
+ auto* ptr = std::any_cast<Return_T>(&d);
72
+ if (!ptr)
73
+ {
74
+ rb_raise(rb_eRuntimeError, "Unexpected return type for %s#%s", rb_class2name(klass), rb_id2name(method_id));
75
+ }
76
+ return *ptr;
77
+ }
52
78
  }
53
79
 
54
- std::any data = iter->second;
55
- return std::any_cast<Return_T>(data);
80
+ rb_raise(rb_eRuntimeError, "Could not find data for klass and method id");
56
81
  }
57
82
  }
@@ -0,0 +1,50 @@
1
+ #include "unittest.hpp"
2
+ #include "embed_ruby.hpp"
3
+
4
+ #include <rice/rice.hpp>
5
+ #include <rice/stl.hpp>
6
+
7
+ using namespace Rice;
8
+
9
+ TESTSUITE(NativeRegistry);
10
+
11
+ SETUP(NativeRegistry)
12
+ {
13
+ embed_ruby();
14
+ }
15
+
16
+ TESTCASE(collisions)
17
+ {
18
+ std::array<Class, 100> classes;
19
+ int scale = 1000;
20
+
21
+ for (int i = 0; i < std::size(classes); i++)
22
+ {
23
+ Class cls(anonymous_class());
24
+
25
+ for (int j = 0; j < scale; j++)
26
+ {
27
+ cls.define_function("int" + std::to_string(j), []() { return 1; });
28
+ cls.define_function("long" + std::to_string(j), []() { return 1L; });
29
+ cls.define_function("double" + std::to_string(j), []() { return 1.0; });
30
+ cls.define_function("float" + std::to_string(j), []() { return 1.0f; });
31
+ cls.define_function("bool" + std::to_string(j), []() { return true; });
32
+ }
33
+
34
+ classes[i] = cls;
35
+ }
36
+
37
+ for (auto& cls : classes)
38
+ {
39
+ auto obj = cls.call("new");
40
+
41
+ for (int j = 0; j < scale; j++)
42
+ {
43
+ obj.call("int" + std::to_string(j));
44
+ obj.call("long" + std::to_string(j));
45
+ obj.call("double" + std::to_string(j));
46
+ obj.call("float" + std::to_string(j));
47
+ obj.call("bool" + std::to_string(j));
48
+ }
49
+ }
50
+ }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rice
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.3.1
4
+ version: 4.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Brannan
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2024-03-16 00:00:00.000000000 Z
13
+ date: 2024-10-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -188,6 +188,7 @@ files:
188
188
  - test/test_Keep_Alive_No_Wrapper.cpp
189
189
  - test/test_Memory_Management.cpp
190
190
  - test/test_Module.cpp
191
+ - test/test_Native_Registry.cpp
191
192
  - test/test_Object.cpp
192
193
  - test/test_Ownership.cpp
193
194
  - test/test_Self.cpp
@@ -232,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
233
  - !ruby/object:Gem::Version
233
234
  version: '0'
234
235
  requirements: []
235
- rubygems_version: 3.5.4
236
+ rubygems_version: 3.5.22
236
237
  signing_key:
237
238
  specification_version: 4
238
239
  summary: Ruby Interface for C++ Extensions