rice 4.5.0 → 4.6.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -0
- data/CMakeLists.txt +31 -0
- data/CMakePresets.json +75 -0
- data/COPYING +3 -2
- data/FindRuby.cmake +437 -0
- data/Rakefile +5 -4
- data/include/rice/rice.hpp +5436 -3201
- data/include/rice/stl.hpp +2355 -1269
- data/lib/make_rice_headers.rb +79 -0
- data/lib/mkmf-rice.rb +4 -0
- data/lib/rice/version.rb +3 -0
- data/lib/rice.rb +1 -0
- data/lib/rubygems/builder.rb +11 -0
- data/lib/rubygems/cmake_builder.rb +113 -0
- data/lib/rubygems_plugin.rb +9 -0
- data/rice/Arg.hpp +7 -1
- data/rice/Arg.ipp +11 -2
- data/rice/Buffer.hpp +123 -0
- data/rice/Buffer.ipp +599 -0
- data/rice/Constructor.ipp +3 -3
- data/rice/Data_Object.hpp +2 -3
- data/rice/Data_Object.ipp +188 -188
- data/rice/Data_Type.hpp +4 -5
- data/rice/Data_Type.ipp +42 -26
- data/rice/Enum.hpp +0 -1
- data/rice/Enum.ipp +26 -23
- data/rice/Init.hpp +8 -0
- data/rice/Init.ipp +8 -0
- data/rice/MemoryView.ipp +1 -41
- data/rice/Return.hpp +1 -1
- data/rice/Return.ipp +6 -0
- data/rice/cpp_api/Array.hpp +209 -0
- data/rice/cpp_api/Array.ipp +304 -0
- data/rice/cpp_api/Builtin_Object.hpp +31 -0
- data/rice/cpp_api/Builtin_Object.ipp +37 -0
- data/rice/cpp_api/Class.hpp +70 -0
- data/rice/cpp_api/Class.ipp +97 -0
- data/rice/cpp_api/Encoding.hpp +32 -0
- data/rice/cpp_api/Encoding.ipp +59 -0
- data/rice/cpp_api/Hash.hpp +194 -0
- data/rice/cpp_api/Hash.ipp +257 -0
- data/rice/cpp_api/Identifier.hpp +46 -0
- data/rice/cpp_api/Identifier.ipp +31 -0
- data/rice/cpp_api/Module.hpp +72 -0
- data/rice/cpp_api/Module.ipp +101 -0
- data/rice/cpp_api/Object.hpp +272 -0
- data/rice/cpp_api/Object.ipp +235 -0
- data/rice/cpp_api/String.hpp +74 -0
- data/rice/cpp_api/String.ipp +120 -0
- data/rice/cpp_api/Struct.hpp +113 -0
- data/rice/cpp_api/Struct.ipp +92 -0
- data/rice/cpp_api/Symbol.hpp +46 -0
- data/rice/cpp_api/Symbol.ipp +93 -0
- data/rice/cpp_api/shared_methods.hpp +134 -0
- data/rice/detail/MethodInfo.hpp +1 -9
- data/rice/detail/MethodInfo.ipp +5 -72
- data/rice/detail/Native.hpp +3 -2
- data/rice/detail/Native.ipp +32 -4
- data/rice/detail/NativeAttributeGet.hpp +3 -2
- data/rice/detail/NativeAttributeGet.ipp +8 -2
- data/rice/detail/NativeAttributeSet.hpp +3 -2
- data/rice/detail/NativeAttributeSet.ipp +8 -2
- data/rice/detail/NativeCallbackFFI.ipp +1 -1
- data/rice/detail/NativeFunction.hpp +17 -6
- data/rice/detail/NativeFunction.ipp +168 -64
- data/rice/detail/NativeIterator.hpp +3 -2
- data/rice/detail/NativeIterator.ipp +8 -2
- data/rice/detail/RubyType.hpp +2 -5
- data/rice/detail/RubyType.ipp +50 -5
- data/rice/detail/Type.hpp +3 -1
- data/rice/detail/Type.ipp +61 -31
- data/rice/detail/Wrapper.hpp +68 -33
- data/rice/detail/Wrapper.ipp +103 -113
- data/rice/detail/from_ruby.hpp +5 -4
- data/rice/detail/from_ruby.ipp +737 -365
- data/rice/detail/to_ruby.ipp +1092 -186
- data/rice/global_function.ipp +1 -1
- data/rice/libc/file.hpp +11 -0
- data/rice/libc/file.ipp +32 -0
- data/rice/rice.hpp +23 -16
- data/rice/stl/complex.hpp +6 -0
- data/rice/stl/complex.ipp +93 -0
- data/rice/stl/exception.hpp +11 -0
- data/rice/stl/exception.ipp +29 -0
- data/rice/stl/exception_ptr.hpp +6 -0
- data/rice/stl/exception_ptr.ipp +27 -0
- data/rice/stl/map.hpp +12 -0
- data/rice/stl/map.ipp +469 -0
- data/rice/stl/monostate.hpp +6 -0
- data/rice/stl/monostate.ipp +80 -0
- data/rice/stl/multimap.hpp +14 -0
- data/rice/stl/multimap.ipp +448 -0
- data/rice/stl/optional.hpp +6 -0
- data/rice/stl/optional.ipp +118 -0
- data/rice/stl/pair.hpp +13 -0
- data/rice/stl/pair.ipp +155 -0
- data/rice/stl/reference_wrapper.hpp +6 -0
- data/rice/stl/reference_wrapper.ipp +41 -0
- data/rice/stl/set.hpp +12 -0
- data/rice/stl/set.ipp +495 -0
- data/rice/stl/shared_ptr.hpp +28 -0
- data/rice/stl/shared_ptr.ipp +224 -0
- data/rice/stl/string.hpp +6 -0
- data/rice/stl/string.ipp +158 -0
- data/rice/stl/string_view.hpp +6 -0
- data/rice/stl/string_view.ipp +65 -0
- data/rice/stl/tuple.hpp +6 -0
- data/rice/stl/tuple.ipp +128 -0
- data/rice/stl/type_index.hpp +6 -0
- data/rice/stl/type_index.ipp +30 -0
- data/rice/stl/type_info.hpp +6 -0
- data/rice/stl/type_info.ipp +29 -0
- data/rice/stl/unique_ptr.hpp +22 -0
- data/rice/stl/unique_ptr.ipp +139 -0
- data/rice/stl/unordered_map.hpp +12 -0
- data/rice/stl/unordered_map.ipp +469 -0
- data/rice/stl/variant.hpp +6 -0
- data/rice/stl/variant.ipp +242 -0
- data/rice/stl/vector.hpp +12 -0
- data/rice/stl/vector.ipp +590 -0
- data/rice/stl.hpp +7 -3
- data/rice/traits/attribute_traits.hpp +26 -0
- data/rice/traits/function_traits.hpp +95 -0
- data/rice/traits/method_traits.hpp +47 -0
- data/rice/traits/rice_traits.hpp +160 -0
- data/rice.gemspec +85 -0
- data/test/embed_ruby.cpp +3 -0
- data/test/ruby/test_multiple_extensions_same_class.rb +14 -14
- data/test/test_Array.cpp +6 -3
- data/test/test_Attribute.cpp +34 -1
- data/test/test_Buffer.cpp +285 -0
- data/test/test_Callback.cpp +2 -3
- data/test/test_Data_Object.cpp +88 -34
- data/test/test_Data_Type.cpp +106 -65
- data/test/test_Director.cpp +7 -3
- data/test/test_Enum.cpp +5 -2
- data/test/test_File.cpp +1 -1
- data/test/test_From_Ruby.cpp +181 -114
- data/test/test_Iterator.cpp +1 -1
- data/test/{test_JumpException.cpp → test_Jump_Exception.cpp} +1 -0
- data/test/test_Keep_Alive.cpp +7 -18
- data/test/test_Keep_Alive_No_Wrapper.cpp +0 -1
- data/test/test_Module.cpp +13 -6
- data/test/test_Native_Registry.cpp +0 -1
- data/test/test_Overloads.cpp +180 -5
- data/test/test_Ownership.cpp +100 -57
- data/test/test_Proc.cpp +0 -1
- data/test/test_Self.cpp +4 -4
- data/test/test_Stl_Map.cpp +37 -39
- data/test/test_Stl_Multimap.cpp +693 -0
- data/test/test_Stl_Pair.cpp +8 -8
- data/test/test_Stl_Reference_Wrapper.cpp +4 -2
- data/test/test_Stl_Set.cpp +790 -0
- data/test/{test_Stl_SmartPointer.cpp → test_Stl_SharedPtr.cpp} +97 -127
- data/test/test_Stl_Tuple.cpp +116 -0
- data/test/test_Stl_Type.cpp +1 -1
- data/test/test_Stl_UniquePtr.cpp +202 -0
- data/test/test_Stl_Unordered_Map.cpp +28 -34
- data/test/test_Stl_Variant.cpp +217 -89
- data/test/test_Stl_Vector.cpp +209 -83
- data/test/test_To_Ruby.cpp +373 -1
- data/test/test_Type.cpp +85 -14
- data/test/test_global_functions.cpp +17 -4
- metadata +94 -10
- data/rice/detail/TupleIterator.hpp +0 -14
@@ -0,0 +1,22 @@
|
|
1
|
+
#ifndef Rice__stl__unique_ptr__hpp_
|
2
|
+
#define Rice__stl__unique_ptr__hpp_
|
3
|
+
|
4
|
+
namespace Rice::detail
|
5
|
+
{
|
6
|
+
template<typename T>
|
7
|
+
class Wrapper<std::unique_ptr<T>> : public WrapperBase
|
8
|
+
{
|
9
|
+
public:
|
10
|
+
Wrapper(std::unique_ptr<T>&& data);
|
11
|
+
~Wrapper();
|
12
|
+
void* get() override;
|
13
|
+
std::unique_ptr<T>& data();
|
14
|
+
|
15
|
+
private:
|
16
|
+
std::unique_ptr<T> data_;
|
17
|
+
};
|
18
|
+
}
|
19
|
+
|
20
|
+
#include "unique_ptr.ipp"
|
21
|
+
|
22
|
+
#endif // Rice__stl__unique_ptr__hpp_
|
@@ -0,0 +1,139 @@
|
|
1
|
+
#include <memory>
|
2
|
+
|
3
|
+
namespace Rice::detail
|
4
|
+
{
|
5
|
+
template<typename T>
|
6
|
+
inline Wrapper<std::unique_ptr<T>>::Wrapper(std::unique_ptr<T>&& data)
|
7
|
+
: data_(std::move(data))
|
8
|
+
{
|
9
|
+
}
|
10
|
+
|
11
|
+
template<typename T>
|
12
|
+
inline Wrapper<std::unique_ptr<T>>::~Wrapper()
|
13
|
+
{
|
14
|
+
Registries::instance.instances.remove(this->get());
|
15
|
+
}
|
16
|
+
|
17
|
+
template<typename T>
|
18
|
+
inline void* Wrapper<std::unique_ptr<T>>::get()
|
19
|
+
{
|
20
|
+
return (void*)this->data_.get();
|
21
|
+
}
|
22
|
+
|
23
|
+
template<typename T>
|
24
|
+
inline std::unique_ptr<T>& Wrapper<std::unique_ptr<T>>::data()
|
25
|
+
{
|
26
|
+
return data_;
|
27
|
+
}
|
28
|
+
|
29
|
+
template <typename T>
|
30
|
+
class To_Ruby<std::unique_ptr<T>>
|
31
|
+
{
|
32
|
+
public:
|
33
|
+
VALUE convert(std::unique_ptr<T>& data)
|
34
|
+
{
|
35
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
36
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
37
|
+
}
|
38
|
+
|
39
|
+
VALUE convert(std::unique_ptr<T>&& data)
|
40
|
+
{
|
41
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
42
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, data, true);
|
43
|
+
}
|
44
|
+
};
|
45
|
+
|
46
|
+
template <typename T>
|
47
|
+
class To_Ruby<std::unique_ptr<T>&>
|
48
|
+
{
|
49
|
+
public:
|
50
|
+
VALUE convert(std::unique_ptr<T>& data)
|
51
|
+
{
|
52
|
+
std::pair<VALUE, rb_data_type_t*> rubyTypeInfo = detail::Registries::instance.types.figureType<T>(*data);
|
53
|
+
return detail::wrap<std::unique_ptr<T>>(rubyTypeInfo.first, rubyTypeInfo.second, std::move(data), true);
|
54
|
+
}
|
55
|
+
};
|
56
|
+
|
57
|
+
template <typename T>
|
58
|
+
class From_Ruby<std::unique_ptr<T>>
|
59
|
+
{
|
60
|
+
public:
|
61
|
+
Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
|
62
|
+
{
|
63
|
+
WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
64
|
+
return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
|
65
|
+
}
|
66
|
+
|
67
|
+
Convertible is_convertible(VALUE value)
|
68
|
+
{
|
69
|
+
if (!is_same_smart_ptr(value))
|
70
|
+
return Convertible::None;
|
71
|
+
|
72
|
+
switch (rb_type(value))
|
73
|
+
{
|
74
|
+
case RUBY_T_DATA:
|
75
|
+
return Convertible::Exact;
|
76
|
+
break;
|
77
|
+
default:
|
78
|
+
return Convertible::None;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
std::unique_ptr<T> convert(VALUE value)
|
83
|
+
{
|
84
|
+
Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
|
85
|
+
if (!wrapper)
|
86
|
+
{
|
87
|
+
std::string message = "Invalid smart pointer wrapper";
|
88
|
+
throw std::runtime_error(message.c_str());
|
89
|
+
}
|
90
|
+
return std::move(wrapper->data());
|
91
|
+
}
|
92
|
+
};
|
93
|
+
|
94
|
+
template <typename T>
|
95
|
+
class From_Ruby<std::unique_ptr<T>&>
|
96
|
+
{
|
97
|
+
public:
|
98
|
+
Wrapper<std::unique_ptr<T>>* is_same_smart_ptr(VALUE value)
|
99
|
+
{
|
100
|
+
WrapperBase* wrapper = detail::getWrapper(value, Data_Type<T>::ruby_data_type());
|
101
|
+
return dynamic_cast<Wrapper<std::unique_ptr<T>>*>(wrapper);
|
102
|
+
}
|
103
|
+
|
104
|
+
Convertible is_convertible(VALUE value)
|
105
|
+
{
|
106
|
+
if (!is_same_smart_ptr(value))
|
107
|
+
return Convertible::None;
|
108
|
+
|
109
|
+
switch (rb_type(value))
|
110
|
+
{
|
111
|
+
case RUBY_T_DATA:
|
112
|
+
return Convertible::Exact;
|
113
|
+
break;
|
114
|
+
default:
|
115
|
+
return Convertible::None;
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
std::unique_ptr<T>& convert(VALUE value)
|
120
|
+
{
|
121
|
+
Wrapper<std::unique_ptr<T>>* wrapper = is_same_smart_ptr(value);
|
122
|
+
if (!wrapper)
|
123
|
+
{
|
124
|
+
std::string message = "Invalid smart pointer wrapper";
|
125
|
+
throw std::runtime_error(message.c_str());
|
126
|
+
}
|
127
|
+
return wrapper->data();
|
128
|
+
}
|
129
|
+
};
|
130
|
+
|
131
|
+
template<typename T>
|
132
|
+
struct Type<std::unique_ptr<T>>
|
133
|
+
{
|
134
|
+
static bool verify()
|
135
|
+
{
|
136
|
+
return Type<T>::verify();
|
137
|
+
}
|
138
|
+
};
|
139
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#ifndef Rice__stl__unordered_map__hpp_
|
2
|
+
#define Rice__stl__unordered_map__hpp_
|
3
|
+
|
4
|
+
namespace Rice
|
5
|
+
{
|
6
|
+
template<typename Key, typename T>
|
7
|
+
Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string name = "");
|
8
|
+
}
|
9
|
+
|
10
|
+
#include "unordered_map.ipp"
|
11
|
+
|
12
|
+
#endif // Rice__stl__unordered_map__hpp_
|
@@ -0,0 +1,469 @@
|
|
1
|
+
#include <unordered_map>
|
2
|
+
|
3
|
+
namespace Rice
|
4
|
+
{
|
5
|
+
namespace stl
|
6
|
+
{
|
7
|
+
template<typename T>
|
8
|
+
class UnorderedMapHelper
|
9
|
+
{
|
10
|
+
using Key_T = typename T::key_type;
|
11
|
+
using Mapped_T = typename T::mapped_type;
|
12
|
+
using Value_T = typename T::value_type;
|
13
|
+
using Reference_T = typename T::reference;
|
14
|
+
using Size_T = typename T::size_type;
|
15
|
+
using Difference_T = typename T::difference_type;
|
16
|
+
using To_Ruby_T = typename detail::remove_cv_recursive_t<Mapped_T>;
|
17
|
+
|
18
|
+
public:
|
19
|
+
UnorderedMapHelper(Data_Type<T> klass) : klass_(klass)
|
20
|
+
{
|
21
|
+
this->register_pair();
|
22
|
+
this->define_constructor();
|
23
|
+
this->define_copyable_methods();
|
24
|
+
this->define_capacity_methods();
|
25
|
+
this->define_access_methods();
|
26
|
+
this->define_comparable_methods();
|
27
|
+
this->define_modify_methods();
|
28
|
+
this->define_enumerable();
|
29
|
+
this->define_to_s();
|
30
|
+
this->define_to_hash();
|
31
|
+
}
|
32
|
+
|
33
|
+
private:
|
34
|
+
|
35
|
+
void register_pair()
|
36
|
+
{
|
37
|
+
define_pair<const Key_T, T>();
|
38
|
+
}
|
39
|
+
|
40
|
+
void define_constructor()
|
41
|
+
{
|
42
|
+
klass_.define_constructor(Constructor<T>());
|
43
|
+
}
|
44
|
+
|
45
|
+
void define_copyable_methods()
|
46
|
+
{
|
47
|
+
if constexpr (std::is_copy_constructible_v<Value_T>)
|
48
|
+
{
|
49
|
+
klass_.define_method("copy", [](T& unordered_map) -> T
|
50
|
+
{
|
51
|
+
return unordered_map;
|
52
|
+
});
|
53
|
+
}
|
54
|
+
else
|
55
|
+
{
|
56
|
+
klass_.define_method("copy", [](T& unordered_map) -> T
|
57
|
+
{
|
58
|
+
throw std::runtime_error("Cannot copy unordered_maps with non-copy constructible types");
|
59
|
+
return unordered_map;
|
60
|
+
});
|
61
|
+
}
|
62
|
+
}
|
63
|
+
|
64
|
+
void define_capacity_methods()
|
65
|
+
{
|
66
|
+
klass_.define_method("empty?", &T::empty)
|
67
|
+
.define_method("max_size", &T::max_size)
|
68
|
+
.define_method("size", &T::size);
|
69
|
+
|
70
|
+
rb_define_alias(klass_, "count", "size");
|
71
|
+
rb_define_alias(klass_, "length", "size");
|
72
|
+
}
|
73
|
+
|
74
|
+
void define_access_methods()
|
75
|
+
{
|
76
|
+
// Access methods
|
77
|
+
klass_.define_method("[]", [](const T& unordered_map, const Key_T& key) -> std::optional<Mapped_T>
|
78
|
+
{
|
79
|
+
auto iter = unordered_map.find(key);
|
80
|
+
|
81
|
+
if (iter != unordered_map.end())
|
82
|
+
{
|
83
|
+
return iter->second;
|
84
|
+
}
|
85
|
+
else
|
86
|
+
{
|
87
|
+
return std::nullopt;
|
88
|
+
}
|
89
|
+
})
|
90
|
+
.define_method("include?", [](T& unordered_map, Key_T& key) -> bool
|
91
|
+
{
|
92
|
+
return unordered_map.find(key) != unordered_map.end();
|
93
|
+
})
|
94
|
+
.define_method("keys", [](T& unordered_map) -> std::vector<Key_T>
|
95
|
+
{
|
96
|
+
std::vector<Key_T> result;
|
97
|
+
std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
|
98
|
+
[](const auto& pair)
|
99
|
+
{
|
100
|
+
return pair.first;
|
101
|
+
});
|
102
|
+
|
103
|
+
return result;
|
104
|
+
})
|
105
|
+
.define_method("values", [](T& unordered_map) -> std::vector<Mapped_T>
|
106
|
+
{
|
107
|
+
std::vector<Mapped_T> result;
|
108
|
+
std::transform(unordered_map.begin(), unordered_map.end(), std::back_inserter(result),
|
109
|
+
[](const auto& pair)
|
110
|
+
{
|
111
|
+
return pair.second;
|
112
|
+
});
|
113
|
+
|
114
|
+
return result;
|
115
|
+
});
|
116
|
+
|
117
|
+
rb_define_alias(klass_, "has_key", "include?");
|
118
|
+
}
|
119
|
+
|
120
|
+
// Methods that require Value_T to support operator==
|
121
|
+
void define_comparable_methods()
|
122
|
+
{
|
123
|
+
if constexpr (detail::is_comparable_v<Mapped_T>)
|
124
|
+
{
|
125
|
+
klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
|
126
|
+
{
|
127
|
+
auto it = std::find_if(unordered_map.begin(), unordered_map.end(),
|
128
|
+
[&value](auto& pair)
|
129
|
+
{
|
130
|
+
return pair.second == value;
|
131
|
+
});
|
132
|
+
|
133
|
+
return it != unordered_map.end();
|
134
|
+
});
|
135
|
+
}
|
136
|
+
else
|
137
|
+
{
|
138
|
+
klass_.define_method("value?", [](T& unordered_map, Mapped_T& value) -> bool
|
139
|
+
{
|
140
|
+
return false;
|
141
|
+
});
|
142
|
+
}
|
143
|
+
|
144
|
+
rb_define_alias(klass_, "has_value", "value?");
|
145
|
+
}
|
146
|
+
|
147
|
+
void define_modify_methods()
|
148
|
+
{
|
149
|
+
klass_.define_method("clear", &T::clear)
|
150
|
+
.define_method("delete", [](T& unordered_map, Key_T& key) -> std::optional<Mapped_T>
|
151
|
+
{
|
152
|
+
auto iter = unordered_map.find(key);
|
153
|
+
|
154
|
+
if (iter != unordered_map.end())
|
155
|
+
{
|
156
|
+
Mapped_T result = iter->second;
|
157
|
+
unordered_map.erase(iter);
|
158
|
+
return result;
|
159
|
+
}
|
160
|
+
else
|
161
|
+
{
|
162
|
+
return std::nullopt;
|
163
|
+
}
|
164
|
+
})
|
165
|
+
.define_method("[]=", [](T& unordered_map, Key_T key, Mapped_T& value) -> Mapped_T
|
166
|
+
{
|
167
|
+
unordered_map[key] = value;
|
168
|
+
return value;
|
169
|
+
});
|
170
|
+
|
171
|
+
rb_define_alias(klass_, "store", "[]=");
|
172
|
+
}
|
173
|
+
|
174
|
+
void define_enumerable()
|
175
|
+
{
|
176
|
+
// Add enumerable support
|
177
|
+
klass_.template define_iterator<typename T::iterator (T::*)()>(&T::begin, &T::end);
|
178
|
+
}
|
179
|
+
|
180
|
+
void define_to_hash()
|
181
|
+
{
|
182
|
+
// Add enumerable support
|
183
|
+
klass_.define_method("to_h", [](T& unordered_map)
|
184
|
+
{
|
185
|
+
VALUE result = rb_hash_new();
|
186
|
+
std::for_each(unordered_map.begin(), unordered_map.end(), [&result](const Reference_T& pair)
|
187
|
+
{
|
188
|
+
VALUE key = detail::To_Ruby<Key_T&>().convert(pair.first);
|
189
|
+
VALUE value = detail::To_Ruby<To_Ruby_T&>().convert(pair.second);
|
190
|
+
rb_hash_aset(result, key, value);
|
191
|
+
});
|
192
|
+
|
193
|
+
return result;
|
194
|
+
}, Return().setValue());
|
195
|
+
}
|
196
|
+
|
197
|
+
void define_to_s()
|
198
|
+
{
|
199
|
+
if constexpr (detail::is_ostreamable_v<Key_T> && detail::is_ostreamable_v<Mapped_T>)
|
200
|
+
{
|
201
|
+
klass_.define_method("to_s", [](const T& unordered_map)
|
202
|
+
{
|
203
|
+
auto iter = unordered_map.begin();
|
204
|
+
|
205
|
+
std::stringstream stream;
|
206
|
+
stream << "{";
|
207
|
+
|
208
|
+
for (; iter != unordered_map.end(); iter++)
|
209
|
+
{
|
210
|
+
if (iter != unordered_map.begin())
|
211
|
+
{
|
212
|
+
stream << ", ";
|
213
|
+
}
|
214
|
+
stream << iter->first << " => " << iter->second;
|
215
|
+
}
|
216
|
+
|
217
|
+
stream << "}";
|
218
|
+
return stream.str();
|
219
|
+
});
|
220
|
+
}
|
221
|
+
else
|
222
|
+
{
|
223
|
+
klass_.define_method("to_s", [](const T& unordered_map)
|
224
|
+
{
|
225
|
+
return "[Not printable]";
|
226
|
+
});
|
227
|
+
}
|
228
|
+
}
|
229
|
+
|
230
|
+
private:
|
231
|
+
Data_Type<T> klass_;
|
232
|
+
};
|
233
|
+
} // namespace
|
234
|
+
|
235
|
+
template<typename Key, typename T>
|
236
|
+
Data_Type<std::unordered_map<Key, T>> define_unordered_map(std::string klassName)
|
237
|
+
{
|
238
|
+
using UnorderedMap_T = std::unordered_map<Key, T>;
|
239
|
+
using Data_Type_T = Data_Type<UnorderedMap_T>;
|
240
|
+
|
241
|
+
if (klassName.empty())
|
242
|
+
{
|
243
|
+
std::string typeName = detail::typeName(typeid(UnorderedMap_T));
|
244
|
+
klassName = detail::rubyClassName(typeName);
|
245
|
+
}
|
246
|
+
|
247
|
+
Module rb_mStd = define_module("Std");
|
248
|
+
if (Data_Type_T::check_defined(klassName, rb_mStd))
|
249
|
+
{
|
250
|
+
return Data_Type_T();
|
251
|
+
}
|
252
|
+
|
253
|
+
Identifier id(klassName);
|
254
|
+
Data_Type_T result = define_class_under<detail::intrinsic_type<UnorderedMap_T>>(rb_mStd, id);
|
255
|
+
stl::UnorderedMapHelper helper(result);
|
256
|
+
return result;
|
257
|
+
}
|
258
|
+
|
259
|
+
namespace detail
|
260
|
+
{
|
261
|
+
template<typename Key_T, typename T>
|
262
|
+
struct Type<std::unordered_map<Key_T, T>>
|
263
|
+
{
|
264
|
+
static bool verify()
|
265
|
+
{
|
266
|
+
Type<Key_T>::verify();
|
267
|
+
Type<T>::verify();
|
268
|
+
|
269
|
+
if (!Data_Type<std::unordered_map<Key_T, T>>::is_defined())
|
270
|
+
{
|
271
|
+
define_unordered_map<Key_T, T>();
|
272
|
+
}
|
273
|
+
|
274
|
+
return true;
|
275
|
+
}
|
276
|
+
};
|
277
|
+
|
278
|
+
template<typename T, typename U>
|
279
|
+
struct UnorderedMapFromHash
|
280
|
+
{
|
281
|
+
static int convertPair(VALUE key, VALUE value, VALUE user_data)
|
282
|
+
{
|
283
|
+
std::unordered_map<T, U>* result = (std::unordered_map<T, U>*)(user_data);
|
284
|
+
|
285
|
+
// This method is being called from Ruby so we cannot let any C++
|
286
|
+
// exceptions propogate back to Ruby
|
287
|
+
return cpp_protect([&]
|
288
|
+
{
|
289
|
+
result->operator[](From_Ruby<T>().convert(key)) = From_Ruby<U>().convert(value);
|
290
|
+
return ST_CONTINUE;
|
291
|
+
});
|
292
|
+
}
|
293
|
+
|
294
|
+
static std::unordered_map<T, U> convert(VALUE value)
|
295
|
+
{
|
296
|
+
std::unordered_map<T, U> result;
|
297
|
+
VALUE user_data = (VALUE)(&result);
|
298
|
+
|
299
|
+
// MSVC needs help here, but g++ does not
|
300
|
+
using Rb_Hash_ForEach_T = void(*)(VALUE, int(*)(VALUE, VALUE, VALUE), VALUE);
|
301
|
+
detail::protect<Rb_Hash_ForEach_T>(rb_hash_foreach, value, convertPair, user_data);
|
302
|
+
|
303
|
+
return result;
|
304
|
+
}
|
305
|
+
};
|
306
|
+
|
307
|
+
template<typename T, typename U>
|
308
|
+
class From_Ruby<std::unordered_map<T, U>>
|
309
|
+
{
|
310
|
+
public:
|
311
|
+
From_Ruby() = default;
|
312
|
+
|
313
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
314
|
+
{
|
315
|
+
}
|
316
|
+
|
317
|
+
Convertible is_convertible(VALUE value)
|
318
|
+
{
|
319
|
+
switch (rb_type(value))
|
320
|
+
{
|
321
|
+
case RUBY_T_DATA:
|
322
|
+
return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
323
|
+
break;
|
324
|
+
case RUBY_T_HASH:
|
325
|
+
return Convertible::Cast;
|
326
|
+
break;
|
327
|
+
default:
|
328
|
+
return Convertible::None;
|
329
|
+
}
|
330
|
+
}
|
331
|
+
|
332
|
+
std::unordered_map<T, U> convert(VALUE value)
|
333
|
+
{
|
334
|
+
switch (rb_type(value))
|
335
|
+
{
|
336
|
+
case RUBY_T_DATA:
|
337
|
+
{
|
338
|
+
// This is a wrapped unordered_map (hopefully!)
|
339
|
+
return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
|
340
|
+
}
|
341
|
+
case RUBY_T_HASH:
|
342
|
+
{
|
343
|
+
// If this an Ruby hash and the unordered_mapped type is copyable
|
344
|
+
if constexpr (std::is_default_constructible_v<U>)
|
345
|
+
{
|
346
|
+
return UnorderedMapFromHash<T, U>::convert(value);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
default:
|
350
|
+
{
|
351
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
352
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
353
|
+
}
|
354
|
+
}
|
355
|
+
}
|
356
|
+
|
357
|
+
private:
|
358
|
+
Arg* arg_ = nullptr;
|
359
|
+
};
|
360
|
+
|
361
|
+
template<typename T, typename U>
|
362
|
+
class From_Ruby<std::unordered_map<T, U>&>
|
363
|
+
{
|
364
|
+
public:
|
365
|
+
From_Ruby() = default;
|
366
|
+
|
367
|
+
explicit From_Ruby(Arg * arg) : arg_(arg)
|
368
|
+
{
|
369
|
+
}
|
370
|
+
|
371
|
+
Convertible is_convertible(VALUE value)
|
372
|
+
{
|
373
|
+
switch (rb_type(value))
|
374
|
+
{
|
375
|
+
case RUBY_T_DATA:
|
376
|
+
return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
377
|
+
break;
|
378
|
+
case RUBY_T_HASH:
|
379
|
+
return Convertible::Cast;
|
380
|
+
break;
|
381
|
+
default:
|
382
|
+
return Convertible::None;
|
383
|
+
}
|
384
|
+
}
|
385
|
+
|
386
|
+
std::unordered_map<T, U>& convert(VALUE value)
|
387
|
+
{
|
388
|
+
switch (rb_type(value))
|
389
|
+
{
|
390
|
+
case RUBY_T_DATA:
|
391
|
+
{
|
392
|
+
// This is a wrapped unordered_map (hopefully!)
|
393
|
+
return *detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
|
394
|
+
}
|
395
|
+
case RUBY_T_HASH:
|
396
|
+
{
|
397
|
+
// If this an Ruby array and the unordered_map type is copyable
|
398
|
+
if constexpr (std::is_default_constructible_v<std::unordered_map<T, U>>)
|
399
|
+
{
|
400
|
+
this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
|
401
|
+
return this->converted_;
|
402
|
+
}
|
403
|
+
}
|
404
|
+
default:
|
405
|
+
{
|
406
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
407
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
408
|
+
}
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
private:
|
413
|
+
Arg* arg_ = nullptr;
|
414
|
+
std::unordered_map<T, U> converted_;
|
415
|
+
};
|
416
|
+
|
417
|
+
template<typename T, typename U>
|
418
|
+
class From_Ruby<std::unordered_map<T, U>*>
|
419
|
+
{
|
420
|
+
public:
|
421
|
+
Convertible is_convertible(VALUE value)
|
422
|
+
{
|
423
|
+
switch (rb_type(value))
|
424
|
+
{
|
425
|
+
case RUBY_T_DATA:
|
426
|
+
return Data_Type<std::unordered_map<T, U>>::is_descendant(value) ? Convertible::Exact : Convertible::None;
|
427
|
+
break;
|
428
|
+
case RUBY_T_NIL:
|
429
|
+
return Convertible::Exact;
|
430
|
+
break;
|
431
|
+
case RUBY_T_HASH:
|
432
|
+
return Convertible::Cast;
|
433
|
+
break;
|
434
|
+
default:
|
435
|
+
return Convertible::None;
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
std::unordered_map<T, U>* convert(VALUE value)
|
440
|
+
{
|
441
|
+
switch (rb_type(value))
|
442
|
+
{
|
443
|
+
case RUBY_T_DATA:
|
444
|
+
{
|
445
|
+
// This is a wrapped unordered_map (hopefully!)
|
446
|
+
return detail::unwrap<std::unordered_map<T, U>>(value, Data_Type<std::unordered_map<T, U>>::ruby_data_type(), false);
|
447
|
+
}
|
448
|
+
case RUBY_T_HASH:
|
449
|
+
{
|
450
|
+
// If this an Ruby array and the unordered_map type is copyable
|
451
|
+
if constexpr (std::is_default_constructible_v<U>)
|
452
|
+
{
|
453
|
+
this->converted_ = UnorderedMapFromHash<T, U>::convert(value);
|
454
|
+
return &this->converted_;
|
455
|
+
}
|
456
|
+
}
|
457
|
+
default:
|
458
|
+
{
|
459
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected % s)",
|
460
|
+
detail::protect(rb_obj_classname, value), "std::unordered_map");
|
461
|
+
}
|
462
|
+
}
|
463
|
+
}
|
464
|
+
|
465
|
+
private:
|
466
|
+
std::unordered_map<T, U> converted_;
|
467
|
+
};
|
468
|
+
}
|
469
|
+
}
|