test_stl.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. tests/test_stl.cpp -- STL type casters
  3. Copyright (c) 2017 Wenzel Jakob <[email protected]>
  4. All rights reserved. Use of this source code is governed by a
  5. BSD-style license that can be found in the LICENSE file.
  6. */
  7. #include "pybind11_tests.h"
  8. #include "constructor_stats.h"
  9. #include <pybind11/stl.h>
  10. // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
  11. #if PYBIND11_HAS_VARIANT
  12. using std::variant;
  13. #elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
  14. # include <boost/variant.hpp>
  15. # define PYBIND11_HAS_VARIANT 1
  16. using boost::variant;
  17. namespace pybind11 { namespace detail {
  18. template <typename... Ts>
  19. struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
  20. template <>
  21. struct visit_helper<boost::variant> {
  22. template <typename... Args>
  23. static auto call(Args &&...args) -> decltype(boost::apply_visitor(args...)) {
  24. return boost::apply_visitor(args...);
  25. }
  26. };
  27. }} // namespace pybind11::detail
  28. #endif
  29. /// Issue #528: templated constructor
  30. struct TplCtorClass {
  31. template <typename T> TplCtorClass(const T &) { }
  32. bool operator==(const TplCtorClass &) const { return true; }
  33. };
  34. namespace std {
  35. template <>
  36. struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } };
  37. }
  38. TEST_SUBMODULE(stl, m) {
  39. // test_vector
  40. m.def("cast_vector", []() { return std::vector<int>{1}; });
  41. m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
  42. // `std::vector<bool>` is special because it returns proxy objects instead of references
  43. m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; });
  44. m.def("load_bool_vector", [](const std::vector<bool> &v) {
  45. return v.at(0) == true && v.at(1) == false;
  46. });
  47. // Unnumbered regression (caused by #936): pointers to stl containers aren't castable
  48. static std::vector<RValueCaster> lvv{2};
  49. m.def("cast_ptr_vector", []() { return &lvv; });
  50. // test_array
  51. m.def("cast_array", []() { return std::array<int, 2> {{1 , 2}}; });
  52. m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
  53. // test_valarray
  54. m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
  55. m.def("load_valarray", [](const std::valarray<int>& v) {
  56. return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
  57. });
  58. // test_map
  59. m.def("cast_map", []() { return std::map<std::string, std::string>{{"key", "value"}}; });
  60. m.def("load_map", [](const std::map<std::string, std::string> &map) {
  61. return map.at("key") == "value" && map.at("key2") == "value2";
  62. });
  63. // test_set
  64. m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
  65. m.def("load_set", [](const std::set<std::string> &set) {
  66. return set.count("key1") && set.count("key2") && set.count("key3");
  67. });
  68. // test_recursive_casting
  69. m.def("cast_rv_vector", []() { return std::vector<RValueCaster>{2}; });
  70. m.def("cast_rv_array", []() { return std::array<RValueCaster, 3>(); });
  71. // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`),
  72. // casters don't typically do anything with that, which means they fall to the `const Type &`
  73. // caster.
  74. m.def("cast_rv_map", []() { return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}}; });
  75. m.def("cast_rv_nested", []() {
  76. std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v;
  77. v.emplace_back(); // add an array
  78. v.back()[0].emplace_back(); // add a map to the array
  79. v.back()[0].back().emplace("b", RValueCaster{});
  80. v.back()[0].back().emplace("c", RValueCaster{});
  81. v.back()[1].emplace_back(); // add a map to the array
  82. v.back()[1].back().emplace("a", RValueCaster{});
  83. return v;
  84. });
  85. static std::array<RValueCaster, 2> lva;
  86. static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}};
  87. static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>> lvn;
  88. lvn["a"].emplace_back(); // add a list
  89. lvn["a"].back().emplace_back(); // add an array
  90. lvn["a"].emplace_back(); // another list
  91. lvn["a"].back().emplace_back(); // add an array
  92. lvn["b"].emplace_back(); // add a list
  93. lvn["b"].back().emplace_back(); // add an array
  94. lvn["b"].back().emplace_back(); // add another array
  95. m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; });
  96. m.def("cast_lv_array", []() -> const decltype(lva) & { return lva; });
  97. m.def("cast_lv_map", []() -> const decltype(lvm) & { return lvm; });
  98. m.def("cast_lv_nested", []() -> const decltype(lvn) & { return lvn; });
  99. // #853:
  100. m.def("cast_unique_ptr_vector", []() {
  101. std::vector<std::unique_ptr<UserType>> v;
  102. v.emplace_back(new UserType{7});
  103. v.emplace_back(new UserType{42});
  104. return v;
  105. });
  106. // test_move_out_container
  107. struct MoveOutContainer {
  108. struct Value { int value; };
  109. std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
  110. };
  111. py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
  112. .def_readonly("value", &MoveOutContainer::Value::value);
  113. py::class_<MoveOutContainer>(m, "MoveOutContainer")
  114. .def(py::init<>())
  115. .def_property_readonly("move_list", &MoveOutContainer::move_list);
  116. // Class that can be move- and copy-constructed, but not assigned
  117. struct NoAssign {
  118. int value;
  119. explicit NoAssign(int value = 0) : value(value) { }
  120. NoAssign(const NoAssign &) = default;
  121. NoAssign(NoAssign &&) = default;
  122. NoAssign &operator=(const NoAssign &) = delete;
  123. NoAssign &operator=(NoAssign &&) = delete;
  124. };
  125. py::class_<NoAssign>(m, "NoAssign", "Class with no C++ assignment operators")
  126. .def(py::init<>())
  127. .def(py::init<int>());
  128. #ifdef PYBIND11_HAS_OPTIONAL
  129. // test_optional
  130. m.attr("has_optional") = true;
  131. using opt_int = std::optional<int>;
  132. using opt_no_assign = std::optional<NoAssign>;
  133. m.def("double_or_zero", [](const opt_int& x) -> int {
  134. return x.value_or(0) * 2;
  135. });
  136. m.def("half_or_none", [](int x) -> opt_int {
  137. return x ? opt_int(x / 2) : opt_int();
  138. });
  139. m.def("test_nullopt", [](opt_int x) {
  140. return x.value_or(42);
  141. }, py::arg_v("x", std::nullopt, "None"));
  142. m.def("test_no_assign", [](const opt_no_assign &x) {
  143. return x ? x->value : 42;
  144. }, py::arg_v("x", std::nullopt, "None"));
  145. m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
  146. m.def("nodefer_none_optional", [](py::none) { return false; });
  147. #endif
  148. #ifdef PYBIND11_HAS_EXP_OPTIONAL
  149. // test_exp_optional
  150. m.attr("has_exp_optional") = true;
  151. using exp_opt_int = std::experimental::optional<int>;
  152. using exp_opt_no_assign = std::experimental::optional<NoAssign>;
  153. m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int {
  154. return x.value_or(0) * 2;
  155. });
  156. m.def("half_or_none_exp", [](int x) -> exp_opt_int {
  157. return x ? exp_opt_int(x / 2) : exp_opt_int();
  158. });
  159. m.def("test_nullopt_exp", [](exp_opt_int x) {
  160. return x.value_or(42);
  161. }, py::arg_v("x", std::experimental::nullopt, "None"));
  162. m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) {
  163. return x ? x->value : 42;
  164. }, py::arg_v("x", std::experimental::nullopt, "None"));
  165. #endif
  166. #ifdef PYBIND11_HAS_VARIANT
  167. static_assert(std::is_same<py::detail::variant_caster_visitor::result_type, py::handle>::value,
  168. "visitor::result_type is required by boost::variant in C++11 mode");
  169. struct visitor {
  170. using result_type = const char *;
  171. result_type operator()(int) { return "int"; }
  172. result_type operator()(std::string) { return "std::string"; }
  173. result_type operator()(double) { return "double"; }
  174. result_type operator()(std::nullptr_t) { return "std::nullptr_t"; }
  175. };
  176. // test_variant
  177. m.def("load_variant", [](variant<int, std::string, double, std::nullptr_t> v) {
  178. return py::detail::visit_helper<variant>::call(visitor(), v);
  179. });
  180. m.def("load_variant_2pass", [](variant<double, int> v) {
  181. return py::detail::visit_helper<variant>::call(visitor(), v);
  182. });
  183. m.def("cast_variant", []() {
  184. using V = variant<int, std::string>;
  185. return py::make_tuple(V(5), V("Hello"));
  186. });
  187. #endif
  188. // #528: templated constructor
  189. // (no python tests: the test here is that this compiles)
  190. m.def("tpl_ctor_vector", [](std::vector<TplCtorClass> &) {});
  191. m.def("tpl_ctor_map", [](std::unordered_map<TplCtorClass, TplCtorClass> &) {});
  192. m.def("tpl_ctor_set", [](std::unordered_set<TplCtorClass> &) {});
  193. #if defined(PYBIND11_HAS_OPTIONAL)
  194. m.def("tpl_constr_optional", [](std::optional<TplCtorClass> &) {});
  195. #elif defined(PYBIND11_HAS_EXP_OPTIONAL)
  196. m.def("tpl_constr_optional", [](std::experimental::optional<TplCtorClass> &) {});
  197. #endif
  198. // test_vec_of_reference_wrapper
  199. // #171: Can't return STL structures containing reference wrapper
  200. m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) {
  201. static UserType p1{1}, p2{2}, p3{3};
  202. return std::vector<std::reference_wrapper<UserType>> {
  203. std::ref(p1), std::ref(p2), std::ref(p3), p4
  204. };
  205. });
  206. // test_stl_pass_by_pointer
  207. m.def("stl_pass_by_pointer", [](std::vector<int>* v) { return *v; }, "v"_a=nullptr);
  208. class Placeholder {
  209. public:
  210. Placeholder() { print_created(this); }
  211. Placeholder(const Placeholder &) = delete;
  212. ~Placeholder() { print_destroyed(this); }
  213. };
  214. py::class_<Placeholder>(m, "Placeholder");
  215. /// test_stl_vector_ownership
  216. m.def("test_stl_ownership",
  217. []() {
  218. std::vector<Placeholder *> result;
  219. result.push_back(new Placeholder());
  220. return result;
  221. },
  222. py::return_value_policy::take_ownership);
  223. }