6
6
7
7
#include " libpy/any.h"
8
8
#include " libpy/char_sequence.h"
9
- #include " libpy/dense_hash_map.h"
10
9
#include " libpy/itertools.h"
11
10
#include " libpy/meta.h"
12
11
#include " libpy/numpy_utils.h"
@@ -21,162 +20,26 @@ using namespace py::cs::literals;
21
20
22
21
class to_object : public with_python_interpreter {};
23
22
24
- template <typename T>
25
- std::array<T, 3 > examples ();
26
-
27
- template <>
28
- std::array<std::int64_t , 3 > examples () {
29
- return {-200 , 0 , 1000 };
30
- }
31
-
32
- template <>
33
- std::array<std::string, 3 > examples () {
34
- return {" foo" , " " , " arglebargle" };
35
- }
36
-
37
- template <>
38
- std::array<std::array<char , 3 >, 3 > examples () {
39
- std::array<char , 3 > foo{' f' , ' o' , ' o' };
40
- std::array<char , 3 > bar{' b' , ' a' , ' r' };
41
- std::array<char , 3 > baz{' b' , ' a' , ' z' };
42
- return {foo, bar, baz};
43
- }
44
-
45
- template <>
46
- std::array<bool , 3 > examples () {
47
- return {true , false , true };
48
- }
49
-
50
- template <>
51
- std::array<double , 3 > examples () {
52
- return {-1.0 , -0.0 , 100.0 };
53
- }
54
-
55
- template <>
56
- std::array<py::owned_ref<>, 3 > examples () {
57
- Py_INCREF (Py_True);
58
- Py_INCREF (Py_False);
59
- Py_INCREF (Py_None);
60
- return {py::owned_ref<>(Py_True),
61
- py::owned_ref<>(Py_False),
62
- py::owned_ref<>(Py_None)};
63
- }
64
-
65
- template <typename M>
66
- void test_map_to_object_impl (M m) {
67
-
68
- // Fill the map with some example values.
69
- auto it = py::zip (examples<typename M::key_type>(),
70
- examples<typename M::mapped_type>());
71
- for (auto [key, value] : it) {
72
- m[key] = value;
73
- }
74
-
75
- auto check_python_map = [&](py::owned_ref<PyObject> ob) {
76
- ASSERT_TRUE (ob) << " to_object should not return null" ;
77
- EXPECT_TRUE (PyDict_Check (ob.get ()));
78
-
79
- // Python map should be the same length as C++ map.
80
- Py_ssize_t len = PyDict_Size (ob.get ());
81
- EXPECT_EQ (std::size_t (len), m.size ())
82
- << " Python dict length should match C++ map length." ;
83
-
84
- // Key/Value pairs in the python map should match the result of calling
85
- // to_object on each key/value pair in the C++ map.
86
- for (auto & [cxx_key, cxx_value] : m) {
87
- auto py_key = py::to_object (cxx_key);
88
- auto py_value = py::to_object (cxx_value);
89
-
90
- py::borrowed_ref result = PyDict_GetItem (ob.get (), py_key.get ());
91
- ASSERT_TRUE (result) << " Key should have been in the map" ;
92
-
93
- bool values_equal =
94
- PyObject_RichCompareBool (py_value.get (), result.get (), Py_EQ);
95
- EXPECT_EQ (values_equal, 1 ) << " Dict values were not equal" ;
96
- }
97
- };
98
-
99
- // Check to_object with value, const value, and rvalue reference.
100
-
101
- py::owned_ref<PyObject> result = py::to_object (m);
102
- check_python_map (result);
103
-
104
- const M& const_ref = m;
105
- py::owned_ref<PyObject> constref_result = py::to_object (const_ref);
106
- check_python_map (constref_result);
107
-
108
- M copy = m; // Make a copy before moving b/c the lambda above uses ``m``.
109
- py::owned_ref<PyObject> rvalueref_result = py::to_object (std::move (copy));
110
- check_python_map (rvalueref_result);
111
- }
112
-
113
23
TEST_F (to_object, map_to_object) {
114
- // NOTE: This test takes a long time to compile (about a .5s per entry in this
115
- // tuple). This is just enough coverage to test all three of our hash table types,
116
- // and a few important key/value types.
117
- auto maps = std::make_tuple (py::dense_hash_map<std::string, py::owned_ref<PyObject>>(
118
- " missing_value" s),
119
- py::sparse_hash_map<std::int64_t , std::array<char , 3 >>(),
120
- std::unordered_map<std::string, bool >());
121
-
122
- // Call test_map_to_object_impl on each entry in ``maps``.
123
- std::apply ([&](auto ... map) { (test_map_to_object_impl (map), ...); }, maps);
124
- }
125
-
126
- template <typename V>
127
- void test_sequence_to_object_impl (V v) {
128
- auto check_python_list = [&](py::owned_ref<PyObject> ob) {
129
- ASSERT_TRUE (ob) << " to_object should not return null" ;
130
- EXPECT_EQ (PyList_Check (ob.get ()), 1 ) << " ob should be a list" ;
131
-
132
- Py_ssize_t len = PyList_GET_SIZE (ob.get ());
133
- EXPECT_EQ (std::size_t (len), v.size ())
134
- << " Python list length should match C++ vector length." ;
135
-
136
- // Values in Python list should be the result of calling to_object on each entry
137
- // in the C++ vector.
138
- for (auto [i, cxx_value] : py::enumerate (v)) {
139
- auto py_value = py::to_object (cxx_value);
140
-
141
- py::borrowed_ref result = PyList_GetItem (ob.get (), i);
142
- ASSERT_TRUE (result) << " Should have had a value at index " << i;
143
-
144
- bool values_equal =
145
- PyObject_RichCompareBool (py_value.get (), result.get (), Py_EQ);
146
- EXPECT_EQ (values_equal, 1 )
147
- << " List values at index " << i << " were not equal" ;
148
- }
149
- };
150
-
151
- // Check to_object with value, const value, and rvalue reference.
152
-
153
- py::owned_ref<PyObject> result = py::to_object (v);
154
- check_python_list (result);
155
-
156
- const V& const_ref = v;
157
- py::owned_ref<PyObject> constref_result = py::to_object (const_ref);
158
- check_python_list (constref_result);
159
-
160
- V copy = v; // Make a copy before moving b/c the lambda above uses ``v``.
161
- py::owned_ref<PyObject> rvalueref_result = py::to_object (std::move (copy));
162
- check_python_list (rvalueref_result);
24
+ auto map = std::unordered_map<std::string, bool >();
25
+ py_test::test_map_to_object_impl (map);
163
26
}
164
27
165
28
TEST_F (to_object, vector_to_object) {
166
29
auto to_vec = [](const auto & arr) { return std::vector (arr.begin (), arr.end ()); };
167
- auto vectors = std::make_tuple (to_vec (examples<std::string>()),
168
- to_vec (examples<double >()),
169
- to_vec (examples<py::owned_ref<>>()));
30
+ auto vectors = std::make_tuple (to_vec (py_test:: examples<std::string>()),
31
+ to_vec (py_test:: examples<double >()),
32
+ to_vec (py_test:: examples<py::owned_ref<>>()));
170
33
// Call test_sequence_to_object_impl on each entry in `vectors`.
171
- std::apply ([&](auto ... vec) { (test_sequence_to_object_impl (vec), ...); }, vectors);
34
+ std::apply ([&](auto ... vec) { (py_test:: test_sequence_to_object_impl (vec), ...); }, vectors);
172
35
}
173
36
174
37
TEST_F (to_object, array_to_object) {
175
- auto arrays = std::make_tuple (examples<std::string>(),
176
- examples<double >(),
177
- examples<py::owned_ref<>>());
38
+ auto arrays = std::make_tuple (py_test:: examples<std::string>(),
39
+ py_test:: examples<double >(),
40
+ py_test:: examples<py::owned_ref<>>());
178
41
// Call test_sequence_to_object_impl on each entry in `arrays`.
179
- std::apply ([&](auto ... arr) { (test_sequence_to_object_impl (arr), ...); }, arrays);
42
+ std::apply ([&](auto ... arr) { (py_test:: test_sequence_to_object_impl (arr), ...); }, arrays);
180
43
}
181
44
182
45
template <typename R, typename T>
0 commit comments