test_stl.cpp 12 KB

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