rice 4.11.1 → 4.11.3
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 +27 -1
- data/CMakePresets.json +3 -3
- data/include/rice/rice.hpp +209 -22
- data/include/rice/stl.hpp +22 -10
- data/lib/mkmf-rice.rb +6 -4
- data/lib/rice/version.rb +1 -1
- data/rice/Data_Type.ipp +0 -2
- data/rice/detail/RubyType.ipp +11 -0
- data/rice/detail/TypeRegistry.ipp +6 -0
- data/rice/detail/Types.ipp +29 -0
- data/rice/detail/Wrapper.ipp +3 -1
- data/rice/detail/from_ruby.ipp +83 -19
- data/rice/detail/to_ruby.ipp +56 -0
- data/rice/stl/map.ipp +2 -2
- data/rice/stl/ostream.ipp +5 -1
- data/rice/stl/pair.ipp +6 -2
- data/rice/stl/shared_ptr.ipp +6 -2
- data/rice/stl/unique_ptr.ipp +1 -1
- data/rice/stl/unordered_map.ipp +2 -2
- data/rice/traits/function_traits.hpp +21 -0
- data/test/test_Attribute.cpp +31 -0
- data/test/test_Callback.cpp +2 -4
- data/test/test_From_Ruby.cpp +14 -0
- data/test/test_Stl_Map.cpp +56 -0
- data/test/test_Stl_Pair.cpp +32 -0
- data/test/test_Stl_SharedPtr.cpp +93 -0
- data/test/test_Stl_UniquePtr.cpp +47 -0
- data/test/test_Stl_Unordered_Map.cpp +56 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2b52ff5ddc64209e1c252d529111695d833a57d1362e15b6d223777194dc6750
|
|
4
|
+
data.tar.gz: 214c2b675683e68d026440cc83499a7de0faa6282563c0bfa028c925e677f195
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fdee833532115137ec7e375e83e377c5e21a634b44e0b67bb5954ea3ad04a2983ef3c6ffc5d5deb804b1d94c7b76f04d2cc94b73b054aaa0722f01fd39f58c37
|
|
7
|
+
data.tar.gz: 23e9990bbf398a067608c29028018840506254f3a8a00a7f6cc56840ec88e70007d0309656b297b20ab31776805b3deccb14e16fface820b0ec7d3340aafc0f3
|
data/CHANGELOG.md
CHANGED
|
@@ -1,12 +1,38 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.11.3 (2026-03-11)
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Fix C++20 compilation error with `std::ostringstream::str` overload (#395)
|
|
8
|
+
* Add `function_traits` specializations for ref-qualified member functions (`&`, `const&`)
|
|
9
|
+
|
|
10
|
+
### Enhancements
|
|
11
|
+
|
|
12
|
+
* Support C++20 and C++23 compilation
|
|
13
|
+
* Make C++ standard version configurable via `--with-cxx-standard` in mkmf-rice
|
|
14
|
+
* Add `/Zc:__cplusplus` to MSVC build flags
|
|
15
|
+
* Add CMake-based CI job testing C++17, C++20, and C++23
|
|
16
|
+
* Add test case for function pointer struct attributes
|
|
17
|
+
* Add support for `std::shared_ptr<const T>`
|
|
18
|
+
* Add support for `std::unique_ptr<const T>`
|
|
19
|
+
* Add support for non-constructible objects in std::pair, std::map, std::multimap
|
|
20
|
+
* Add support for wrapping pointers to abstract types that cannot be created nor destroyed
|
|
21
|
+
* Fix converting std::nullptr_t to Ruby
|
|
22
|
+
|
|
23
|
+
## 4.11.2 (2026-02-21)
|
|
24
|
+
|
|
25
|
+
### Enhancements
|
|
26
|
+
|
|
27
|
+
* Add support for `long double`
|
|
28
|
+
* Improve support for references to incomplete types
|
|
29
|
+
|
|
3
30
|
## 4.11.1 (2026-02-18)
|
|
4
31
|
|
|
5
32
|
### Enhancements
|
|
6
33
|
|
|
7
34
|
* Be more lenient on wrapp Qnil values in the C++ API
|
|
8
35
|
|
|
9
|
-
|
|
10
36
|
## 4.11.0 (2026-02-17)
|
|
11
37
|
|
|
12
38
|
This release focuses on improving memory management.
|
data/CMakePresets.json
CHANGED
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake",
|
|
117
117
|
"cacheVariables": {
|
|
118
118
|
"CMAKE_EXPORT_COMPILE_COMMANDS": "ON",
|
|
119
|
-
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE"
|
|
119
|
+
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /Zc:__cplusplus /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE"
|
|
120
120
|
},
|
|
121
121
|
"condition": {
|
|
122
122
|
"type": "equals",
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"cacheVariables": {
|
|
156
156
|
"CMAKE_BUILD_TYPE": "Debug",
|
|
157
157
|
"CMAKE_CXX_COMPILER": "clang-cl.exe",
|
|
158
|
-
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field",
|
|
158
|
+
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /Zc:__cplusplus /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field",
|
|
159
159
|
"CMAKE_CXX_FLAGS_DEBUG": "/Od /Zi"
|
|
160
160
|
}
|
|
161
161
|
},
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
"cacheVariables": {
|
|
167
167
|
"CMAKE_BUILD_TYPE": "Release",
|
|
168
168
|
"CMAKE_CXX_COMPILER": "clang-cl.exe",
|
|
169
|
-
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field",
|
|
169
|
+
"CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /Zc:__cplusplus /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field",
|
|
170
170
|
"CMAKE_CXX_FLAGS_RELEASE": "/O2 /DNDEBUG",
|
|
171
171
|
"CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON"
|
|
172
172
|
}
|
data/include/rice/rice.hpp
CHANGED
|
@@ -556,6 +556,27 @@ namespace Rice::detail
|
|
|
556
556
|
{
|
|
557
557
|
};
|
|
558
558
|
|
|
559
|
+
// ref-qualified member Functions on C++ classes (C++20 uses these for std library types)
|
|
560
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
561
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) &> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
562
|
+
{
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
566
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const&> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
567
|
+
{
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
571
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) & noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
572
|
+
{
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
576
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const& noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
577
|
+
{
|
|
578
|
+
};
|
|
579
|
+
|
|
559
580
|
/*// Functors and lambdas
|
|
560
581
|
template<class Function_T>
|
|
561
582
|
struct function_traits<Function_T&> : public function_traits<Function_T>
|
|
@@ -3797,6 +3818,17 @@ namespace Rice::detail
|
|
|
3797
3818
|
static inline std::string name = "Float";
|
|
3798
3819
|
};
|
|
3799
3820
|
|
|
3821
|
+
template<>
|
|
3822
|
+
class RubyType<long double>
|
|
3823
|
+
{
|
|
3824
|
+
public:
|
|
3825
|
+
using FromRuby_T = double(*)(VALUE);
|
|
3826
|
+
|
|
3827
|
+
static inline FromRuby_T fromRuby = rb_num2dbl;
|
|
3828
|
+
static inline std::string packTemplate = "d*";
|
|
3829
|
+
static inline std::string name = "Float";
|
|
3830
|
+
};
|
|
3831
|
+
|
|
3800
3832
|
template<>
|
|
3801
3833
|
class RubyType<void>
|
|
3802
3834
|
{
|
|
@@ -6073,6 +6105,35 @@ namespace Rice::detail
|
|
|
6073
6105
|
}
|
|
6074
6106
|
};
|
|
6075
6107
|
|
|
6108
|
+
template<>
|
|
6109
|
+
struct Type<long double>
|
|
6110
|
+
{
|
|
6111
|
+
static bool verify()
|
|
6112
|
+
{
|
|
6113
|
+
return true;
|
|
6114
|
+
}
|
|
6115
|
+
|
|
6116
|
+
static VALUE rubyKlass()
|
|
6117
|
+
{
|
|
6118
|
+
return rb_cFloat;
|
|
6119
|
+
}
|
|
6120
|
+
};
|
|
6121
|
+
|
|
6122
|
+
template<int N>
|
|
6123
|
+
struct Type<long double[N]>
|
|
6124
|
+
{
|
|
6125
|
+
static bool verify()
|
|
6126
|
+
{
|
|
6127
|
+
define_buffer<long double>();
|
|
6128
|
+
return true;
|
|
6129
|
+
}
|
|
6130
|
+
|
|
6131
|
+
static VALUE rubyKlass()
|
|
6132
|
+
{
|
|
6133
|
+
return rb_cString;
|
|
6134
|
+
}
|
|
6135
|
+
};
|
|
6136
|
+
|
|
6076
6137
|
template<>
|
|
6077
6138
|
struct Type<void>
|
|
6078
6139
|
{
|
|
@@ -6601,6 +6662,62 @@ namespace Rice
|
|
|
6601
6662
|
Arg* arg_ = nullptr;
|
|
6602
6663
|
};
|
|
6603
6664
|
|
|
6665
|
+
// =========== long double ============
|
|
6666
|
+
template<>
|
|
6667
|
+
class To_Ruby<long double>
|
|
6668
|
+
{
|
|
6669
|
+
public:
|
|
6670
|
+
To_Ruby() = default;
|
|
6671
|
+
|
|
6672
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
6673
|
+
{}
|
|
6674
|
+
|
|
6675
|
+
VALUE convert(const long double& native)
|
|
6676
|
+
{
|
|
6677
|
+
return protect(rb_float_new, native);
|
|
6678
|
+
}
|
|
6679
|
+
|
|
6680
|
+
private:
|
|
6681
|
+
Arg* arg_ = nullptr;
|
|
6682
|
+
};
|
|
6683
|
+
|
|
6684
|
+
template<>
|
|
6685
|
+
class To_Ruby<long double&>
|
|
6686
|
+
{
|
|
6687
|
+
public:
|
|
6688
|
+
To_Ruby() = default;
|
|
6689
|
+
|
|
6690
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
6691
|
+
{}
|
|
6692
|
+
|
|
6693
|
+
VALUE convert(const long double& native)
|
|
6694
|
+
{
|
|
6695
|
+
return protect(rb_float_new, native);
|
|
6696
|
+
}
|
|
6697
|
+
|
|
6698
|
+
private:
|
|
6699
|
+
Arg* arg_ = nullptr;
|
|
6700
|
+
};
|
|
6701
|
+
|
|
6702
|
+
template<int N>
|
|
6703
|
+
class To_Ruby<long double[N]>
|
|
6704
|
+
{
|
|
6705
|
+
public:
|
|
6706
|
+
To_Ruby() = default;
|
|
6707
|
+
|
|
6708
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
6709
|
+
{}
|
|
6710
|
+
|
|
6711
|
+
VALUE convert(long double data[N])
|
|
6712
|
+
{
|
|
6713
|
+
Buffer<long double> buffer(data, N);
|
|
6714
|
+
Data_Object<Buffer<long double>> dataObject(std::move(buffer));
|
|
6715
|
+
return dataObject.value();
|
|
6716
|
+
}
|
|
6717
|
+
private:
|
|
6718
|
+
Arg* arg_ = nullptr;
|
|
6719
|
+
};
|
|
6720
|
+
|
|
6604
6721
|
// =========== float ============
|
|
6605
6722
|
template<>
|
|
6606
6723
|
class To_Ruby<float>
|
|
@@ -7879,6 +7996,86 @@ namespace Rice::detail
|
|
|
7879
7996
|
Reference<double> reference_;
|
|
7880
7997
|
};
|
|
7881
7998
|
|
|
7999
|
+
// =========== long double ============
|
|
8000
|
+
template<>
|
|
8001
|
+
class From_Ruby<long double>
|
|
8002
|
+
{
|
|
8003
|
+
public:
|
|
8004
|
+
From_Ruby() = default;
|
|
8005
|
+
|
|
8006
|
+
explicit From_Ruby(Arg* arg) : arg_(arg)
|
|
8007
|
+
{}
|
|
8008
|
+
|
|
8009
|
+
long double is_convertible(VALUE value)
|
|
8010
|
+
{
|
|
8011
|
+
return FromRubyFundamental<long double>::is_convertible(value);
|
|
8012
|
+
}
|
|
8013
|
+
|
|
8014
|
+
long double convert(VALUE value)
|
|
8015
|
+
{
|
|
8016
|
+
return FromRubyFundamental<long double>::convert(value);
|
|
8017
|
+
}
|
|
8018
|
+
|
|
8019
|
+
private:
|
|
8020
|
+
Arg* arg_ = nullptr;
|
|
8021
|
+
};
|
|
8022
|
+
|
|
8023
|
+
template<>
|
|
8024
|
+
class From_Ruby<long double&>
|
|
8025
|
+
{
|
|
8026
|
+
public:
|
|
8027
|
+
using Reference_T = Reference<long double>;
|
|
8028
|
+
|
|
8029
|
+
From_Ruby() = default;
|
|
8030
|
+
|
|
8031
|
+
explicit From_Ruby(Arg* arg) : arg_(arg)
|
|
8032
|
+
{}
|
|
8033
|
+
|
|
8034
|
+
long double is_convertible(VALUE value)
|
|
8035
|
+
{
|
|
8036
|
+
switch (rb_type(value))
|
|
8037
|
+
{
|
|
8038
|
+
case RUBY_T_DATA:
|
|
8039
|
+
{
|
|
8040
|
+
if (Data_Type<Reference_T>::is_descendant(value))
|
|
8041
|
+
{
|
|
8042
|
+
return Convertible::Exact;
|
|
8043
|
+
}
|
|
8044
|
+
[[fallthrough]];
|
|
8045
|
+
}
|
|
8046
|
+
default:
|
|
8047
|
+
{
|
|
8048
|
+
return FromRubyFundamental<long double>::is_convertible(value);
|
|
8049
|
+
}
|
|
8050
|
+
}
|
|
8051
|
+
}
|
|
8052
|
+
|
|
8053
|
+
long double& convert(VALUE value)
|
|
8054
|
+
{
|
|
8055
|
+
switch (rb_type(value))
|
|
8056
|
+
{
|
|
8057
|
+
case RUBY_T_DATA:
|
|
8058
|
+
{
|
|
8059
|
+
if (Data_Type<Reference_T>::is_descendant(value))
|
|
8060
|
+
{
|
|
8061
|
+
Reference_T* reference = unwrap<Reference_T>(value, Data_Type<Reference_T>::ruby_data_type(), false);
|
|
8062
|
+
return reference->get();
|
|
8063
|
+
}
|
|
8064
|
+
[[fallthrough]];
|
|
8065
|
+
}
|
|
8066
|
+
default:
|
|
8067
|
+
{
|
|
8068
|
+
this->reference_ = Reference<long double>(value);
|
|
8069
|
+
return this->reference_.get();
|
|
8070
|
+
}
|
|
8071
|
+
}
|
|
8072
|
+
}
|
|
8073
|
+
|
|
8074
|
+
private:
|
|
8075
|
+
Arg* arg_ = nullptr;
|
|
8076
|
+
Reference<long double> reference_;
|
|
8077
|
+
};
|
|
8078
|
+
|
|
7882
8079
|
// =========== float ============
|
|
7883
8080
|
template<>
|
|
7884
8081
|
class From_Ruby<float>
|
|
@@ -8678,31 +8875,15 @@ namespace Rice::detail
|
|
|
8678
8875
|
}
|
|
8679
8876
|
}
|
|
8680
8877
|
|
|
8681
|
-
|
|
8878
|
+
std::nullptr_t convert(VALUE value)
|
|
8682
8879
|
{
|
|
8683
8880
|
if (value == Qnil)
|
|
8684
8881
|
{
|
|
8685
8882
|
return nullptr;
|
|
8686
8883
|
}
|
|
8687
8884
|
|
|
8688
|
-
|
|
8689
|
-
|
|
8690
|
-
return (void*)value;
|
|
8691
|
-
}
|
|
8692
|
-
|
|
8693
|
-
switch (rb_type(value))
|
|
8694
|
-
{
|
|
8695
|
-
case RUBY_T_NIL:
|
|
8696
|
-
{
|
|
8697
|
-
return nullptr;
|
|
8698
|
-
break;
|
|
8699
|
-
}
|
|
8700
|
-
default:
|
|
8701
|
-
{
|
|
8702
|
-
throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
|
|
8703
|
-
detail::protect(rb_obj_classname, value), "nil");
|
|
8704
|
-
}
|
|
8705
|
-
}
|
|
8885
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
|
|
8886
|
+
detail::protect(rb_obj_classname, value), "nil");
|
|
8706
8887
|
}
|
|
8707
8888
|
private:
|
|
8708
8889
|
Arg* arg_ = nullptr;
|
|
@@ -8973,6 +9154,12 @@ namespace Rice::detail
|
|
|
8973
9154
|
{
|
|
8974
9155
|
return std::type_index(typeid(T));
|
|
8975
9156
|
}
|
|
9157
|
+
else if constexpr (std::is_reference_v<T>)
|
|
9158
|
+
{
|
|
9159
|
+
// For incomplete reference types, strip the reference and use pointer.
|
|
9160
|
+
// Can't form T* when T is a reference type (pointer-to-reference is illegal).
|
|
9161
|
+
return std::type_index(typeid(std::remove_reference_t<T>*));
|
|
9162
|
+
}
|
|
8976
9163
|
else
|
|
8977
9164
|
{
|
|
8978
9165
|
return std::type_index(typeid(T*));
|
|
@@ -10095,7 +10282,9 @@ namespace Rice::detail
|
|
|
10095
10282
|
|
|
10096
10283
|
if constexpr (is_complete_v<T>)
|
|
10097
10284
|
{
|
|
10098
|
-
|
|
10285
|
+
// is_abstract_v requires a complete type, so nest inside is_complete_v.
|
|
10286
|
+
// Deleting an abstract class through a non-virtual destructor is UB.
|
|
10287
|
+
if constexpr (std::is_destructible_v<T> && !std::is_abstract_v<T>)
|
|
10099
10288
|
{
|
|
10100
10289
|
if (this->isOwner_)
|
|
10101
10290
|
{
|
|
@@ -14845,8 +15034,6 @@ namespace Rice
|
|
|
14845
15034
|
template <typename Attribute_T, typename Access_T, typename...Arg_Ts>
|
|
14846
15035
|
inline Data_Type<T>& Data_Type<T>::define_attr_internal(VALUE klass, std::string name, Attribute_T attribute, Access_T, const Arg_Ts&...args)
|
|
14847
15036
|
{
|
|
14848
|
-
using Attr_T = typename detail::attribute_traits<Attribute_T>::attr_type;
|
|
14849
|
-
|
|
14850
15037
|
// Define attribute getter
|
|
14851
15038
|
if constexpr (std::is_same_v<Access_T, AttrAccess::ReadWriteType> || std::is_same_v<Access_T, AttrAccess::ReadType>)
|
|
14852
15039
|
{
|
data/include/rice/stl.hpp
CHANGED
|
@@ -1133,8 +1133,12 @@ namespace Rice::stl
|
|
|
1133
1133
|
|
|
1134
1134
|
void define_methods()
|
|
1135
1135
|
{
|
|
1136
|
+
#if __cplusplus >= 202002L
|
|
1137
|
+
klass_.define_method<std::string(std::ostringstream::*)() const&>("str", &std::ostringstream::str)
|
|
1138
|
+
#else
|
|
1136
1139
|
klass_.define_method<std::string(std::ostringstream::*)() const>("str", &std::ostringstream::str)
|
|
1137
|
-
|
|
1140
|
+
#endif
|
|
1141
|
+
.define_method("str=", [](std::ostringstream& stream, const std::string& s) { stream.str(s); }, Arg("str"));
|
|
1138
1142
|
|
|
1139
1143
|
rb_define_alias(klass_, "to_s", "str");
|
|
1140
1144
|
}
|
|
@@ -1310,8 +1314,12 @@ namespace Rice
|
|
|
1310
1314
|
private:
|
|
1311
1315
|
void define_constructors()
|
|
1312
1316
|
{
|
|
1313
|
-
|
|
1314
|
-
|
|
1317
|
+
if constexpr (std::is_default_constructible_v<T>)
|
|
1318
|
+
{
|
|
1319
|
+
klass_.define_constructor(Constructor<T>());
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
klass_.define_constructor(Constructor<T, First_Parameter_T, Second_Parameter_T>(), Arg("x").keepAlive(), Arg("y").keepAlive());
|
|
1315
1323
|
|
|
1316
1324
|
if constexpr (std::is_copy_constructible_v<First_T> && std::is_copy_constructible_v<Second_T>)
|
|
1317
1325
|
{
|
|
@@ -1650,7 +1658,7 @@ namespace Rice
|
|
|
1650
1658
|
}, Arg("key"))
|
|
1651
1659
|
.define_method("[]=", [](T& map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
|
|
1652
1660
|
{
|
|
1653
|
-
map
|
|
1661
|
+
map.insert_or_assign(key, value);
|
|
1654
1662
|
return value;
|
|
1655
1663
|
}, Arg("key").keepAlive(), Arg("value").keepAlive());
|
|
1656
1664
|
|
|
@@ -1772,7 +1780,7 @@ namespace Rice
|
|
|
1772
1780
|
// exceptions propogate back to Ruby
|
|
1773
1781
|
return cpp_protect([&]
|
|
1774
1782
|
{
|
|
1775
|
-
result->
|
|
1783
|
+
result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
|
|
1776
1784
|
return ST_CONTINUE;
|
|
1777
1785
|
});
|
|
1778
1786
|
}
|
|
@@ -3201,7 +3209,11 @@ namespace Rice
|
|
|
3201
3209
|
|
|
3202
3210
|
if constexpr (detail::is_complete_v<T> && !std::is_void_v<T>)
|
|
3203
3211
|
{
|
|
3204
|
-
|
|
3212
|
+
// is_abstract_v requires a complete type, so it must be nested inside the is_complete_v check
|
|
3213
|
+
if constexpr (!std::is_abstract_v<T>)
|
|
3214
|
+
{
|
|
3215
|
+
result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
|
|
3216
|
+
}
|
|
3205
3217
|
}
|
|
3206
3218
|
|
|
3207
3219
|
// Forward methods to wrapped T
|
|
@@ -3256,7 +3268,7 @@ namespace Rice::detail
|
|
|
3256
3268
|
}
|
|
3257
3269
|
else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
|
|
3258
3270
|
{
|
|
3259
|
-
return this->data_.get();
|
|
3271
|
+
return (void*)this->data_.get();
|
|
3260
3272
|
}
|
|
3261
3273
|
else
|
|
3262
3274
|
{
|
|
@@ -3931,7 +3943,7 @@ namespace Rice::detail
|
|
|
3931
3943
|
}
|
|
3932
3944
|
else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
|
|
3933
3945
|
{
|
|
3934
|
-
return this->data_.get();
|
|
3946
|
+
return (void*)this->data_.get();
|
|
3935
3947
|
}
|
|
3936
3948
|
else
|
|
3937
3949
|
{
|
|
@@ -4171,7 +4183,7 @@ namespace Rice
|
|
|
4171
4183
|
}, Arg("key"))
|
|
4172
4184
|
.define_method("[]=", [](T& unordered_map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
|
|
4173
4185
|
{
|
|
4174
|
-
unordered_map
|
|
4186
|
+
unordered_map.insert_or_assign(key, value);
|
|
4175
4187
|
return value;
|
|
4176
4188
|
}, Arg("key").keepAlive(), Arg("value").keepAlive());
|
|
4177
4189
|
|
|
@@ -4293,7 +4305,7 @@ namespace Rice
|
|
|
4293
4305
|
// exceptions propogate back to Ruby
|
|
4294
4306
|
return cpp_protect([&]
|
|
4295
4307
|
{
|
|
4296
|
-
result->
|
|
4308
|
+
result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
|
|
4297
4309
|
return ST_CONTINUE;
|
|
4298
4310
|
});
|
|
4299
4311
|
}
|
data/lib/mkmf-rice.rb
CHANGED
|
@@ -24,14 +24,16 @@ end
|
|
|
24
24
|
# Now pull in the C++ support
|
|
25
25
|
include MakeMakefile['C++']
|
|
26
26
|
|
|
27
|
-
# Rice needs c++17.
|
|
27
|
+
# Rice needs c++17 or higher. Use --with-cxx-standard=20 to override.
|
|
28
|
+
std = with_config('cxx-standard', '17')
|
|
29
|
+
|
|
28
30
|
if IS_MSWIN
|
|
29
|
-
$CXXFLAGS += " /std:c
|
|
31
|
+
$CXXFLAGS += " /std:c++#{std} /EHs /permissive- /bigobj /utf-8 /Zc:__cplusplus"
|
|
30
32
|
$CPPFLAGS += " -D_ALLOW_KEYWORD_MACROS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE"
|
|
31
33
|
elsif IS_MINGW
|
|
32
|
-
$CXXFLAGS += " -std=c
|
|
34
|
+
$CXXFLAGS += " -std=c++#{std} -Wa,-mbig-obj"
|
|
33
35
|
else
|
|
34
|
-
$CXXFLAGS += " -std=c
|
|
36
|
+
$CXXFLAGS += " -std=c++#{std}"
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
# Rice needs to include its header. Let's setup the include path
|
data/lib/rice/version.rb
CHANGED
data/rice/Data_Type.ipp
CHANGED
|
@@ -376,8 +376,6 @@ namespace Rice
|
|
|
376
376
|
template <typename Attribute_T, typename Access_T, typename...Arg_Ts>
|
|
377
377
|
inline Data_Type<T>& Data_Type<T>::define_attr_internal(VALUE klass, std::string name, Attribute_T attribute, Access_T, const Arg_Ts&...args)
|
|
378
378
|
{
|
|
379
|
-
using Attr_T = typename detail::attribute_traits<Attribute_T>::attr_type;
|
|
380
|
-
|
|
381
379
|
// Define attribute getter
|
|
382
380
|
if constexpr (std::is_same_v<Access_T, AttrAccess::ReadWriteType> || std::is_same_v<Access_T, AttrAccess::ReadType>)
|
|
383
381
|
{
|
data/rice/detail/RubyType.ipp
CHANGED
|
@@ -154,6 +154,17 @@ namespace Rice::detail
|
|
|
154
154
|
static inline std::string name = "Float";
|
|
155
155
|
};
|
|
156
156
|
|
|
157
|
+
template<>
|
|
158
|
+
class RubyType<long double>
|
|
159
|
+
{
|
|
160
|
+
public:
|
|
161
|
+
using FromRuby_T = double(*)(VALUE);
|
|
162
|
+
|
|
163
|
+
static inline FromRuby_T fromRuby = rb_num2dbl;
|
|
164
|
+
static inline std::string packTemplate = "d*";
|
|
165
|
+
static inline std::string name = "Float";
|
|
166
|
+
};
|
|
167
|
+
|
|
157
168
|
template<>
|
|
158
169
|
class RubyType<void>
|
|
159
170
|
{
|
|
@@ -13,6 +13,12 @@ namespace Rice::detail
|
|
|
13
13
|
{
|
|
14
14
|
return std::type_index(typeid(T));
|
|
15
15
|
}
|
|
16
|
+
else if constexpr (std::is_reference_v<T>)
|
|
17
|
+
{
|
|
18
|
+
// For incomplete reference types, strip the reference and use pointer.
|
|
19
|
+
// Can't form T* when T is a reference type (pointer-to-reference is illegal).
|
|
20
|
+
return std::type_index(typeid(std::remove_reference_t<T>*));
|
|
21
|
+
}
|
|
16
22
|
else
|
|
17
23
|
{
|
|
18
24
|
return std::type_index(typeid(T*));
|
data/rice/detail/Types.ipp
CHANGED
|
@@ -404,6 +404,35 @@ namespace Rice::detail
|
|
|
404
404
|
}
|
|
405
405
|
};
|
|
406
406
|
|
|
407
|
+
template<>
|
|
408
|
+
struct Type<long double>
|
|
409
|
+
{
|
|
410
|
+
static bool verify()
|
|
411
|
+
{
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
static VALUE rubyKlass()
|
|
416
|
+
{
|
|
417
|
+
return rb_cFloat;
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
template<int N>
|
|
422
|
+
struct Type<long double[N]>
|
|
423
|
+
{
|
|
424
|
+
static bool verify()
|
|
425
|
+
{
|
|
426
|
+
define_buffer<long double>();
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
static VALUE rubyKlass()
|
|
431
|
+
{
|
|
432
|
+
return rb_cString;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
|
|
407
436
|
template<>
|
|
408
437
|
struct Type<void>
|
|
409
438
|
{
|
data/rice/detail/Wrapper.ipp
CHANGED
|
@@ -121,7 +121,9 @@ namespace Rice::detail
|
|
|
121
121
|
|
|
122
122
|
if constexpr (is_complete_v<T>)
|
|
123
123
|
{
|
|
124
|
-
|
|
124
|
+
// is_abstract_v requires a complete type, so nest inside is_complete_v.
|
|
125
|
+
// Deleting an abstract class through a non-virtual destructor is UB.
|
|
126
|
+
if constexpr (std::is_destructible_v<T> && !std::is_abstract_v<T>)
|
|
125
127
|
{
|
|
126
128
|
if (this->isOwner_)
|
|
127
129
|
{
|
data/rice/detail/from_ruby.ipp
CHANGED
|
@@ -729,6 +729,86 @@ namespace Rice::detail
|
|
|
729
729
|
Reference<double> reference_;
|
|
730
730
|
};
|
|
731
731
|
|
|
732
|
+
// =========== long double ============
|
|
733
|
+
template<>
|
|
734
|
+
class From_Ruby<long double>
|
|
735
|
+
{
|
|
736
|
+
public:
|
|
737
|
+
From_Ruby() = default;
|
|
738
|
+
|
|
739
|
+
explicit From_Ruby(Arg* arg) : arg_(arg)
|
|
740
|
+
{}
|
|
741
|
+
|
|
742
|
+
long double is_convertible(VALUE value)
|
|
743
|
+
{
|
|
744
|
+
return FromRubyFundamental<long double>::is_convertible(value);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
long double convert(VALUE value)
|
|
748
|
+
{
|
|
749
|
+
return FromRubyFundamental<long double>::convert(value);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
private:
|
|
753
|
+
Arg* arg_ = nullptr;
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
template<>
|
|
757
|
+
class From_Ruby<long double&>
|
|
758
|
+
{
|
|
759
|
+
public:
|
|
760
|
+
using Reference_T = Reference<long double>;
|
|
761
|
+
|
|
762
|
+
From_Ruby() = default;
|
|
763
|
+
|
|
764
|
+
explicit From_Ruby(Arg* arg) : arg_(arg)
|
|
765
|
+
{}
|
|
766
|
+
|
|
767
|
+
long double is_convertible(VALUE value)
|
|
768
|
+
{
|
|
769
|
+
switch (rb_type(value))
|
|
770
|
+
{
|
|
771
|
+
case RUBY_T_DATA:
|
|
772
|
+
{
|
|
773
|
+
if (Data_Type<Reference_T>::is_descendant(value))
|
|
774
|
+
{
|
|
775
|
+
return Convertible::Exact;
|
|
776
|
+
}
|
|
777
|
+
[[fallthrough]];
|
|
778
|
+
}
|
|
779
|
+
default:
|
|
780
|
+
{
|
|
781
|
+
return FromRubyFundamental<long double>::is_convertible(value);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
long double& convert(VALUE value)
|
|
787
|
+
{
|
|
788
|
+
switch (rb_type(value))
|
|
789
|
+
{
|
|
790
|
+
case RUBY_T_DATA:
|
|
791
|
+
{
|
|
792
|
+
if (Data_Type<Reference_T>::is_descendant(value))
|
|
793
|
+
{
|
|
794
|
+
Reference_T* reference = unwrap<Reference_T>(value, Data_Type<Reference_T>::ruby_data_type(), false);
|
|
795
|
+
return reference->get();
|
|
796
|
+
}
|
|
797
|
+
[[fallthrough]];
|
|
798
|
+
}
|
|
799
|
+
default:
|
|
800
|
+
{
|
|
801
|
+
this->reference_ = Reference<long double>(value);
|
|
802
|
+
return this->reference_.get();
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
private:
|
|
808
|
+
Arg* arg_ = nullptr;
|
|
809
|
+
Reference<long double> reference_;
|
|
810
|
+
};
|
|
811
|
+
|
|
732
812
|
// =========== float ============
|
|
733
813
|
template<>
|
|
734
814
|
class From_Ruby<float>
|
|
@@ -1528,31 +1608,15 @@ namespace Rice::detail
|
|
|
1528
1608
|
}
|
|
1529
1609
|
}
|
|
1530
1610
|
|
|
1531
|
-
|
|
1611
|
+
std::nullptr_t convert(VALUE value)
|
|
1532
1612
|
{
|
|
1533
1613
|
if (value == Qnil)
|
|
1534
1614
|
{
|
|
1535
1615
|
return nullptr;
|
|
1536
1616
|
}
|
|
1537
1617
|
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
return (void*)value;
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
switch (rb_type(value))
|
|
1544
|
-
{
|
|
1545
|
-
case RUBY_T_NIL:
|
|
1546
|
-
{
|
|
1547
|
-
return nullptr;
|
|
1548
|
-
break;
|
|
1549
|
-
}
|
|
1550
|
-
default:
|
|
1551
|
-
{
|
|
1552
|
-
throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
|
|
1553
|
-
detail::protect(rb_obj_classname, value), "nil");
|
|
1554
|
-
}
|
|
1555
|
-
}
|
|
1618
|
+
throw Exception(rb_eTypeError, "wrong argument type %s (expected %s)",
|
|
1619
|
+
detail::protect(rb_obj_classname, value), "nil");
|
|
1556
1620
|
}
|
|
1557
1621
|
private:
|
|
1558
1622
|
Arg* arg_ = nullptr;
|
data/rice/detail/to_ruby.ipp
CHANGED
|
@@ -501,6 +501,62 @@ namespace Rice
|
|
|
501
501
|
Arg* arg_ = nullptr;
|
|
502
502
|
};
|
|
503
503
|
|
|
504
|
+
// =========== long double ============
|
|
505
|
+
template<>
|
|
506
|
+
class To_Ruby<long double>
|
|
507
|
+
{
|
|
508
|
+
public:
|
|
509
|
+
To_Ruby() = default;
|
|
510
|
+
|
|
511
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
512
|
+
{}
|
|
513
|
+
|
|
514
|
+
VALUE convert(const long double& native)
|
|
515
|
+
{
|
|
516
|
+
return protect(rb_float_new, native);
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
private:
|
|
520
|
+
Arg* arg_ = nullptr;
|
|
521
|
+
};
|
|
522
|
+
|
|
523
|
+
template<>
|
|
524
|
+
class To_Ruby<long double&>
|
|
525
|
+
{
|
|
526
|
+
public:
|
|
527
|
+
To_Ruby() = default;
|
|
528
|
+
|
|
529
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
530
|
+
{}
|
|
531
|
+
|
|
532
|
+
VALUE convert(const long double& native)
|
|
533
|
+
{
|
|
534
|
+
return protect(rb_float_new, native);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
private:
|
|
538
|
+
Arg* arg_ = nullptr;
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
template<int N>
|
|
542
|
+
class To_Ruby<long double[N]>
|
|
543
|
+
{
|
|
544
|
+
public:
|
|
545
|
+
To_Ruby() = default;
|
|
546
|
+
|
|
547
|
+
explicit To_Ruby(Arg* arg) : arg_(arg)
|
|
548
|
+
{}
|
|
549
|
+
|
|
550
|
+
VALUE convert(long double data[N])
|
|
551
|
+
{
|
|
552
|
+
Buffer<long double> buffer(data, N);
|
|
553
|
+
Data_Object<Buffer<long double>> dataObject(std::move(buffer));
|
|
554
|
+
return dataObject.value();
|
|
555
|
+
}
|
|
556
|
+
private:
|
|
557
|
+
Arg* arg_ = nullptr;
|
|
558
|
+
};
|
|
559
|
+
|
|
504
560
|
// =========== float ============
|
|
505
561
|
template<>
|
|
506
562
|
class To_Ruby<float>
|
data/rice/stl/map.ipp
CHANGED
|
@@ -156,7 +156,7 @@ namespace Rice
|
|
|
156
156
|
}, Arg("key"))
|
|
157
157
|
.define_method("[]=", [](T& map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
|
|
158
158
|
{
|
|
159
|
-
map
|
|
159
|
+
map.insert_or_assign(key, value);
|
|
160
160
|
return value;
|
|
161
161
|
}, Arg("key").keepAlive(), Arg("value").keepAlive());
|
|
162
162
|
|
|
@@ -278,7 +278,7 @@ namespace Rice
|
|
|
278
278
|
// exceptions propogate back to Ruby
|
|
279
279
|
return cpp_protect([&]
|
|
280
280
|
{
|
|
281
|
-
result->
|
|
281
|
+
result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
|
|
282
282
|
return ST_CONTINUE;
|
|
283
283
|
});
|
|
284
284
|
}
|
data/rice/stl/ostream.ipp
CHANGED
|
@@ -59,8 +59,12 @@ namespace Rice::stl
|
|
|
59
59
|
|
|
60
60
|
void define_methods()
|
|
61
61
|
{
|
|
62
|
+
#if __cplusplus >= 202002L
|
|
63
|
+
klass_.define_method<std::string(std::ostringstream::*)() const&>("str", &std::ostringstream::str)
|
|
64
|
+
#else
|
|
62
65
|
klass_.define_method<std::string(std::ostringstream::*)() const>("str", &std::ostringstream::str)
|
|
63
|
-
|
|
66
|
+
#endif
|
|
67
|
+
.define_method("str=", [](std::ostringstream& stream, const std::string& s) { stream.str(s); }, Arg("str"));
|
|
64
68
|
|
|
65
69
|
rb_define_alias(klass_, "to_s", "str");
|
|
66
70
|
}
|
data/rice/stl/pair.ipp
CHANGED
|
@@ -24,8 +24,12 @@ namespace Rice
|
|
|
24
24
|
private:
|
|
25
25
|
void define_constructors()
|
|
26
26
|
{
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
if constexpr (std::is_default_constructible_v<T>)
|
|
28
|
+
{
|
|
29
|
+
klass_.define_constructor(Constructor<T>());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
klass_.define_constructor(Constructor<T, First_Parameter_T, Second_Parameter_T>(), Arg("x").keepAlive(), Arg("y").keepAlive());
|
|
29
33
|
|
|
30
34
|
if constexpr (std::is_copy_constructible_v<First_T> && std::is_copy_constructible_v<Second_T>)
|
|
31
35
|
{
|
data/rice/stl/shared_ptr.ipp
CHANGED
|
@@ -32,7 +32,11 @@ namespace Rice
|
|
|
32
32
|
|
|
33
33
|
if constexpr (detail::is_complete_v<T> && !std::is_void_v<T>)
|
|
34
34
|
{
|
|
35
|
-
|
|
35
|
+
// is_abstract_v requires a complete type, so it must be nested inside the is_complete_v check
|
|
36
|
+
if constexpr (!std::is_abstract_v<T>)
|
|
37
|
+
{
|
|
38
|
+
result.define_constructor(Constructor<SharedPtr_T, typename SharedPtr_T::element_type*>(), Arg("value").takeOwnership());
|
|
39
|
+
}
|
|
36
40
|
}
|
|
37
41
|
|
|
38
42
|
// Forward methods to wrapped T
|
|
@@ -87,7 +91,7 @@ namespace Rice::detail
|
|
|
87
91
|
}
|
|
88
92
|
else if (rb_typeddata_inherited_p(this->inner_rb_data_type_, requestedType))
|
|
89
93
|
{
|
|
90
|
-
return this->data_.get();
|
|
94
|
+
return (void*)this->data_.get();
|
|
91
95
|
}
|
|
92
96
|
else
|
|
93
97
|
{
|
data/rice/stl/unique_ptr.ipp
CHANGED
data/rice/stl/unordered_map.ipp
CHANGED
|
@@ -156,7 +156,7 @@ namespace Rice
|
|
|
156
156
|
}, Arg("key"))
|
|
157
157
|
.define_method("[]=", [](T& unordered_map, Key_T key, Mapped_Parameter_T value) -> Mapped_T
|
|
158
158
|
{
|
|
159
|
-
unordered_map
|
|
159
|
+
unordered_map.insert_or_assign(key, value);
|
|
160
160
|
return value;
|
|
161
161
|
}, Arg("key").keepAlive(), Arg("value").keepAlive());
|
|
162
162
|
|
|
@@ -278,7 +278,7 @@ namespace Rice
|
|
|
278
278
|
// exceptions propogate back to Ruby
|
|
279
279
|
return cpp_protect([&]
|
|
280
280
|
{
|
|
281
|
-
result->
|
|
281
|
+
result->insert_or_assign(From_Ruby<T>().convert(key), From_Ruby<U>().convert(value));
|
|
282
282
|
return ST_CONTINUE;
|
|
283
283
|
});
|
|
284
284
|
}
|
|
@@ -102,6 +102,27 @@ namespace Rice::detail
|
|
|
102
102
|
{
|
|
103
103
|
};
|
|
104
104
|
|
|
105
|
+
// ref-qualified member Functions on C++ classes (C++20 uses these for std library types)
|
|
106
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
107
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) &> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
108
|
+
{
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
112
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const&> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
113
|
+
{
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
117
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) & noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
118
|
+
{
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
template<typename Return_T, typename Class_T, typename...Parameter_Ts>
|
|
122
|
+
struct function_traits<Return_T(Class_T::*)(Parameter_Ts...) const& noexcept> : public function_traits<Return_T(Class_T*, Parameter_Ts...)>
|
|
123
|
+
{
|
|
124
|
+
};
|
|
125
|
+
|
|
105
126
|
/*// Functors and lambdas
|
|
106
127
|
template<class Function_T>
|
|
107
128
|
struct function_traits<Function_T&> : public function_traits<Function_T>
|
data/test/test_Attribute.cpp
CHANGED
|
@@ -590,4 +590,35 @@ TESTCASE(KeepAlive)
|
|
|
590
590
|
// This should work because keepAlive prevents MyClass2 from being GC'd
|
|
591
591
|
ASSERT_NOT_EQUAL(nullptr, dataStruct->myClass2);
|
|
592
592
|
ASSERT_EQUAL(43, dataStruct->myClass2->value);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
namespace
|
|
596
|
+
{
|
|
597
|
+
struct FuncPtrStruct
|
|
598
|
+
{
|
|
599
|
+
int (*callback)(int) = nullptr;
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
TESTCASE(function_pointer_attribute)
|
|
604
|
+
{
|
|
605
|
+
Module m = define_module("Testing");
|
|
606
|
+
|
|
607
|
+
Class c = define_class<FuncPtrStruct>("FuncPtrStruct")
|
|
608
|
+
.define_constructor(Constructor<FuncPtrStruct>())
|
|
609
|
+
.define_attr("callback", &FuncPtrStruct::callback);
|
|
610
|
+
|
|
611
|
+
Object o = c.call("new");
|
|
612
|
+
|
|
613
|
+
// Set the callback via Ruby using a lambda
|
|
614
|
+
std::string code = R"(struct = FuncPtrStruct.new
|
|
615
|
+
struct.callback = lambda { |x| x * 2 }
|
|
616
|
+
struct)";
|
|
617
|
+
|
|
618
|
+
Data_Object<FuncPtrStruct> funcPtrStruct = m.module_eval(code);
|
|
619
|
+
|
|
620
|
+
// Invoke the callback from C++ to verify it works
|
|
621
|
+
ASSERT_NOT_EQUAL(nullptr, funcPtrStruct->callback);
|
|
622
|
+
int result = funcPtrStruct->callback(5);
|
|
623
|
+
ASSERT_EQUAL(10, result);
|
|
593
624
|
}
|
data/test/test_Callback.cpp
CHANGED
|
@@ -55,10 +55,8 @@ TESTCASE(LambdaCallBack)
|
|
|
55
55
|
ASSERT((globalCallback != nullptr));
|
|
56
56
|
|
|
57
57
|
int ref = 4;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
char* result = triggerCallback(1, 2, true, "hello", ref);
|
|
61
|
-
#pragma GCC diagnostic pop
|
|
58
|
+
char hello[] = "hello";
|
|
59
|
+
char* result = triggerCallback(1, 2, true, hello, ref);
|
|
62
60
|
ASSERT_EQUAL("1 - 2.0 - true - hello - 4", result);
|
|
63
61
|
}
|
|
64
62
|
|
data/test/test_From_Ruby.cpp
CHANGED
|
@@ -615,3 +615,17 @@ TESTCASE(void_pointer_array)
|
|
|
615
615
|
Object result = m.module_eval(code);
|
|
616
616
|
ASSERT_EQUAL("[4, 3, 2, 1]", detail::From_Ruby<std::string>().convert(result.value()));
|
|
617
617
|
}
|
|
618
|
+
|
|
619
|
+
TESTCASE(nullptr_t)
|
|
620
|
+
{
|
|
621
|
+
detail::From_Ruby<std::nullptr_t> fromRuby;
|
|
622
|
+
|
|
623
|
+
std::nullptr_t result = fromRuby.convert(Qnil);
|
|
624
|
+
ASSERT_EQUAL(nullptr, result);
|
|
625
|
+
|
|
626
|
+
ASSERT_EXCEPTION_CHECK(
|
|
627
|
+
Exception,
|
|
628
|
+
fromRuby.convert(rb_str_new2("not nil")),
|
|
629
|
+
ASSERT_EQUAL("wrong argument type String (expected nil)", ex.what())
|
|
630
|
+
);
|
|
631
|
+
}
|
data/test/test_Stl_Map.cpp
CHANGED
|
@@ -365,6 +365,62 @@ TESTCASE(NotPrintable)
|
|
|
365
365
|
ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
+
namespace
|
|
369
|
+
{
|
|
370
|
+
// Type with no default constructor - verifies insert_or_assign works in []=
|
|
371
|
+
class NoDefaultMap
|
|
372
|
+
{
|
|
373
|
+
public:
|
|
374
|
+
NoDefaultMap(int value) : value_(value) {}
|
|
375
|
+
int value() const { return value_; }
|
|
376
|
+
|
|
377
|
+
bool operator==(const NoDefaultMap& other) const
|
|
378
|
+
{
|
|
379
|
+
return this->value_ == other.value_;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private:
|
|
383
|
+
int value_;
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
TESTCASE(NoDefaultConstructor)
|
|
388
|
+
{
|
|
389
|
+
define_class<NoDefaultMap>("NoDefaultMap").
|
|
390
|
+
define_constructor(Constructor<NoDefaultMap, int>(), Arg("value")).
|
|
391
|
+
define_method("value", &NoDefaultMap::value);
|
|
392
|
+
|
|
393
|
+
Class c = define_map<std::string, NoDefaultMap>("NoDefaultMap_Map");
|
|
394
|
+
|
|
395
|
+
Object map = c.call("new");
|
|
396
|
+
|
|
397
|
+
// Test []= (insert_or_assign) with non-default-constructible value
|
|
398
|
+
map.call("[]=", "one", NoDefaultMap(1));
|
|
399
|
+
map.call("[]=", "two", NoDefaultMap(2));
|
|
400
|
+
|
|
401
|
+
Object result = map.call("size");
|
|
402
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
|
|
403
|
+
|
|
404
|
+
// Test [] access
|
|
405
|
+
result = map.call("[]", "one");
|
|
406
|
+
ASSERT_EQUAL(1, detail::From_Ruby<int>().convert(result.call("value")));
|
|
407
|
+
|
|
408
|
+
// Test update existing key
|
|
409
|
+
map.call("[]=", "one", NoDefaultMap(10));
|
|
410
|
+
result = map.call("[]", "one");
|
|
411
|
+
ASSERT_EQUAL(10, detail::From_Ruby<int>().convert(result.call("value")));
|
|
412
|
+
|
|
413
|
+
result = map.call("size");
|
|
414
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
|
|
415
|
+
|
|
416
|
+
// Test delete
|
|
417
|
+
result = map.call("delete", "two");
|
|
418
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int>().convert(result.call("value")));
|
|
419
|
+
|
|
420
|
+
result = map.call("size");
|
|
421
|
+
ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
|
|
422
|
+
}
|
|
423
|
+
|
|
368
424
|
namespace
|
|
369
425
|
{
|
|
370
426
|
class Comparable
|
data/test/test_Stl_Pair.cpp
CHANGED
|
@@ -144,6 +144,38 @@ TESTCASE(AutoRegister)
|
|
|
144
144
|
ASSERT(result.is_instance_of(pair.class_of()));
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
namespace
|
|
148
|
+
{
|
|
149
|
+
// Type with no default constructor - like cv::detail::tracking::tbm::Track
|
|
150
|
+
class NoDefault
|
|
151
|
+
{
|
|
152
|
+
public:
|
|
153
|
+
NoDefault(int value) : value_(value) {}
|
|
154
|
+
int value() const { return value_; }
|
|
155
|
+
private:
|
|
156
|
+
int value_;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
TESTCASE(PairNoDefaultConstructor)
|
|
161
|
+
{
|
|
162
|
+
define_class<NoDefault>("NoDefault").
|
|
163
|
+
define_constructor(Constructor<NoDefault, int>(), Arg("value")).
|
|
164
|
+
define_method("value", &NoDefault::value);
|
|
165
|
+
|
|
166
|
+
// This should compile and work even though NoDefault has no default constructor.
|
|
167
|
+
// The pair's default constructor should be skipped, but the two-argument constructor should work.
|
|
168
|
+
Class c = define_pair<const int, NoDefault>("IntNoDefaultPair");
|
|
169
|
+
|
|
170
|
+
Object pair = c.call("new", 42, NoDefault(7));
|
|
171
|
+
|
|
172
|
+
Object result = pair.call("first");
|
|
173
|
+
ASSERT_EQUAL(42, detail::From_Ruby<int>().convert(result));
|
|
174
|
+
|
|
175
|
+
result = pair.call("second");
|
|
176
|
+
ASSERT_EQUAL(7, detail::From_Ruby<int>().convert(result.call("value")));
|
|
177
|
+
}
|
|
178
|
+
|
|
147
179
|
namespace
|
|
148
180
|
{
|
|
149
181
|
struct SomeStruct
|
data/test/test_Stl_SharedPtr.cpp
CHANGED
|
@@ -609,6 +609,99 @@ TESTCASE(InheritedForwarding)
|
|
|
609
609
|
ASSERT_EQUAL(456, detail::From_Ruby<int>().convert(result));
|
|
610
610
|
}
|
|
611
611
|
|
|
612
|
+
// --- shared_ptr<const T> tests ---
|
|
613
|
+
// When shared_ptr wraps a const T, the Wrapper::get() method must handle
|
|
614
|
+
// the const-to-void* conversion. Without a cast, data_.get() returns
|
|
615
|
+
// const T* which cannot implicitly convert to void*.
|
|
616
|
+
namespace
|
|
617
|
+
{
|
|
618
|
+
class ConstTarget
|
|
619
|
+
{
|
|
620
|
+
public:
|
|
621
|
+
int value;
|
|
622
|
+
|
|
623
|
+
ConstTarget() : value(0) {}
|
|
624
|
+
ConstTarget(int v) : value(v) {}
|
|
625
|
+
|
|
626
|
+
int getValue() const { return value; }
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
std::shared_ptr<const ConstTarget> createConstTarget(int v)
|
|
630
|
+
{
|
|
631
|
+
return std::make_shared<const ConstTarget>(v);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
int extractConstTargetValue(std::shared_ptr<const ConstTarget> ptr)
|
|
635
|
+
{
|
|
636
|
+
return ptr->getValue();
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
TESTCASE(SharedPtrConstT)
|
|
641
|
+
{
|
|
642
|
+
define_class<ConstTarget>("ConstTarget").
|
|
643
|
+
define_constructor(Constructor<ConstTarget, int>(),
|
|
644
|
+
Arg("v")).
|
|
645
|
+
define_method("get_value", &ConstTarget::getValue);
|
|
646
|
+
|
|
647
|
+
Module m = define_module("SharedPtrConstTest").
|
|
648
|
+
define_module_function("create_const_target", &createConstTarget).
|
|
649
|
+
define_module_function("extract_const_target_value", &extractConstTargetValue);
|
|
650
|
+
|
|
651
|
+
// Test that shared_ptr<const T> can be unwrapped to access the inner T
|
|
652
|
+
std::string code = R"(ptr = create_const_target(42)
|
|
653
|
+
extract_const_target_value(ptr))";
|
|
654
|
+
|
|
655
|
+
Object result = m.instance_eval(code);
|
|
656
|
+
ASSERT_EQUAL(42, detail::From_Ruby<int>().convert(result.value()));
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// Abstract class with non-virtual destructor - like cv::cudacodec::NVSurfaceToColorConverter
|
|
660
|
+
namespace
|
|
661
|
+
{
|
|
662
|
+
class AbstractClass
|
|
663
|
+
{
|
|
664
|
+
public:
|
|
665
|
+
virtual bool compute(int value) const = 0;
|
|
666
|
+
~AbstractClass() {} // non-virtual destructor
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
class ConcreteImpl : public AbstractClass
|
|
670
|
+
{
|
|
671
|
+
public:
|
|
672
|
+
bool compute(int value) const override { return value > 0; }
|
|
673
|
+
};
|
|
674
|
+
|
|
675
|
+
std::shared_ptr<AbstractClass> createAbstract()
|
|
676
|
+
{
|
|
677
|
+
return std::make_shared<ConcreteImpl>();
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
bool useAbstract(std::shared_ptr<AbstractClass> ptr, int value)
|
|
681
|
+
{
|
|
682
|
+
return ptr->compute(value);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
TESTCASE(SharedPtrAbstractT)
|
|
687
|
+
{
|
|
688
|
+
// shared_ptr<T> where T is abstract should NOT define a constructor taking T*,
|
|
689
|
+
// because deleting through a non-virtual destructor on an abstract class is UB.
|
|
690
|
+
define_class<AbstractClass>("AbstractClass").
|
|
691
|
+
define_method("compute", &AbstractClass::compute,
|
|
692
|
+
Arg("value"));
|
|
693
|
+
|
|
694
|
+
Module m = define_module("SharedPtrAbstractTest").
|
|
695
|
+
define_module_function("create_abstract", &createAbstract).
|
|
696
|
+
define_module_function("use_abstract", &useAbstract);
|
|
697
|
+
|
|
698
|
+
std::string code = R"(ptr = create_abstract
|
|
699
|
+
use_abstract(ptr, 5))";
|
|
700
|
+
|
|
701
|
+
Object result = m.instance_eval(code);
|
|
702
|
+
ASSERT_EQUAL(Qtrue, result.value());
|
|
703
|
+
}
|
|
704
|
+
|
|
612
705
|
// Forward declaration only - IncompleteClass is never defined
|
|
613
706
|
class IncompleteClass;
|
|
614
707
|
|
data/test/test_Stl_UniquePtr.cpp
CHANGED
|
@@ -252,4 +252,51 @@ TESTCASE(Release)
|
|
|
252
252
|
Exception,
|
|
253
253
|
m.module_eval(code),
|
|
254
254
|
ASSERT(std::string(ex.what()).find("undefined method") == 0));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- unique_ptr<const T> tests ---
|
|
258
|
+
// When unique_ptr wraps a const T, the Wrapper::get() method must handle
|
|
259
|
+
// the const-to-void* conversion. Without a cast, data_.get() returns
|
|
260
|
+
// const T* which cannot implicitly convert to void*.
|
|
261
|
+
namespace
|
|
262
|
+
{
|
|
263
|
+
class ConstTarget
|
|
264
|
+
{
|
|
265
|
+
public:
|
|
266
|
+
int value;
|
|
267
|
+
|
|
268
|
+
ConstTarget() : value(0) {}
|
|
269
|
+
ConstTarget(int v) : value(v) {}
|
|
270
|
+
|
|
271
|
+
int getValue() const { return value; }
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
std::unique_ptr<const ConstTarget> createConstTarget(int v)
|
|
275
|
+
{
|
|
276
|
+
return std::make_unique<const ConstTarget>(v);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
int extractConstTargetValue(const std::unique_ptr<const ConstTarget>& ptr)
|
|
280
|
+
{
|
|
281
|
+
return ptr->getValue();
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
TESTCASE(UniquePtrConstT)
|
|
286
|
+
{
|
|
287
|
+
define_class<ConstTarget>("ConstTarget").
|
|
288
|
+
define_constructor(Constructor<ConstTarget, int>(),
|
|
289
|
+
Arg("v")).
|
|
290
|
+
define_method("get_value", &ConstTarget::getValue);
|
|
291
|
+
|
|
292
|
+
Module m = define_module("UniquePtrConstTest").
|
|
293
|
+
define_module_function("create_const_target", &createConstTarget).
|
|
294
|
+
define_module_function("extract_const_target_value", &extractConstTargetValue);
|
|
295
|
+
|
|
296
|
+
// Test that unique_ptr<const T> can be unwrapped to access the inner T
|
|
297
|
+
std::string code = R"(ptr = create_const_target(42)
|
|
298
|
+
extract_const_target_value(ptr))";
|
|
299
|
+
|
|
300
|
+
Object result = m.instance_eval(code);
|
|
301
|
+
ASSERT_EQUAL(42, detail::From_Ruby<int>().convert(result.value()));
|
|
255
302
|
}
|
|
@@ -357,6 +357,62 @@ TESTCASE(NotPrintable)
|
|
|
357
357
|
ASSERT_EQUAL("[Not printable]", detail::From_Ruby<std::string>().convert(result));
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
+
namespace
|
|
361
|
+
{
|
|
362
|
+
// Type with no default constructor - verifies insert_or_assign works in []=
|
|
363
|
+
class NoDefaultUnorderedMap
|
|
364
|
+
{
|
|
365
|
+
public:
|
|
366
|
+
NoDefaultUnorderedMap(int value) : value_(value) {}
|
|
367
|
+
int value() const { return value_; }
|
|
368
|
+
|
|
369
|
+
bool operator==(const NoDefaultUnorderedMap& other) const
|
|
370
|
+
{
|
|
371
|
+
return this->value_ == other.value_;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private:
|
|
375
|
+
int value_;
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
TESTCASE(NoDefaultConstructor)
|
|
380
|
+
{
|
|
381
|
+
define_class<NoDefaultUnorderedMap>("NoDefaultUnorderedMap").
|
|
382
|
+
define_constructor(Constructor<NoDefaultUnorderedMap, int>(), Arg("value")).
|
|
383
|
+
define_method("value", &NoDefaultUnorderedMap::value);
|
|
384
|
+
|
|
385
|
+
Class c = define_unordered_map<std::string, NoDefaultUnorderedMap>("NoDefaultUnorderedMap_Map");
|
|
386
|
+
|
|
387
|
+
Object map = c.call("new");
|
|
388
|
+
|
|
389
|
+
// Test []= (insert_or_assign) with non-default-constructible value
|
|
390
|
+
map.call("[]=", "one", NoDefaultUnorderedMap(1));
|
|
391
|
+
map.call("[]=", "two", NoDefaultUnorderedMap(2));
|
|
392
|
+
|
|
393
|
+
Object result = map.call("size");
|
|
394
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
|
|
395
|
+
|
|
396
|
+
// Test [] access
|
|
397
|
+
result = map.call("[]", "one");
|
|
398
|
+
ASSERT_EQUAL(1, detail::From_Ruby<int>().convert(result.call("value")));
|
|
399
|
+
|
|
400
|
+
// Test update existing key
|
|
401
|
+
map.call("[]=", "one", NoDefaultUnorderedMap(10));
|
|
402
|
+
result = map.call("[]", "one");
|
|
403
|
+
ASSERT_EQUAL(10, detail::From_Ruby<int>().convert(result.call("value")));
|
|
404
|
+
|
|
405
|
+
result = map.call("size");
|
|
406
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int32_t>().convert(result));
|
|
407
|
+
|
|
408
|
+
// Test delete
|
|
409
|
+
result = map.call("delete", "two");
|
|
410
|
+
ASSERT_EQUAL(2, detail::From_Ruby<int>().convert(result.call("value")));
|
|
411
|
+
|
|
412
|
+
result = map.call("size");
|
|
413
|
+
ASSERT_EQUAL(1, detail::From_Ruby<int32_t>().convert(result));
|
|
414
|
+
}
|
|
415
|
+
|
|
360
416
|
namespace
|
|
361
417
|
{
|
|
362
418
|
class Comparable
|