Unverified Commit ec24786e authored by Ralf W. Grosse-Kunstleve's avatar Ralf W. Grosse-Kunstleve Committed by GitHub
Browse files

Fully-automatic clang-format with include reordering (#3713)

* chore: add clang-format

* Removing check-style (Classic check-style)

Ported from @henryiii's https://github.com/pybind/pybind11/pull/3683/commits/53056b1b0eeb4136b0d7362a8261b6b59658e0a7



* Automatic clang-format changes (NO manual changes).
Co-authored-by: default avatarHenry Schreiner <henryschreineriii@gmail.com>
parent e96221be
...@@ -8,14 +8,15 @@ ...@@ -8,14 +8,15 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h"
namespace { namespace {
// Many bases for testing that multiple inheritance from many classes (i.e. requiring extra // Many bases for testing that multiple inheritance from many classes (i.e. requiring extra
// space for holder constructed flags) works. // space for holder constructed flags) works.
template <int N> struct BaseN { template <int N>
struct BaseN {
explicit BaseN(int i) : i(i) {} explicit BaseN(int i) : i(i) {}
int i; int i;
}; };
...@@ -57,13 +58,23 @@ struct Base2a { ...@@ -57,13 +58,23 @@ struct Base2a {
int i; int i;
}; };
struct Base12a : Base1a, Base2a { struct Base12a : Base1a, Base2a {
Base12a(int i, int j) : Base1a(i), Base2a(j) { } Base12a(int i, int j) : Base1a(i), Base2a(j) {}
}; };
// test_mi_unaligned_base // test_mi_unaligned_base
// test_mi_base_return // test_mi_base_return
struct I801B1 { int a = 1; I801B1() = default; I801B1(const I801B1 &) = default; virtual ~I801B1() = default; }; struct I801B1 {
struct I801B2 { int b = 2; I801B2() = default; I801B2(const I801B2 &) = default; virtual ~I801B2() = default; }; int a = 1;
I801B1() = default;
I801B1(const I801B1 &) = default;
virtual ~I801B1() = default;
};
struct I801B2 {
int b = 2;
I801B2() = default;
I801B2(const I801B2 &) = default;
virtual ~I801B2() = default;
};
struct I801C : I801B1, I801B2 {}; struct I801C : I801B1, I801B2 {};
struct I801D : I801C {}; // Indirect MI struct I801D : I801C {}; // Indirect MI
...@@ -82,8 +93,7 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -82,8 +93,7 @@ TEST_SUBMODULE(multiple_inheritance, m) {
int i; int i;
}; };
py::class_<Base1> b1(m, "Base1"); py::class_<Base1> b1(m, "Base1");
b1.def(py::init<int>()) b1.def(py::init<int>()).def("foo", &Base1::foo);
.def("foo", &Base1::foo);
struct Base2 { struct Base2 {
explicit Base2(int i) : i(i) {} explicit Base2(int i) : i(i) {}
...@@ -91,42 +101,49 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -91,42 +101,49 @@ TEST_SUBMODULE(multiple_inheritance, m) {
int i; int i;
}; };
py::class_<Base2> b2(m, "Base2"); py::class_<Base2> b2(m, "Base2");
b2.def(py::init<int>()) b2.def(py::init<int>()).def("bar", &Base2::bar);
.def("bar", &Base2::bar);
// test_multiple_inheritance_cpp // test_multiple_inheritance_cpp
struct Base12 : Base1, Base2 { struct Base12 : Base1, Base2 {
Base12(int i, int j) : Base1(i), Base2(j) { } Base12(int i, int j) : Base1(i), Base2(j) {}
}; };
struct MIType : Base12 { struct MIType : Base12 {
MIType(int i, int j) : Base12(i, j) { } MIType(int i, int j) : Base12(i, j) {}
}; };
py::class_<Base12, Base1, Base2>(m, "Base12"); py::class_<Base12, Base1, Base2>(m, "Base12");
py::class_<MIType, Base12>(m, "MIType") py::class_<MIType, Base12>(m, "MIType").def(py::init<int, int>());
.def(py::init<int, int>());
// test_multiple_inheritance_python_many_bases // test_multiple_inheritance_python_many_bases
#define PYBIND11_BASEN(N) \ #define PYBIND11_BASEN(N) \
py::class_<BaseN<(N)>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { \ py::class_<BaseN<(N)>>(m, "BaseN" #N).def(py::init<int>()).def("f" #N, [](BaseN<N> &b) { \
return b.i + (N); \ return b.i + (N); \
}) })
PYBIND11_BASEN( 1); PYBIND11_BASEN( 2); PYBIND11_BASEN( 3); PYBIND11_BASEN( 4); PYBIND11_BASEN(1);
PYBIND11_BASEN( 5); PYBIND11_BASEN( 6); PYBIND11_BASEN( 7); PYBIND11_BASEN( 8); PYBIND11_BASEN(2);
PYBIND11_BASEN( 9); PYBIND11_BASEN(10); PYBIND11_BASEN(11); PYBIND11_BASEN(12); PYBIND11_BASEN(3);
PYBIND11_BASEN(13); PYBIND11_BASEN(14); PYBIND11_BASEN(15); PYBIND11_BASEN(16); PYBIND11_BASEN(4);
PYBIND11_BASEN(5);
PYBIND11_BASEN(6);
PYBIND11_BASEN(7);
PYBIND11_BASEN(8);
PYBIND11_BASEN(9);
PYBIND11_BASEN(10);
PYBIND11_BASEN(11);
PYBIND11_BASEN(12);
PYBIND11_BASEN(13);
PYBIND11_BASEN(14);
PYBIND11_BASEN(15);
PYBIND11_BASEN(16);
PYBIND11_BASEN(17); PYBIND11_BASEN(17);
// Uncommenting this should result in a compile time failure (MI can only be specified via // Uncommenting this should result in a compile time failure (MI can only be specified via
// template parameters because pybind has to know the types involved; see discussion in #742 for // template parameters because pybind has to know the types involved; see discussion in #742
// details). // for details).
// struct Base12v2 : Base1, Base2 { // struct Base12v2 : Base1, Base2 {
// Base12v2(int i, int j) : Base1(i), Base2(j) { } // Base12v2(int i, int j) : Base1(i), Base2(j) { }
// }; // };
// py::class_<Base12v2>(m, "Base12v2", b1, b2) // py::class_<Base12v2>(m, "Base12v2", b1, b2)
// .def(py::init<int, int>()); // .def(py::init<int, int>());
// test_multiple_inheritance_virtbase // test_multiple_inheritance_virtbase
// Test the case where not all base classes are specified, and where pybind11 requires the // Test the case where not all base classes are specified, and where pybind11 requires the
...@@ -139,8 +156,8 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -139,8 +156,8 @@ TEST_SUBMODULE(multiple_inheritance, m) {
.def(py::init<int>()) .def(py::init<int>())
.def("bar", &Base2a::bar); .def("bar", &Base2a::bar);
py::class_<Base12a, /* Base1 missing */ Base2a, py::class_<Base12a, /* Base1 missing */ Base2a, std::shared_ptr<Base12a>>(
std::shared_ptr<Base12a>>(m, "Base12a", py::multiple_inheritance()) m, "Base12a", py::multiple_inheritance())
.def(py::init<int, int>()); .def(py::init<int, int>());
m.def("bar_base2a", [](Base2a *b) { return b->bar(); }); m.def("bar_base2a", [](Base2a *b) { return b->bar(); });
...@@ -150,11 +167,18 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -150,11 +167,18 @@ TEST_SUBMODULE(multiple_inheritance, m) {
// test_mi_base_return // test_mi_base_return
// Issue #801: invalid casting to derived type with MI bases // Issue #801: invalid casting to derived type with MI bases
// Unregistered classes: // Unregistered classes:
struct I801B3 { int c = 3; virtual ~I801B3() = default; }; struct I801B3 {
int c = 3;
virtual ~I801B3() = default;
};
struct I801E : I801B3, I801D {}; struct I801E : I801B3, I801D {};
py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1").def(py::init<>()).def_readonly("a", &I801B1::a); py::class_<I801B1, std::shared_ptr<I801B1>>(m, "I801B1")
py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2").def(py::init<>()).def_readonly("b", &I801B2::b); .def(py::init<>())
.def_readonly("a", &I801B1::a);
py::class_<I801B2, std::shared_ptr<I801B2>>(m, "I801B2")
.def(py::init<>())
.def_readonly("b", &I801B2::b);
py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>()); py::class_<I801C, I801B1, I801B2, std::shared_ptr<I801C>>(m, "I801C").def(py::init<>());
py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>()); py::class_<I801D, I801C, std::shared_ptr<I801D>>(m, "I801D").def(py::init<>());
...@@ -179,11 +203,8 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -179,11 +203,8 @@ TEST_SUBMODULE(multiple_inheritance, m) {
m.def("i801e_c", []() -> I801C * { return new I801E(); }); m.def("i801e_c", []() -> I801C * { return new I801E(); });
m.def("i801e_b2", []() -> I801B2 * { return new I801E(); }); m.def("i801e_b2", []() -> I801B2 * { return new I801E(); });
// test_mi_static_properties // test_mi_static_properties
py::class_<Vanilla>(m, "Vanilla") py::class_<Vanilla>(m, "Vanilla").def(py::init<>()).def("vanilla", &Vanilla::vanilla);
.def(py::init<>())
.def("vanilla", &Vanilla::vanilla);
py::class_<WithStatic1>(m, "WithStatic1") py::class_<WithStatic1>(m, "WithStatic1")
.def(py::init<>()) .def(py::init<>())
...@@ -195,22 +216,19 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -195,22 +216,19 @@ TEST_SUBMODULE(multiple_inheritance, m) {
.def_static("static_func2", &WithStatic2::static_func2) .def_static("static_func2", &WithStatic2::static_func2)
.def_readwrite_static("static_value2", &WithStatic2::static_value2); .def_readwrite_static("static_value2", &WithStatic2::static_value2);
py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>( py::class_<VanillaStaticMix1, Vanilla, WithStatic1, WithStatic2>(m, "VanillaStaticMix1")
m, "VanillaStaticMix1")
.def(py::init<>()) .def(py::init<>())
.def_static("static_func", &VanillaStaticMix1::static_func) .def_static("static_func", &VanillaStaticMix1::static_func)
.def_readwrite_static("static_value", &VanillaStaticMix1::static_value); .def_readwrite_static("static_value", &VanillaStaticMix1::static_value);
py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>( py::class_<VanillaStaticMix2, WithStatic1, Vanilla, WithStatic2>(m, "VanillaStaticMix2")
m, "VanillaStaticMix2")
.def(py::init<>()) .def(py::init<>())
.def_static("static_func", &VanillaStaticMix2::static_func) .def_static("static_func", &VanillaStaticMix2::static_func)
.def_readwrite_static("static_value", &VanillaStaticMix2::static_value); .def_readwrite_static("static_value", &VanillaStaticMix2::static_value);
struct WithDict {};
struct WithDict { }; struct VanillaDictMix1 : Vanilla, WithDict {};
struct VanillaDictMix1 : Vanilla, WithDict { }; struct VanillaDictMix2 : WithDict, Vanilla {};
struct VanillaDictMix2 : WithDict, Vanilla { };
py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>()); py::class_<WithDict>(m, "WithDict", py::dynamic_attr()).def(py::init<>());
py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>()); py::class_<VanillaDictMix1, Vanilla, WithDict>(m, "VanillaDictMix1").def(py::init<>());
py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>()); py::class_<VanillaDictMix2, WithDict, Vanilla>(m, "VanillaDictMix2").def(py::init<>());
...@@ -218,18 +236,25 @@ TEST_SUBMODULE(multiple_inheritance, m) { ...@@ -218,18 +236,25 @@ TEST_SUBMODULE(multiple_inheritance, m) {
// test_diamond_inheritance // test_diamond_inheritance
// Issue #959: segfault when constructing diamond inheritance instance // Issue #959: segfault when constructing diamond inheritance instance
// All of these have int members so that there will be various unequal pointers involved. // All of these have int members so that there will be various unequal pointers involved.
struct B { int b; B() = default; B(const B&) = default; virtual ~B() = default; }; struct B {
struct C0 : public virtual B { int c0; }; int b;
struct C1 : public virtual B { int c1; }; B() = default;
struct D : public C0, public C1 { int d; }; B(const B &) = default;
py::class_<B>(m, "B") virtual ~B() = default;
.def("b", [](B *self) { return self; }); };
py::class_<C0, B>(m, "C0") struct C0 : public virtual B {
.def("c0", [](C0 *self) { return self; }); int c0;
py::class_<C1, B>(m, "C1") };
.def("c1", [](C1 *self) { return self; }); struct C1 : public virtual B {
py::class_<D, C0, C1>(m, "D") int c1;
.def(py::init<>()); };
struct D : public C0, public C1 {
int d;
};
py::class_<B>(m, "B").def("b", [](B *self) { return self; });
py::class_<C0, B>(m, "C0").def("c0", [](C0 *self) { return self; });
py::class_<C1, B>(m, "C1").def("c1", [](C1 *self) { return self; });
py::class_<D, C0, C1>(m, "D").def(py::init<>());
// test_pr3635_diamond_* // test_pr3635_diamond_*
// - functions are get_{base}_{var}, return {var} // - functions are get_{base}_{var}, return {var}
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/numpy.h> #include <pybind11/numpy.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "pybind11_tests.h"
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
...@@ -22,7 +22,7 @@ struct DtypeCheck { ...@@ -22,7 +22,7 @@ struct DtypeCheck {
}; };
template <typename T> template <typename T>
DtypeCheck get_dtype_check(const char* name) { DtypeCheck get_dtype_check(const char *name) {
py::module_ np = py::module_::import("numpy"); py::module_ np = py::module_::import("numpy");
DtypeCheck check{}; DtypeCheck check{};
check.numpy = np.attr("dtype")(np.attr(name)); check.numpy = np.attr("dtype")(np.attr(name));
...@@ -31,17 +31,15 @@ DtypeCheck get_dtype_check(const char* name) { ...@@ -31,17 +31,15 @@ DtypeCheck get_dtype_check(const char* name) {
} }
std::vector<DtypeCheck> get_concrete_dtype_checks() { std::vector<DtypeCheck> get_concrete_dtype_checks() {
return { return {// Normalization
// Normalization get_dtype_check<std::int8_t>("int8"),
get_dtype_check<std::int8_t>("int8"), get_dtype_check<std::uint8_t>("uint8"),
get_dtype_check<std::uint8_t>("uint8"), get_dtype_check<std::int16_t>("int16"),
get_dtype_check<std::int16_t>("int16"), get_dtype_check<std::uint16_t>("uint16"),
get_dtype_check<std::uint16_t>("uint16"), get_dtype_check<std::int32_t>("int32"),
get_dtype_check<std::int32_t>("int32"), get_dtype_check<std::uint32_t>("uint32"),
get_dtype_check<std::uint32_t>("uint32"), get_dtype_check<std::int64_t>("int64"),
get_dtype_check<std::int64_t>("int64"), get_dtype_check<std::uint64_t>("uint64")};
get_dtype_check<std::uint64_t>("uint64")
};
} }
struct DtypeSizeCheck { struct DtypeSizeCheck {
...@@ -80,15 +78,18 @@ using arr = py::array; ...@@ -80,15 +78,18 @@ using arr = py::array;
using arr_t = py::array_t<uint16_t, 0>; using arr_t = py::array_t<uint16_t, 0>;
static_assert(std::is_same<arr_t::value_type, uint16_t>::value, ""); static_assert(std::is_same<arr_t::value_type, uint16_t>::value, "");
template<typename... Ix> arr data(const arr& a, Ix... index) { template <typename... Ix>
arr data(const arr &a, Ix... index) {
return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...)); return arr(a.nbytes() - a.offset_at(index...), (const uint8_t *) a.data(index...));
} }
template<typename... Ix> arr data_t(const arr_t& a, Ix... index) { template <typename... Ix>
arr data_t(const arr_t &a, Ix... index) {
return arr(a.size() - a.index_at(index...), a.data(index...)); return arr(a.size() - a.index_at(index...), a.data(index...));
} }
template<typename... Ix> arr& mutate_data(arr& a, Ix... index) { template <typename... Ix>
arr &mutate_data(arr &a, Ix... index) {
auto *ptr = (uint8_t *) a.mutable_data(index...); auto *ptr = (uint8_t *) a.mutable_data(index...);
for (py::ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) { for (py::ssize_t i = 0; i < a.nbytes() - a.offset_at(index...); i++) {
ptr[i] = (uint8_t) (ptr[i] * 2); ptr[i] = (uint8_t) (ptr[i] * 2);
...@@ -96,7 +97,8 @@ template<typename... Ix> arr& mutate_data(arr& a, Ix... index) { ...@@ -96,7 +97,8 @@ template<typename... Ix> arr& mutate_data(arr& a, Ix... index) {
return a; return a;
} }
template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) { template <typename... Ix>
arr_t &mutate_data_t(arr_t &a, Ix... index) {
auto ptr = a.mutable_data(index...); auto ptr = a.mutable_data(index...);
for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++) { for (py::ssize_t i = 0; i < a.size() - a.index_at(index...); i++) {
ptr[i]++; ptr[i]++;
...@@ -104,20 +106,40 @@ template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) { ...@@ -104,20 +106,40 @@ template<typename... Ix> arr_t& mutate_data_t(arr_t& a, Ix... index) {
return a; return a;
} }
template<typename... Ix> py::ssize_t index_at(const arr& a, Ix... idx) { return a.index_at(idx...); } template <typename... Ix>
template<typename... Ix> py::ssize_t index_at_t(const arr_t& a, Ix... idx) { return a.index_at(idx...); } py::ssize_t index_at(const arr &a, Ix... idx) {
template<typename... Ix> py::ssize_t offset_at(const arr& a, Ix... idx) { return a.offset_at(idx...); } return a.index_at(idx...);
template<typename... Ix> py::ssize_t offset_at_t(const arr_t& a, Ix... idx) { return a.offset_at(idx...); } }
template<typename... Ix> py::ssize_t at_t(const arr_t& a, Ix... idx) { return a.at(idx...); } template <typename... Ix>
template<typename... Ix> arr_t& mutate_at_t(arr_t& a, Ix... idx) { a.mutable_at(idx...)++; return a; } py::ssize_t index_at_t(const arr_t &a, Ix... idx) {
return a.index_at(idx...);
#define def_index_fn(name, type) \ }
sm.def(#name, [](type a) { return name(a); }); \ template <typename... Ix>
sm.def(#name, [](type a, int i) { return name(a, i); }); \ py::ssize_t offset_at(const arr &a, Ix... idx) {
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \ return a.offset_at(idx...);
}
template <typename... Ix>
py::ssize_t offset_at_t(const arr_t &a, Ix... idx) {
return a.offset_at(idx...);
}
template <typename... Ix>
py::ssize_t at_t(const arr_t &a, Ix... idx) {
return a.at(idx...);
}
template <typename... Ix>
arr_t &mutate_at_t(arr_t &a, Ix... idx) {
a.mutable_at(idx...)++;
return a;
}
#define def_index_fn(name, type) \
sm.def(#name, [](type a) { return name(a); }); \
sm.def(#name, [](type a, int i) { return name(a, i); }); \
sm.def(#name, [](type a, int i, int j) { return name(a, i, j); }); \
sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); }); sm.def(#name, [](type a, int i, int j, int k) { return name(a, i, j, k); });
template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) { template <typename T, typename T2>
py::handle auxiliaries(T &&r, T2 &&r2) {
if (r.ndim() != 2) { if (r.ndim() != 2) {
throw std::domain_error("error: ndim != 2"); throw std::domain_error("error: ndim != 2");
} }
...@@ -138,16 +160,18 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) { ...@@ -138,16 +160,18 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
static int data_i = 42; static int data_i = 42;
TEST_SUBMODULE(numpy_array, sm) { TEST_SUBMODULE(numpy_array, sm) {
try { py::module_::import("numpy"); } try {
catch (...) { return; } py::module_::import("numpy");
} catch (...) {
return;
}
// test_dtypes // test_dtypes
py::class_<DtypeCheck>(sm, "DtypeCheck") py::class_<DtypeCheck>(sm, "DtypeCheck")
.def_readonly("numpy", &DtypeCheck::numpy) .def_readonly("numpy", &DtypeCheck::numpy)
.def_readonly("pybind11", &DtypeCheck::pybind11) .def_readonly("pybind11", &DtypeCheck::pybind11)
.def("__repr__", [](const DtypeCheck& self) { .def("__repr__", [](const DtypeCheck &self) {
return py::str("<DtypeCheck numpy={} pybind11={}>").format( return py::str("<DtypeCheck numpy={} pybind11={}>").format(self.numpy, self.pybind11);
self.numpy, self.pybind11);
}); });
sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks); sm.def("get_concrete_dtype_checks", &get_concrete_dtype_checks);
...@@ -155,41 +179,41 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -155,41 +179,41 @@ TEST_SUBMODULE(numpy_array, sm) {
.def_readonly("name", &DtypeSizeCheck::name) .def_readonly("name", &DtypeSizeCheck::name)
.def_readonly("size_cpp", &DtypeSizeCheck::size_cpp) .def_readonly("size_cpp", &DtypeSizeCheck::size_cpp)
.def_readonly("size_numpy", &DtypeSizeCheck::size_numpy) .def_readonly("size_numpy", &DtypeSizeCheck::size_numpy)
.def("__repr__", [](const DtypeSizeCheck& self) { .def("__repr__", [](const DtypeSizeCheck &self) {
return py::str("<DtypeSizeCheck name='{}' size_cpp={} size_numpy={} dtype={}>").format( return py::str("<DtypeSizeCheck name='{}' size_cpp={} size_numpy={} dtype={}>")
self.name, self.size_cpp, self.size_numpy, self.dtype); .format(self.name, self.size_cpp, self.size_numpy, self.dtype);
}); });
sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks); sm.def("get_platform_dtype_size_checks", &get_platform_dtype_size_checks);
// test_array_attributes // test_array_attributes
sm.def("ndim", [](const arr& a) { return a.ndim(); }); sm.def("ndim", [](const arr &a) { return a.ndim(); });
sm.def("shape", [](const arr& a) { return arr(a.ndim(), a.shape()); }); sm.def("shape", [](const arr &a) { return arr(a.ndim(), a.shape()); });
sm.def("shape", [](const arr& a, py::ssize_t dim) { return a.shape(dim); }); sm.def("shape", [](const arr &a, py::ssize_t dim) { return a.shape(dim); });
sm.def("strides", [](const arr& a) { return arr(a.ndim(), a.strides()); }); sm.def("strides", [](const arr &a) { return arr(a.ndim(), a.strides()); });
sm.def("strides", [](const arr& a, py::ssize_t dim) { return a.strides(dim); }); sm.def("strides", [](const arr &a, py::ssize_t dim) { return a.strides(dim); });
sm.def("writeable", [](const arr& a) { return a.writeable(); }); sm.def("writeable", [](const arr &a) { return a.writeable(); });
sm.def("size", [](const arr& a) { return a.size(); }); sm.def("size", [](const arr &a) { return a.size(); });
sm.def("itemsize", [](const arr& a) { return a.itemsize(); }); sm.def("itemsize", [](const arr &a) { return a.itemsize(); });
sm.def("nbytes", [](const arr& a) { return a.nbytes(); }); sm.def("nbytes", [](const arr &a) { return a.nbytes(); });
sm.def("owndata", [](const arr& a) { return a.owndata(); }); sm.def("owndata", [](const arr &a) { return a.owndata(); });
// test_index_offset // test_index_offset
def_index_fn(index_at, const arr&); def_index_fn(index_at, const arr &);
def_index_fn(index_at_t, const arr_t&); def_index_fn(index_at_t, const arr_t &);
def_index_fn(offset_at, const arr&); def_index_fn(offset_at, const arr &);
def_index_fn(offset_at_t, const arr_t&); def_index_fn(offset_at_t, const arr_t &);
// test_data // test_data
def_index_fn(data, const arr&); def_index_fn(data, const arr &);
def_index_fn(data_t, const arr_t&); def_index_fn(data_t, const arr_t &);
// test_mutate_data, test_mutate_readonly // test_mutate_data, test_mutate_readonly
def_index_fn(mutate_data, arr&); def_index_fn(mutate_data, arr &);
def_index_fn(mutate_data_t, arr_t&); def_index_fn(mutate_data_t, arr_t &);
def_index_fn(at_t, const arr_t&); def_index_fn(at_t, const arr_t &);
def_index_fn(mutate_at_t, arr_t&); def_index_fn(mutate_at_t, arr_t &);
// test_make_c_f_array // test_make_c_f_array
sm.def("make_f_array", [] { return py::array_t<float>({ 2, 2 }, { 4, 8 }); }); sm.def("make_f_array", [] { return py::array_t<float>({2, 2}, {4, 8}); });
sm.def("make_c_array", [] { return py::array_t<float>({ 2, 2 }, { 8, 4 }); }); sm.def("make_c_array", [] { return py::array_t<float>({2, 2}, {8, 4}); });
// test_empty_shaped_array // test_empty_shaped_array
sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); }); sm.def("make_empty_shaped_array", [] { return py::array(py::dtype("f"), {}, {}); });
...@@ -198,18 +222,16 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -198,18 +222,16 @@ TEST_SUBMODULE(numpy_array, sm) {
// test_wrap // test_wrap
sm.def("wrap", [](const py::array &a) { sm.def("wrap", [](const py::array &a) {
return py::array( return py::array(a.dtype(),
a.dtype(), {a.shape(), a.shape() + a.ndim()},
{a.shape(), a.shape() + a.ndim()}, {a.strides(), a.strides() + a.ndim()},
{a.strides(), a.strides() + a.ndim()}, a.data(),
a.data(), a);
a
);
}); });
// test_numpy_view // test_numpy_view
struct ArrayClass { struct ArrayClass {
int data[2] = { 1, 2 }; int data[2] = {1, 2};
ArrayClass() { py::print("ArrayClass()"); } ArrayClass() { py::print("ArrayClass()"); }
~ArrayClass() { py::print("~ArrayClass()"); } ~ArrayClass() { py::print("~ArrayClass()"); }
}; };
...@@ -217,13 +239,12 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -217,13 +239,12 @@ TEST_SUBMODULE(numpy_array, sm) {
.def(py::init<>()) .def(py::init<>())
.def("numpy_view", [](py::object &obj) { .def("numpy_view", [](py::object &obj) {
py::print("ArrayClass::numpy_view()"); py::print("ArrayClass::numpy_view()");
auto &a = obj.cast<ArrayClass&>(); auto &a = obj.cast<ArrayClass &>();
return py::array_t<int>({2}, {4}, a.data, obj); return py::array_t<int>({2}, {4}, a.data, obj);
} });
);
// test_cast_numpy_int64_to_uint64 // test_cast_numpy_int64_to_uint64
sm.def("function_taking_uint64", [](uint64_t) { }); sm.def("function_taking_uint64", [](uint64_t) {});
// test_isinstance // test_isinstance
sm.def("isinstance_untyped", [](py::object yes, py::object no) { sm.def("isinstance_untyped", [](py::object yes, py::object no) {
...@@ -236,18 +257,14 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -236,18 +257,14 @@ TEST_SUBMODULE(numpy_array, sm) {
// test_constructors // test_constructors
sm.def("default_constructors", []() { sm.def("default_constructors", []() {
return py::dict( return py::dict("array"_a = py::array(),
"array"_a=py::array(), "array_t<int32>"_a = py::array_t<std::int32_t>(),
"array_t<int32>"_a=py::array_t<std::int32_t>(), "array_t<double>"_a = py::array_t<double>());
"array_t<double>"_a=py::array_t<double>()
);
}); });
sm.def("converting_constructors", [](const py::object &o) { sm.def("converting_constructors", [](const py::object &o) {
return py::dict( return py::dict("array"_a = py::array(o),
"array"_a=py::array(o), "array_t<int32>"_a = py::array_t<std::int32_t>(o),
"array_t<int32>"_a=py::array_t<std::int32_t>(o), "array_t<double>"_a = py::array_t<double>(o));
"array_t<double>"_a=py::array_t<double>(o)
);
}); });
// test_overload_resolution // test_overload_resolution
...@@ -294,17 +311,21 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -294,17 +311,21 @@ TEST_SUBMODULE(numpy_array, sm) {
sm.def("issue685", [](const py::object &) { return "other"; }); sm.def("issue685", [](const py::object &) { return "other"; });
// test_array_unchecked_fixed_dims // test_array_unchecked_fixed_dims
sm.def("proxy_add2", [](py::array_t<double> a, double v) { sm.def(
auto r = a.mutable_unchecked<2>(); "proxy_add2",
for (py::ssize_t i = 0; i < r.shape(0); i++) { [](py::array_t<double> a, double v) {
for (py::ssize_t j = 0; j < r.shape(1); j++) { auto r = a.mutable_unchecked<2>();
r(i, j) += v; for (py::ssize_t i = 0; i < r.shape(0); i++) {
for (py::ssize_t j = 0; j < r.shape(1); j++) {
r(i, j) += v;
}
} }
} },
}, py::arg{}.noconvert(), py::arg()); py::arg{}.noconvert(),
py::arg());
sm.def("proxy_init3", [](double start) { sm.def("proxy_init3", [](double start) {
py::array_t<double, py::array::c_style> a({ 3, 3, 3 }); py::array_t<double, py::array::c_style> a({3, 3, 3});
auto r = a.mutable_unchecked<3>(); auto r = a.mutable_unchecked<3>();
for (py::ssize_t i = 0; i < r.shape(0); i++) { for (py::ssize_t i = 0; i < r.shape(0); i++) {
for (py::ssize_t j = 0; j < r.shape(1); j++) { for (py::ssize_t j = 0; j < r.shape(1); j++) {
...@@ -316,7 +337,7 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -316,7 +337,7 @@ TEST_SUBMODULE(numpy_array, sm) {
return a; return a;
}); });
sm.def("proxy_init3F", [](double start) { sm.def("proxy_init3F", [](double start) {
py::array_t<double, py::array::f_style> a({ 3, 3, 3 }); py::array_t<double, py::array::f_style> a({3, 3, 3});
auto r = a.mutable_unchecked<3>(); auto r = a.mutable_unchecked<3>();
for (py::ssize_t k = 0; k < r.shape(2); k++) { for (py::ssize_t k = 0; k < r.shape(2); k++) {
for (py::ssize_t j = 0; j < r.shape(1); j++) { for (py::ssize_t j = 0; j < r.shape(1); j++) {
...@@ -356,19 +377,23 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -356,19 +377,23 @@ TEST_SUBMODULE(numpy_array, sm) {
// test_array_unchecked_dyn_dims // test_array_unchecked_dyn_dims
// Same as the above, but without a compile-time dimensions specification: // Same as the above, but without a compile-time dimensions specification:
sm.def("proxy_add2_dyn", [](py::array_t<double> a, double v) { sm.def(
auto r = a.mutable_unchecked(); "proxy_add2_dyn",
if (r.ndim() != 2) { [](py::array_t<double> a, double v) {
throw std::domain_error("error: ndim != 2"); auto r = a.mutable_unchecked();
} if (r.ndim() != 2) {
for (py::ssize_t i = 0; i < r.shape(0); i++) { throw std::domain_error("error: ndim != 2");
for (py::ssize_t j = 0; j < r.shape(1); j++) {
r(i, j) += v;
} }
} for (py::ssize_t i = 0; i < r.shape(0); i++) {
}, py::arg{}.noconvert(), py::arg()); for (py::ssize_t j = 0; j < r.shape(1); j++) {
r(i, j) += v;
}
}
},
py::arg{}.noconvert(),
py::arg());
sm.def("proxy_init3_dyn", [](double start) { sm.def("proxy_init3_dyn", [](double start) {
py::array_t<double, py::array::c_style> a({ 3, 3, 3 }); py::array_t<double, py::array::c_style> a({3, 3, 3});
auto r = a.mutable_unchecked(); auto r = a.mutable_unchecked();
if (r.ndim() != 3) { if (r.ndim() != 3) {
throw std::domain_error("error: ndim != 3"); throw std::domain_error("error: ndim != 3");
...@@ -386,29 +411,31 @@ TEST_SUBMODULE(numpy_array, sm) { ...@@ -386,29 +411,31 @@ TEST_SUBMODULE(numpy_array, sm) {
return auxiliaries(a.unchecked(), a.mutable_unchecked()); return auxiliaries(a.unchecked(), a.mutable_unchecked());
}); });
sm.def("array_auxiliaries2", [](py::array_t<double> a) { sm.def("array_auxiliaries2", [](py::array_t<double> a) { return auxiliaries(a, a); });
return auxiliaries(a, a);
});
// test_array_failures // test_array_failures
// Issue #785: Uninformative "Unknown internal error" exception when constructing array from empty object: // Issue #785: Uninformative "Unknown internal error" exception when constructing array from
// empty object:
sm.def("array_fail_test", []() { return py::array(py::object()); }); sm.def("array_fail_test", []() { return py::array(py::object()); });
sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); }); sm.def("array_t_fail_test", []() { return py::array_t<double>(py::object()); });
// Make sure the error from numpy is being passed through: // Make sure the error from numpy is being passed through:
sm.def("array_fail_test_negative_size", []() { int c = 0; return py::array(-1, &c); }); sm.def("array_fail_test_negative_size", []() {
int c = 0;
return py::array(-1, &c);
});
// test_initializer_list // test_initializer_list
// Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous // Issue (unnumbered; reported in #788): regression: initializer lists can be ambiguous
sm.def("array_initializer_list1", []() { return py::array_t<float>(1); }); sm.def("array_initializer_list1", []() { return py::array_t<float>(1); });
// { 1 } also works for the above, but clang warns about it // { 1 } also works for the above, but clang warns about it
sm.def("array_initializer_list2", []() { return py::array_t<float>({ 1, 2 }); }); sm.def("array_initializer_list2", []() { return py::array_t<float>({1, 2}); });
sm.def("array_initializer_list3", []() { return py::array_t<float>({ 1, 2, 3 }); }); sm.def("array_initializer_list3", []() { return py::array_t<float>({1, 2, 3}); });
sm.def("array_initializer_list4", []() { return py::array_t<float>({ 1, 2, 3, 4 }); }); sm.def("array_initializer_list4", []() { return py::array_t<float>({1, 2, 3, 4}); });
// test_array_resize // test_array_resize
// reshape array to 2D without changing size // reshape array to 2D without changing size
sm.def("array_reshape2", [](py::array_t<double> a) { sm.def("array_reshape2", [](py::array_t<double> a) {
const auto dim_sz = (py::ssize_t)std::sqrt(a.size()); const auto dim_sz = (py::ssize_t) std::sqrt(a.size());
if (dim_sz * dim_sz != a.size()) { if (dim_sz * dim_sz != a.size()) {
throw std::domain_error( throw std::domain_error(
"array_reshape2: input array total size is not a squared integer"); "array_reshape2: input array total size is not a squared integer");
......
...@@ -7,13 +7,14 @@ ...@@ -7,13 +7,14 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/numpy.h> #include <pybind11/numpy.h>
#include "pybind11_tests.h"
#ifdef __GNUC__ #ifdef __GNUC__
#define PYBIND11_PACKED(cls) cls __attribute__((__packed__)) # define PYBIND11_PACKED(cls) cls __attribute__((__packed__))
#else #else
#define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop)) # define PYBIND11_PACKED(cls) __pragma(pack(push, 1)) cls __pragma(pack(pop))
#endif #endif
namespace py = pybind11; namespace py = pybind11;
...@@ -25,7 +26,7 @@ struct SimpleStruct { ...@@ -25,7 +26,7 @@ struct SimpleStruct {
long double ldbl_; long double ldbl_;
}; };
std::ostream& operator<<(std::ostream& os, const SimpleStruct& v) { std::ostream &operator<<(std::ostream &os, const SimpleStruct &v) {
return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; return os << "s:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
} }
...@@ -43,7 +44,7 @@ PYBIND11_PACKED(struct PackedStruct { ...@@ -43,7 +44,7 @@ PYBIND11_PACKED(struct PackedStruct {
long double ldbl_; long double ldbl_;
}); });
std::ostream& operator<<(std::ostream& os, const PackedStruct& v) { std::ostream &operator<<(std::ostream &os, const PackedStruct &v) {
return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_; return os << "p:" << v.bool_ << "," << v.uint_ << "," << v.float_ << "," << v.ldbl_;
} }
...@@ -52,7 +53,7 @@ PYBIND11_PACKED(struct NestedStruct { ...@@ -52,7 +53,7 @@ PYBIND11_PACKED(struct NestedStruct {
PackedStruct b; PackedStruct b;
}); });
std::ostream& operator<<(std::ostream& os, const NestedStruct& v) { std::ostream &operator<<(std::ostream &os, const NestedStruct &v) {
return os << "n:a=" << v.a << ";b=" << v.b; return os << "n:a=" << v.a << ";b=" << v.b;
} }
...@@ -70,7 +71,7 @@ struct PartialNestedStruct { ...@@ -70,7 +71,7 @@ struct PartialNestedStruct {
uint64_t dummy2; uint64_t dummy2;
}; };
struct UnboundStruct { }; struct UnboundStruct {};
struct StringStruct { struct StringStruct {
char a[3]; char a[3];
...@@ -82,7 +83,7 @@ struct ComplexStruct { ...@@ -82,7 +83,7 @@ struct ComplexStruct {
std::complex<double> cdbl; std::complex<double> cdbl;
}; };
std::ostream& operator<<(std::ostream& os, const ComplexStruct& v) { std::ostream &operator<<(std::ostream &os, const ComplexStruct &v) {
return os << "c:" << v.cflt << "," << v.cdbl; return os << "c:" << v.cflt << "," << v.cdbl;
} }
...@@ -106,7 +107,7 @@ PYBIND11_PACKED(struct EnumStruct { ...@@ -106,7 +107,7 @@ PYBIND11_PACKED(struct EnumStruct {
E2 e2; E2 e2;
}); });
std::ostream& operator<<(std::ostream& os, const StringStruct& v) { std::ostream &operator<<(std::ostream &os, const StringStruct &v) {
os << "a='"; os << "a='";
for (size_t i = 0; i < 3 && (v.a[i] != 0); i++) { for (size_t i = 0; i < 3 && (v.a[i] != 0); i++) {
os << v.a[i]; os << v.a[i];
...@@ -118,7 +119,7 @@ std::ostream& operator<<(std::ostream& os, const StringStruct& v) { ...@@ -118,7 +119,7 @@ std::ostream& operator<<(std::ostream& os, const StringStruct& v) {
return os << "'"; return os << "'";
} }
std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) { std::ostream &operator<<(std::ostream &os, const ArrayStruct &v) {
os << "a={"; os << "a={";
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (i > 0) { if (i > 0) {
...@@ -142,15 +143,14 @@ std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) { ...@@ -142,15 +143,14 @@ std::ostream& operator<<(std::ostream& os, const ArrayStruct& v) {
return os << '}'; return os << '}';
} }
std::ostream& operator<<(std::ostream& os, const EnumStruct& v) { std::ostream &operator<<(std::ostream &os, const EnumStruct &v) {
return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y"); return os << "e1=" << (v.e1 == E1::A ? "A" : "B") << ",e2=" << (v.e2 == E2::X ? "X" : "Y");
} }
template <typename T> template <typename T>
py::array mkarray_via_buffer(size_t n) { py::array mkarray_via_buffer(size_t n) {
return py::array(py::buffer_info(nullptr, sizeof(T), return py::array(py::buffer_info(
py::format_descriptor<T>::format(), nullptr, sizeof(T), py::format_descriptor<T>::format(), 1, {n}, {sizeof(T)}));
1, { n }, { sizeof(T) }));
} }
#define SET_TEST_VALS(s, i) \ #define SET_TEST_VALS(s, i) \
...@@ -188,9 +188,9 @@ py::list print_recarray(py::array_t<S, 0> arr) { ...@@ -188,9 +188,9 @@ py::list print_recarray(py::array_t<S, 0> arr) {
py::array_t<int32_t, 0> test_array_ctors(int i) { py::array_t<int32_t, 0> test_array_ctors(int i) {
using arr_t = py::array_t<int32_t, 0>; using arr_t = py::array_t<int32_t, 0>;
std::vector<int32_t> data { 1, 2, 3, 4, 5, 6 }; std::vector<int32_t> data{1, 2, 3, 4, 5, 6};
std::vector<py::ssize_t> shape { 3, 2 }; std::vector<py::ssize_t> shape{3, 2};
std::vector<py::ssize_t> strides { 8, 4 }; std::vector<py::ssize_t> strides{8, 4};
auto *ptr = data.data(); auto *ptr = data.data();
auto *vptr = (void *) ptr; auto *vptr = (void *) ptr;
...@@ -210,36 +210,62 @@ py::array_t<int32_t, 0> test_array_ctors(int i) { ...@@ -210,36 +210,62 @@ py::array_t<int32_t, 0> test_array_ctors(int i) {
}; };
switch (i) { switch (i) {
// shape: (3, 2) // shape: (3, 2)
case 10: return arr_t(shape, strides, ptr); case 10:
case 11: return py::array(shape, strides, ptr); return arr_t(shape, strides, ptr);
case 12: return py::array(dtype, shape, strides, vptr); case 11:
case 13: return arr_t(shape, ptr); return py::array(shape, strides, ptr);
case 14: return py::array(shape, ptr); case 12:
case 15: return py::array(dtype, shape, vptr); return py::array(dtype, shape, strides, vptr);
case 16: return arr_t(buf_ndim2); case 13:
case 17: return py::array(buf_ndim2); return arr_t(shape, ptr);
// shape: (3, 2) - post-fill case 14:
case 20: return fill(arr_t(shape, strides)); return py::array(shape, ptr);
case 21: return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor case 15:
case 22: return fill(py::array(dtype, shape, strides)); return py::array(dtype, shape, vptr);
case 23: return fill(arr_t(shape)); case 16:
case 24: return py::array(shape, ptr); // can't have nullptr due to templated ctor return arr_t(buf_ndim2);
case 25: return fill(py::array(dtype, shape)); case 17:
case 26: return fill(arr_t(buf_ndim2_null)); return py::array(buf_ndim2);
case 27: return fill(py::array(buf_ndim2_null)); // shape: (3, 2) - post-fill
// shape: (6, ) case 20:
case 30: return arr_t(6, ptr); return fill(arr_t(shape, strides));
case 31: return py::array(6, ptr); case 21:
case 32: return py::array(dtype, 6, vptr); return py::array(shape, strides, ptr); // can't have nullptr due to templated ctor
case 33: return arr_t(buf_ndim1); case 22:
case 34: return py::array(buf_ndim1); return fill(py::array(dtype, shape, strides));
// shape: (6, ) case 23:
case 40: return fill(arr_t(6)); return fill(arr_t(shape));
case 41: return py::array(6, ptr); // can't have nullptr due to templated ctor case 24:
case 42: return fill(py::array(dtype, 6)); return py::array(shape, ptr); // can't have nullptr due to templated ctor
case 43: return fill(arr_t(buf_ndim1_null)); case 25:
case 44: return fill(py::array(buf_ndim1_null)); return fill(py::array(dtype, shape));
case 26:
return fill(arr_t(buf_ndim2_null));
case 27:
return fill(py::array(buf_ndim2_null));
// shape: (6, )
case 30:
return arr_t(6, ptr);
case 31:
return py::array(6, ptr);
case 32:
return py::array(dtype, 6, vptr);
case 33:
return arr_t(buf_ndim1);
case 34:
return py::array(buf_ndim1);
// shape: (6, )
case 40:
return fill(arr_t(6));
case 41:
return py::array(6, ptr); // can't have nullptr due to templated ctor
case 42:
return fill(py::array(dtype, 6));
case 43:
return fill(arr_t(buf_ndim1_null));
case 44:
return fill(py::array(buf_ndim1_null));
} }
return arr_t(); return arr_t();
} }
...@@ -251,9 +277,15 @@ py::list test_dtype_ctors() { ...@@ -251,9 +277,15 @@ py::list test_dtype_ctors() {
list.append(py::dtype::from_args(py::str("bool"))); list.append(py::dtype::from_args(py::str("bool")));
py::list names, offsets, formats; py::list names, offsets, formats;
py::dict dict; py::dict dict;
names.append(py::str("a")); names.append(py::str("b")); dict["names"] = names; names.append(py::str("a"));
offsets.append(py::int_(1)); offsets.append(py::int_(10)); dict["offsets"] = offsets; names.append(py::str("b"));
formats.append(py::dtype("int32")); formats.append(py::dtype("float64")); dict["formats"] = formats; dict["names"] = names;
offsets.append(py::int_(1));
offsets.append(py::int_(10));
dict["offsets"] = offsets;
formats.append(py::dtype("int32"));
formats.append(py::dtype("float64"));
dict["formats"] = formats;
dict["itemsize"] = py::int_(20); dict["itemsize"] = py::int_(20);
list.append(py::dtype::from_args(dict)); list.append(py::dtype::from_args(dict));
list.append(py::dtype(names, formats, offsets, 20)); list.append(py::dtype(names, formats, offsets, 20));
...@@ -266,8 +298,11 @@ struct A {}; ...@@ -266,8 +298,11 @@ struct A {};
struct B {}; struct B {};
TEST_SUBMODULE(numpy_dtypes, m) { TEST_SUBMODULE(numpy_dtypes, m) {
try { py::module_::import("numpy"); } try {
catch (...) { return; } py::module_::import("numpy");
} catch (...) {
return;
}
// typeinfo may be registered before the dtype descriptor for scalar casts to work... // typeinfo may be registered before the dtype descriptor for scalar casts to work...
py::class_<SimpleStruct>(m, "SimpleStruct") py::class_<SimpleStruct>(m, "SimpleStruct")
...@@ -285,11 +320,10 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -285,11 +320,10 @@ TEST_SUBMODULE(numpy_dtypes, m) {
if (py::len(tup) != 4) { if (py::len(tup) != 4) {
throw py::cast_error("Invalid size"); throw py::cast_error("Invalid size");
} }
return SimpleStruct{ return SimpleStruct{tup[0].cast<bool>(),
tup[0].cast<bool>(), tup[1].cast<uint32_t>(),
tup[1].cast<uint32_t>(), tup[2].cast<float>(),
tup[2].cast<float>(), tup[3].cast<long double>()};
tup[3].cast<long double>()};
}); });
PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_);
...@@ -311,18 +345,18 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -311,18 +345,18 @@ TEST_SUBMODULE(numpy_dtypes, m) {
#ifdef PYBIND11_NEVER_DEFINED_EVER #ifdef PYBIND11_NEVER_DEFINED_EVER
// If enabled, this should produce a static_assert failure telling the user that the struct // If enabled, this should produce a static_assert failure telling the user that the struct
// is not a POD type // is not a POD type
struct NotPOD { std::string v; NotPOD() : v("hi") {}; }; struct NotPOD {
std::string v;
NotPOD() : v("hi"){};
};
PYBIND11_NUMPY_DTYPE(NotPOD, v); PYBIND11_NUMPY_DTYPE(NotPOD, v);
#endif #endif
// Check that dtypes can be registered programmatically, both from // Check that dtypes can be registered programmatically, both from
// initializer lists of field descriptors and from other containers. // initializer lists of field descriptors and from other containers.
py::detail::npy_format_descriptor<A>::register_dtype( py::detail::npy_format_descriptor<A>::register_dtype({});
{}
);
py::detail::npy_format_descriptor<B>::register_dtype( py::detail::npy_format_descriptor<B>::register_dtype(
std::vector<py::detail::field_descriptor>{} std::vector<py::detail::field_descriptor>{});
);
// test_recarray, test_scalar_conversion // test_recarray, test_scalar_conversion
m.def("create_rec_simple", &create_recarray<SimpleStruct>); m.def("create_rec_simple", &create_recarray<SimpleStruct>);
...@@ -355,17 +389,15 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -355,17 +389,15 @@ TEST_SUBMODULE(numpy_dtypes, m) {
m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); }); m.def("get_format_unbound", []() { return py::format_descriptor<UnboundStruct>::format(); });
m.def("print_format_descriptors", []() { m.def("print_format_descriptors", []() {
py::list l; py::list l;
for (const auto &fmt : { for (const auto &fmt : {py::format_descriptor<SimpleStruct>::format(),
py::format_descriptor<SimpleStruct>::format(), py::format_descriptor<PackedStruct>::format(),
py::format_descriptor<PackedStruct>::format(), py::format_descriptor<NestedStruct>::format(),
py::format_descriptor<NestedStruct>::format(), py::format_descriptor<PartialStruct>::format(),
py::format_descriptor<PartialStruct>::format(), py::format_descriptor<PartialNestedStruct>::format(),
py::format_descriptor<PartialNestedStruct>::format(), py::format_descriptor<StringStruct>::format(),
py::format_descriptor<StringStruct>::format(), py::format_descriptor<ArrayStruct>::format(),
py::format_descriptor<ArrayStruct>::format(), py::format_descriptor<EnumStruct>::format(),
py::format_descriptor<EnumStruct>::format(), py::format_descriptor<ComplexStruct>::format()}) {
py::format_descriptor<ComplexStruct>::format()
}) {
l.append(py::cast(fmt)); l.append(py::cast(fmt));
} }
return l; return l;
...@@ -373,12 +405,9 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -373,12 +405,9 @@ TEST_SUBMODULE(numpy_dtypes, m) {
// test_dtype // test_dtype
std::vector<const char *> dtype_names{ std::vector<const char *> dtype_names{
"byte", "short", "intc", "int_", "longlong", "byte", "short", "intc", "int_", "longlong", "ubyte", "ushort",
"ubyte", "ushort", "uintc", "uint", "ulonglong", "uintc", "uint", "ulonglong", "half", "single", "double", "longdouble",
"half", "single", "double", "longdouble", "csingle", "cdouble", "clongdouble", "bool_", "datetime64", "timedelta64", "object_"};
"csingle", "cdouble", "clongdouble",
"bool_", "datetime64", "timedelta64", "object_"
};
m.def("print_dtypes", []() { m.def("print_dtypes", []() {
py::list l; py::list l;
...@@ -415,9 +444,12 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -415,9 +444,12 @@ TEST_SUBMODULE(numpy_dtypes, m) {
py::list list; py::list list;
auto dt1 = py::dtype::of<int32_t>(); auto dt1 = py::dtype::of<int32_t>();
auto dt2 = py::dtype::of<SimpleStruct>(); auto dt2 = py::dtype::of<SimpleStruct>();
list.append(dt1); list.append(dt2); list.append(dt1);
list.append(py::bool_(dt1.has_fields())); list.append(py::bool_(dt2.has_fields())); list.append(dt2);
list.append(py::int_(dt1.itemsize())); list.append(py::int_(dt2.itemsize())); list.append(py::bool_(dt1.has_fields()));
list.append(py::bool_(dt2.has_fields()));
list.append(py::int_(dt1.itemsize()));
list.append(py::int_(dt2.itemsize()));
return list; return list;
}); });
struct TrailingPaddingStruct { struct TrailingPaddingStruct {
...@@ -436,14 +468,20 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -436,14 +468,20 @@ TEST_SUBMODULE(numpy_dtypes, m) {
for (py::ssize_t i = 0; i < req.size * req.itemsize; i++) { for (py::ssize_t i = 0; i < req.size * req.itemsize; i++) {
static_cast<char *>(req.ptr)[i] = 0; static_cast<char *>(req.ptr)[i] = 0;
} }
ptr[1].a[0] = 'a'; ptr[1].b[0] = 'a'; ptr[1].a[0] = 'a';
ptr[2].a[0] = 'a'; ptr[2].b[0] = 'a'; ptr[1].b[0] = 'a';
ptr[3].a[0] = 'a'; ptr[3].b[0] = 'a'; ptr[2].a[0] = 'a';
ptr[2].b[0] = 'a';
ptr[2].a[1] = 'b'; ptr[2].b[1] = 'b'; ptr[3].a[0] = 'a';
ptr[3].a[1] = 'b'; ptr[3].b[1] = 'b'; ptr[3].b[0] = 'a';
ptr[3].a[2] = 'c'; ptr[3].b[2] = 'c'; ptr[2].a[1] = 'b';
ptr[2].b[1] = 'b';
ptr[3].a[1] = 'b';
ptr[3].b[1] = 'b';
ptr[3].a[2] = 'c';
ptr[3].b[2] = 'c';
} }
return arr; return arr;
}); });
...@@ -513,14 +551,19 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -513,14 +551,19 @@ TEST_SUBMODULE(numpy_dtypes, m) {
PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z); PYBIND11_NUMPY_DTYPE(CompareStruct, x, y, z);
m.def("compare_buffer_info", []() { m.def("compare_buffer_info", []() {
py::list list; py::list list;
list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(py::buffer_info(nullptr, sizeof(float), "f", 1)))); list.append(py::bool_(py::detail::compare_buffer_info<float>::compare(
list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(py::buffer_info(nullptr, sizeof(int), "I", 1)))); py::buffer_info(nullptr, sizeof(float), "f", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), "l", 1)))); list.append(py::bool_(py::detail::compare_buffer_info<unsigned>::compare(
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1)))); py::buffer_info(nullptr, sizeof(int), "I", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1)))); list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(
py::buffer_info(nullptr, sizeof(long), "l", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<long>::compare(
py::buffer_info(nullptr, sizeof(long), sizeof(long) == sizeof(int) ? "i" : "q", 1))));
list.append(py::bool_(py::detail::compare_buffer_info<CompareStruct>::compare(
py::buffer_info(nullptr, sizeof(CompareStruct), "T{?:x:3xI:y:f:z:}", 1))));
return list; return list;
}); });
m.def("buffer_to_dtype", [](py::buffer& buf) { return py::dtype(buf.request()); }); m.def("buffer_to_dtype", [](py::buffer &buf) { return py::dtype(buf.request()); });
// test_scalar_conversion // test_scalar_conversion
auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; }; auto f_simple = [](SimpleStruct s) { return s.uint_ * 10; };
...@@ -534,7 +577,8 @@ TEST_SUBMODULE(numpy_dtypes, m) { ...@@ -534,7 +577,8 @@ TEST_SUBMODULE(numpy_dtypes, m) {
m.def("f_simple_pass_thru_vectorized", py::vectorize(f_simple_pass_thru)); m.def("f_simple_pass_thru_vectorized", py::vectorize(f_simple_pass_thru));
// test_register_dtype // test_register_dtype
m.def("register_dtype", []() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); }); m.def("register_dtype",
[]() { PYBIND11_NUMPY_DTYPE(SimpleStruct, bool_, uint_, float_, ldbl_); });
// test_str_leak // test_str_leak
m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); }); m.def("dtype_wrapper", [](py::object d) { return py::dtype::from_args(std::move(d)); });
......
...@@ -8,38 +8,43 @@ ...@@ -8,38 +8,43 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/numpy.h> #include <pybind11/numpy.h>
#include "pybind11_tests.h"
#include <utility> #include <utility>
double my_func(int x, float y, double z) { double my_func(int x, float y, double z) {
py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z)); py::print("my_func(x:int={}, y:float={:.0f}, z:float={:.0f})"_s.format(x, y, z));
return (float) x*y*z; return (float) x * y * z;
} }
TEST_SUBMODULE(numpy_vectorize, m) { TEST_SUBMODULE(numpy_vectorize, m) {
try { py::module_::import("numpy"); } try {
catch (...) { return; } py::module_::import("numpy");
} catch (...) {
return;
}
// test_vectorize, test_docs, test_array_collapse // test_vectorize, test_docs, test_array_collapse
// Vectorize all arguments of a function (though non-vector arguments are also allowed) // Vectorize all arguments of a function (though non-vector arguments are also allowed)
m.def("vectorized_func", py::vectorize(my_func)); m.def("vectorized_func", py::vectorize(my_func));
// Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the vectorization) // Vectorize a lambda function with a capture object (e.g. to exclude some arguments from the
// vectorization)
m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) { m.def("vectorized_func2", [](py::array_t<int> x, py::array_t<float> y, float z) {
return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x), return py::vectorize([z](int x, float y) { return my_func(x, y, z); })(std::move(x),
std::move(y)); std::move(y));
}); });
// Vectorize a complex-valued function // Vectorize a complex-valued function
m.def("vectorized_func3", py::vectorize( m.def("vectorized_func3",
[](std::complex<double> c) { return c * std::complex<double>(2.f); } py::vectorize([](std::complex<double> c) { return c * std::complex<double>(2.f); }));
));
// test_type_selection // test_type_selection
// NumPy function which only accepts specific data types // NumPy function which only accepts specific data types
// A lot of these no lints could be replaced with const refs, and probably should at some point. // A lot of these no lints could be replaced with const refs, and probably should at some
// point.
m.def("selective_func", m.def("selective_func",
[](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; }); [](const py::array_t<int, py::array::c_style> &) { return "Int branch taken."; });
m.def("selective_func", m.def("selective_func",
...@@ -49,8 +54,8 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -49,8 +54,8 @@ TEST_SUBMODULE(numpy_vectorize, m) {
}); });
// test_passthrough_arguments // test_passthrough_arguments
// Passthrough test: references and non-pod types should be automatically passed through (in the // Passthrough test: references and non-pod types should be automatically passed through (in
// function definition below, only `b`, `d`, and `g` are vectorized): // the function definition below, only `b`, `d`, and `g` are vectorized):
struct NonPODClass { struct NonPODClass {
explicit NonPODClass(int v) : value{v} {} explicit NonPODClass(int v) : value{v} {}
int value; int value;
...@@ -76,8 +81,7 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -76,8 +81,7 @@ TEST_SUBMODULE(numpy_vectorize, m) {
int value = 0; int value = 0;
}; };
py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass"); py::class_<VectorizeTestClass> vtc(m, "VectorizeTestClass");
vtc .def(py::init<int>()) vtc.def(py::init<int>()).def_readwrite("value", &VectorizeTestClass::value);
.def_readwrite("value", &VectorizeTestClass::value);
// Automatic vectorizing of methods // Automatic vectorizing of methods
vtc.def("method", py::vectorize(&VectorizeTestClass::method)); vtc.def("method", py::vectorize(&VectorizeTestClass::method));
...@@ -99,5 +103,5 @@ TEST_SUBMODULE(numpy_vectorize, m) { ...@@ -99,5 +103,5 @@ TEST_SUBMODULE(numpy_vectorize, m) {
return py::detail::broadcast(buffers, ndim, shape); return py::detail::broadcast(buffers, ndim, shape);
}); });
m.def("add_to", py::vectorize([](NonPODClass& x, int a) { x.value += a; })); m.def("add_to", py::vectorize([](NonPODClass &x, int a) { x.value += a; }));
} }
...@@ -7,8 +7,10 @@ ...@@ -7,8 +7,10 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "pybind11_tests.h"
#include <vector> #include <vector>
// IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures // IMPORTANT: Disable internal pybind11 translation mechanisms for STL data structures
...@@ -26,12 +28,13 @@ TEST_SUBMODULE(opaque_types, m) { ...@@ -26,12 +28,13 @@ TEST_SUBMODULE(opaque_types, m) {
.def(py::init<>()) .def(py::init<>())
.def("pop_back", &StringList::pop_back) .def("pop_back", &StringList::pop_back)
/* There are multiple versions of push_back(), etc. Select the right ones. */ /* There are multiple versions of push_back(), etc. Select the right ones. */
.def("push_back", (void (StringList::*)(const std::string &)) &StringList::push_back) .def("push_back", (void(StringList::*)(const std::string &)) & StringList::push_back)
.def("back", (std::string &(StringList::*)()) &StringList::back) .def("back", (std::string & (StringList::*) ()) & StringList::back)
.def("__len__", [](const StringList &v) { return v.size(); }) .def("__len__", [](const StringList &v) { return v.size(); })
.def("__iter__", [](StringList &v) { .def(
return py::make_iterator(v.begin(), v.end()); "__iter__",
}, py::keep_alive<0, 1>()); [](StringList &v) { return py::make_iterator(v.begin(), v.end()); },
py::keep_alive<0, 1>());
class ClassWithSTLVecProperty { class ClassWithSTLVecProperty {
public: public:
......
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include <pybind11/operators.h>
#include <pybind11/stl.h>
#include "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <functional> #include <functional>
#include <pybind11/operators.h>
#include <pybind11/stl.h>
class Vector2 { class Vector2 {
public: public:
...@@ -21,17 +23,24 @@ public: ...@@ -21,17 +23,24 @@ public:
print_move_created(this); print_move_created(this);
v.x = v.y = 0; v.x = v.y = 0;
} }
Vector2 &operator=(const Vector2 &v) { x = v.x; y = v.y; print_copy_assigned(this); return *this; } Vector2 &operator=(const Vector2 &v) {
x = v.x;
y = v.y;
print_copy_assigned(this);
return *this;
}
Vector2 &operator=(Vector2 &&v) noexcept { Vector2 &operator=(Vector2 &&v) noexcept {
x = v.x; x = v.x;
y = v.y; y = v.y;
v.x = v.y = 0; v.x = v.y = 0;
print_move_assigned(this); print_move_assigned(this);
return *this; return *this;
} }
~Vector2() { print_destroyed(this); } ~Vector2() { print_destroyed(this); }
std::string toString() const { return "[" + std::to_string(x) + ", " + std::to_string(y) + "]"; } std::string toString() const {
return "[" + std::to_string(x) + ", " + std::to_string(y) + "]";
}
Vector2 operator-() const { return Vector2(-x, -y); } Vector2 operator-() const { return Vector2(-x, -y); }
Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); } Vector2 operator+(const Vector2 &v) const { return Vector2(x + v.x, y + v.y); }
...@@ -42,30 +51,51 @@ public: ...@@ -42,30 +51,51 @@ public:
Vector2 operator/(float value) const { return Vector2(x / value, y / value); } Vector2 operator/(float value) const { return Vector2(x / value, y / value); }
Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); } Vector2 operator*(const Vector2 &v) const { return Vector2(x * v.x, y * v.y); }
Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); } Vector2 operator/(const Vector2 &v) const { return Vector2(x / v.x, y / v.y); }
Vector2& operator+=(const Vector2 &v) { x += v.x; y += v.y; return *this; } Vector2 &operator+=(const Vector2 &v) {
Vector2& operator-=(const Vector2 &v) { x -= v.x; y -= v.y; return *this; } x += v.x;
Vector2& operator*=(float v) { x *= v; y *= v; return *this; } y += v.y;
Vector2& operator/=(float v) { x /= v; y /= v; return *this; } return *this;
Vector2& operator*=(const Vector2 &v) { x *= v.x; y *= v.y; return *this; } }
Vector2& operator/=(const Vector2 &v) { x /= v.x; y /= v.y; return *this; } Vector2 &operator-=(const Vector2 &v) {
x -= v.x;
y -= v.y;
return *this;
}
Vector2 &operator*=(float v) {
x *= v;
y *= v;
return *this;
}
Vector2 &operator/=(float v) {
x /= v;
y /= v;
return *this;
}
Vector2 &operator*=(const Vector2 &v) {
x *= v.x;
y *= v.y;
return *this;
}
Vector2 &operator/=(const Vector2 &v) {
x /= v.x;
y /= v.y;
return *this;
}
friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); } friend Vector2 operator+(float f, const Vector2 &v) { return Vector2(f + v.x, f + v.y); }
friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); } friend Vector2 operator-(float f, const Vector2 &v) { return Vector2(f - v.x, f - v.y); }
friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); } friend Vector2 operator*(float f, const Vector2 &v) { return Vector2(f * v.x, f * v.y); }
friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); } friend Vector2 operator/(float f, const Vector2 &v) { return Vector2(f / v.x, f / v.y); }
bool operator==(const Vector2 &v) const { bool operator==(const Vector2 &v) const { return x == v.x && y == v.y; }
return x == v.x && y == v.y; bool operator!=(const Vector2 &v) const { return x != v.x || y != v.y; }
}
bool operator!=(const Vector2 &v) const {
return x != v.x || y != v.y;
}
private: private:
float x, y; float x, y;
}; };
class C1 { }; class C1 {};
class C2 { }; class C2 {};
int operator+(const C1 &, const C1 &) { return 11; } int operator+(const C1 &, const C1 &) { return 11; }
int operator+(const C2 &, const C2 &) { return 22; } int operator+(const C2 &, const C2 &) { return 22; }
...@@ -84,43 +114,41 @@ bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs ...@@ -84,43 +114,41 @@ bool operator==(const HashMe &lhs, const HashMe &rhs) { return lhs.member == rhs
// namespace instead, per this recommendation: // namespace instead, per this recommendation:
// https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations // https://en.cppreference.com/w/cpp/language/extending_std#Adding_template_specializations
namespace std { namespace std {
template<> template <>
struct hash<Vector2> { struct hash<Vector2> {
// Not a good hash function, but easy to test // Not a good hash function, but easy to test
size_t operator()(const Vector2 &) { return 4; } size_t operator()(const Vector2 &) { return 4; }
}; };
// HashMe has a hash function in C++ but no `__hash__` for Python. // HashMe has a hash function in C++ but no `__hash__` for Python.
template <> template <>
struct hash<HashMe> { struct hash<HashMe> {
std::size_t operator()(const HashMe &selector) const { std::size_t operator()(const HashMe &selector) const {
return std::hash<std::string>()(selector.member); return std::hash<std::string>()(selector.member);
} }
}; };
} // namespace std } // namespace std
// Not a good abs function, but easy to test. // Not a good abs function, but easy to test.
std::string abs(const Vector2&) { std::string abs(const Vector2 &) { return "abs(Vector2)"; }
return "abs(Vector2)";
}
// MSVC & Intel warns about unknown pragmas, and warnings are errors. // MSVC & Intel warns about unknown pragmas, and warnings are errors.
#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) #if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#pragma GCC diagnostic push # pragma GCC diagnostic push
// clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to // clang 7.0.0 and Apple LLVM 10.0.1 introduce `-Wself-assign-overloaded` to
// `-Wall`, which is used here for overloading (e.g. `py::self += py::self `). // `-Wall`, which is used here for overloading (e.g. `py::self += py::self `).
// Here, we suppress the warning using `#pragma diagnostic`. // Here, we suppress the warning using `#pragma diagnostic`.
// Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46 // Taken from: https://github.com/RobotLocomotion/drake/commit/aaf84b46
// TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`). // TODO(eric): This could be resolved using a function / functor (e.g. `py::self()`).
#if defined(__APPLE__) && defined(__clang__) # if defined(__APPLE__) && defined(__clang__)
#if (__clang_major__ >= 10) # if (__clang_major__ >= 10)
#pragma GCC diagnostic ignored "-Wself-assign-overloaded" # pragma GCC diagnostic ignored "-Wself-assign-overloaded"
#endif # endif
#elif defined(__clang__) # elif defined(__clang__)
#if (__clang_major__ >= 7) # if (__clang_major__ >= 7)
#pragma GCC diagnostic ignored "-Wself-assign-overloaded" # pragma GCC diagnostic ignored "-Wself-assign-overloaded"
#endif # endif
#endif # endif
#endif #endif
TEST_SUBMODULE(operators, m) { TEST_SUBMODULE(operators, m) {
...@@ -154,46 +182,52 @@ TEST_SUBMODULE(operators, m) { ...@@ -154,46 +182,52 @@ TEST_SUBMODULE(operators, m) {
.def(py::hash(py::self)) .def(py::hash(py::self))
// N.B. See warning about usage of `py::detail::abs(py::self)` in // N.B. See warning about usage of `py::detail::abs(py::self)` in
// `operators.h`. // `operators.h`.
.def("__abs__", [](const Vector2& v) { return abs(v); }) .def("__abs__", [](const Vector2 &v) { return abs(v); });
;
m.attr("Vector") = m.attr("Vector2"); m.attr("Vector") = m.attr("Vector2");
// test_operators_notimplemented // test_operators_notimplemented
// #393: need to return NotSupported to ensure correct arithmetic operator behavior // #393: need to return NotSupported to ensure correct arithmetic operator behavior
py::class_<C1>(m, "C1") py::class_<C1>(m, "C1").def(py::init<>()).def(py::self + py::self);
.def(py::init<>())
.def(py::self + py::self);
py::class_<C2>(m, "C2") py::class_<C2>(m, "C2")
.def(py::init<>()) .def(py::init<>())
.def(py::self + py::self) .def(py::self + py::self)
.def("__add__", [](const C2& c2, const C1& c1) { return c2 + c1; }) .def("__add__", [](const C2 &c2, const C1 &c1) { return c2 + c1; })
.def("__radd__", [](const C2& c2, const C1& c1) { return c1 + c2; }); .def("__radd__", [](const C2 &c2, const C1 &c1) { return c1 + c2; });
// test_nested // test_nested
// #328: first member in a class can't be used in operators // #328: first member in a class can't be used in operators
struct NestABase { int value = -2; }; struct NestABase {
int value = -2;
};
py::class_<NestABase>(m, "NestABase") py::class_<NestABase>(m, "NestABase")
.def(py::init<>()) .def(py::init<>())
.def_readwrite("value", &NestABase::value); .def_readwrite("value", &NestABase::value);
struct NestA : NestABase { struct NestA : NestABase {
int value = 3; int value = 3;
NestA& operator+=(int i) { value += i; return *this; } NestA &operator+=(int i) {
value += i;
return *this;
}
}; };
py::class_<NestA>(m, "NestA") py::class_<NestA>(m, "NestA")
.def(py::init<>()) .def(py::init<>())
.def(py::self += int()) .def(py::self += int())
.def("as_base", [](NestA &a) -> NestABase& { .def(
return (NestABase&) a; "as_base",
}, py::return_value_policy::reference_internal); [](NestA &a) -> NestABase & { return (NestABase &) a; },
py::return_value_policy::reference_internal);
m.def("get_NestA", [](const NestA &a) { return a.value; }); m.def("get_NestA", [](const NestA &a) { return a.value; });
struct NestB { struct NestB {
NestA a; NestA a;
int value = 4; int value = 4;
NestB& operator-=(int i) { value -= i; return *this; } NestB &operator-=(int i) {
value -= i;
return *this;
}
}; };
py::class_<NestB>(m, "NestB") py::class_<NestB>(m, "NestB")
.def(py::init<>()) .def(py::init<>())
...@@ -204,7 +238,10 @@ TEST_SUBMODULE(operators, m) { ...@@ -204,7 +238,10 @@ TEST_SUBMODULE(operators, m) {
struct NestC { struct NestC {
NestB b; NestB b;
int value = 5; int value = 5;
NestC& operator*=(int i) { value *= i; return *this; } NestC &operator*=(int i) {
value *= i;
return *this;
}
}; };
py::class_<NestC>(m, "NestC") py::class_<NestC>(m, "NestC")
.def(py::init<>()) .def(py::init<>())
...@@ -212,16 +249,15 @@ TEST_SUBMODULE(operators, m) { ...@@ -212,16 +249,15 @@ TEST_SUBMODULE(operators, m) {
.def_readwrite("b", &NestC::b); .def_readwrite("b", &NestC::b);
m.def("get_NestC", [](const NestC &c) { return c.value; }); m.def("get_NestC", [](const NestC &c) { return c.value; });
// test_overriding_eq_reset_hash // test_overriding_eq_reset_hash
// #2191 Overriding __eq__ should set __hash__ to None // #2191 Overriding __eq__ should set __hash__ to None
struct Comparable { struct Comparable {
int value; int value;
bool operator==(const Comparable& rhs) const {return value == rhs.value;} bool operator==(const Comparable &rhs) const { return value == rhs.value; }
}; };
struct Hashable : Comparable { struct Hashable : Comparable {
explicit Hashable(int value): Comparable{value}{}; explicit Hashable(int value) : Comparable{value} {};
size_t hash() const { return static_cast<size_t>(value); } size_t hash() const { return static_cast<size_t>(value); }
}; };
...@@ -229,9 +265,7 @@ TEST_SUBMODULE(operators, m) { ...@@ -229,9 +265,7 @@ TEST_SUBMODULE(operators, m) {
using Hashable::Hashable; using Hashable::Hashable;
}; };
py::class_<Comparable>(m, "Comparable") py::class_<Comparable>(m, "Comparable").def(py::init<int>()).def(py::self == py::self);
.def(py::init<int>())
.def(py::self == py::self);
py::class_<Hashable>(m, "Hashable") py::class_<Hashable>(m, "Hashable")
.def(py::init<int>()) .def(py::init<int>())
...@@ -250,5 +284,5 @@ TEST_SUBMODULE(operators, m) { ...@@ -250,5 +284,5 @@ TEST_SUBMODULE(operators, m) {
m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; }); m.def("get_unhashable_HashMe_set", []() { return std::unordered_set<HashMe>{{"one"}}; });
} }
#if !defined(_MSC_VER) && !defined(__INTEL_COMPILER) #if !defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
...@@ -20,11 +20,11 @@ ...@@ -20,11 +20,11 @@
namespace exercise_trampoline { namespace exercise_trampoline {
struct SimpleBase { struct SimpleBase {
int num = 0; int num = 0;
virtual ~SimpleBase() = default; virtual ~SimpleBase() = default;
// For compatibility with old clang versions: // For compatibility with old clang versions:
SimpleBase() = default; SimpleBase() = default;
SimpleBase(const SimpleBase &) = default; SimpleBase(const SimpleBase &) = default;
}; };
...@@ -50,7 +50,7 @@ void wrap(py::module m) { ...@@ -50,7 +50,7 @@ void wrap(py::module m) {
} }
auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline); auto cpp_state = std::unique_ptr<SimpleBase>(new SimpleBaseTrampoline);
cpp_state->num = t[0].cast<int>(); cpp_state->num = t[0].cast<int>();
auto py_state = t[1].cast<py::dict>(); auto py_state = t[1].cast<py::dict>();
return std::make_pair(std::move(cpp_state), py_state); return std::make_pair(std::move(cpp_state), py_state);
})); }));
......
...@@ -7,22 +7,21 @@ ...@@ -7,22 +7,21 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include <utility>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <utility>
TEST_SUBMODULE(pytypes, m) { TEST_SUBMODULE(pytypes, m) {
// test_bool // test_bool
m.def("get_bool", []{return py::bool_(false);}); m.def("get_bool", [] { return py::bool_(false); });
// test_int // test_int
m.def("get_int", []{return py::int_(0);}); m.def("get_int", [] { return py::int_(0); });
// test_iterator // test_iterator
m.def("get_iterator", []{return py::iterator();}); m.def("get_iterator", [] { return py::iterator(); });
// test_iterable // test_iterable
m.def("get_iterable", []{return py::iterable();}); m.def("get_iterable", [] { return py::iterable(); });
// test_float // test_float
m.def("get_float", []{return py::float_(0.0f);}); m.def("get_float", [] { return py::float_(0.0f); });
// test_list // test_list
m.def("list_no_args", []() { return py::list{}; }); m.def("list_no_args", []() { return py::list{}; });
m.def("list_ssize_t", []() { return py::list{(py::ssize_t) 0}; }); m.def("list_ssize_t", []() { return py::list{(py::ssize_t) 0}; });
...@@ -45,7 +44,7 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -45,7 +44,7 @@ TEST_SUBMODULE(pytypes, m) {
} }
}); });
// test_none // test_none
m.def("get_none", []{return py::none();}); m.def("get_none", [] { return py::none(); });
m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); }); m.def("print_none", [](const py::none &none) { py::print("none: {}"_s.format(none)); });
// test_set // test_set
...@@ -66,15 +65,15 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -66,15 +65,15 @@ TEST_SUBMODULE(pytypes, m) {
m.def("set_contains", [](const py::set &set, const char *key) { return set.contains(key); }); m.def("set_contains", [](const py::set &set, const char *key) { return set.contains(key); });
// test_dict // test_dict
m.def("get_dict", []() { return py::dict("key"_a="value"); }); m.def("get_dict", []() { return py::dict("key"_a = "value"); });
m.def("print_dict", [](const py::dict &dict) { m.def("print_dict", [](const py::dict &dict) {
for (auto item : dict) { for (auto item : dict) {
py::print("key: {}, value={}"_s.format(item.first, item.second)); py::print("key: {}, value={}"_s.format(item.first, item.second));
} }
}); });
m.def("dict_keyword_constructor", []() { m.def("dict_keyword_constructor", []() {
auto d1 = py::dict("x"_a=1, "y"_a=2); auto d1 = py::dict("x"_a = 1, "y"_a = 2);
auto d2 = py::dict("z"_a=3, **d1); auto d2 = py::dict("z"_a = 3, **d1);
return d2; return d2;
}); });
m.def("dict_contains", m.def("dict_contains",
...@@ -91,7 +90,8 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -91,7 +90,8 @@ TEST_SUBMODULE(pytypes, m) {
#if PY_VERSION_HEX >= 0x03030000 #if PY_VERSION_HEX >= 0x03030000
// test_simple_namespace // test_simple_namespace
m.def("get_simple_namespace", []() { m.def("get_simple_namespace", []() {
auto ns = py::module_::import("types").attr("SimpleNamespace")("attr"_a=42, "x"_a="foo", "wrong"_a=1); auto ns = py::module_::import("types").attr("SimpleNamespace")(
"attr"_a = 42, "x"_a = "foo", "wrong"_a = 1);
py::delattr(ns, "wrong"); py::delattr(ns, "wrong");
py::setattr(ns, "right", py::int_(2)); py::setattr(ns, "right", py::int_(2));
return ns; return ns;
...@@ -103,16 +103,15 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -103,16 +103,15 @@ TEST_SUBMODULE(pytypes, m) {
m.def("str_from_char_size_t", []() { return py::str{"blue", (py::size_t) 4}; }); m.def("str_from_char_size_t", []() { return py::str{"blue", (py::size_t) 4}; });
m.def("str_from_string", []() { return py::str(std::string("baz")); }); m.def("str_from_string", []() { return py::str(std::string("baz")); });
m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); }); m.def("str_from_bytes", []() { return py::str(py::bytes("boo", 3)); });
m.def("str_from_object", [](const py::object& obj) { return py::str(obj); }); m.def("str_from_object", [](const py::object &obj) { return py::str(obj); });
m.def("repr_from_object", [](const py::object& obj) { return py::repr(obj); }); m.def("repr_from_object", [](const py::object &obj) { return py::repr(obj); });
m.def("str_from_handle", [](py::handle h) { return py::str(h); }); m.def("str_from_handle", [](py::handle h) { return py::str(h); });
m.def("str_from_string_from_str", [](const py::str& obj) { m.def("str_from_string_from_str",
return py::str(static_cast<std::string>(obj)); [](const py::str &obj) { return py::str(static_cast<std::string>(obj)); });
});
m.def("str_format", []() { m.def("str_format", []() {
auto s1 = "{} + {} = {}"_s.format(1, 2, 3); auto s1 = "{} + {} = {}"_s.format(1, 2, 3);
auto s2 = "{a} + {b} = {c}"_s.format("a"_a=1, "b"_a=2, "c"_a=3); auto s2 = "{a} + {b} = {c}"_s.format("a"_a = 1, "b"_a = 2, "c"_a = 3);
return py::make_tuple(s1, s2); return py::make_tuple(s1, s2);
}); });
...@@ -131,9 +130,7 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -131,9 +130,7 @@ TEST_SUBMODULE(pytypes, m) {
// test_capsule // test_capsule
m.def("return_capsule_with_destructor", []() { m.def("return_capsule_with_destructor", []() {
py::print("creating capsule"); py::print("creating capsule");
return py::capsule([]() { return py::capsule([]() { py::print("destructing capsule"); });
py::print("destructing capsule");
});
}); });
m.def("return_capsule_with_destructor_2", []() { m.def("return_capsule_with_destructor_2", []() {
...@@ -148,23 +145,23 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -148,23 +145,23 @@ TEST_SUBMODULE(pytypes, m) {
if (ptr) { if (ptr) {
const auto *name = PyCapsule_GetName(ptr); const auto *name = PyCapsule_GetName(ptr);
py::print("destructing capsule ({}, '{}')"_s.format( py::print("destructing capsule ({}, '{}')"_s.format(
(size_t) PyCapsule_GetPointer(ptr, name), name (size_t) PyCapsule_GetPointer(ptr, name), name));
));
} }
}); });
capsule.set_pointer((void *) 1234); capsule.set_pointer((void *) 1234);
// Using get_pointer<T>() // Using get_pointer<T>()
void* contents1 = static_cast<void*>(capsule); void *contents1 = static_cast<void *>(capsule);
void* contents2 = capsule.get_pointer(); void *contents2 = capsule.get_pointer();
void* contents3 = capsule.get_pointer<void>(); void *contents3 = capsule.get_pointer<void>();
auto result1 = reinterpret_cast<size_t>(contents1); auto result1 = reinterpret_cast<size_t>(contents1);
auto result2 = reinterpret_cast<size_t>(contents2); auto result2 = reinterpret_cast<size_t>(contents2);
auto result3 = reinterpret_cast<size_t>(contents3); auto result3 = reinterpret_cast<size_t>(contents3);
py::print("created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name())); py::print(
"created capsule ({}, '{}')"_s.format(result1 & result2 & result3, capsule.name()));
return capsule; return capsule;
}); });
...@@ -244,51 +241,45 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -244,51 +241,45 @@ TEST_SUBMODULE(pytypes, m) {
// test_constructors // test_constructors
m.def("default_constructors", []() { m.def("default_constructors", []() {
return py::dict( return py::dict("bytes"_a = py::bytes(),
"bytes"_a=py::bytes(), "bytearray"_a = py::bytearray(),
"bytearray"_a=py::bytearray(), "str"_a = py::str(),
"str"_a=py::str(), "bool"_a = py::bool_(),
"bool"_a=py::bool_(), "int"_a = py::int_(),
"int"_a=py::int_(), "float"_a = py::float_(),
"float"_a=py::float_(), "tuple"_a = py::tuple(),
"tuple"_a=py::tuple(), "list"_a = py::list(),
"list"_a=py::list(), "dict"_a = py::dict(),
"dict"_a=py::dict(), "set"_a = py::set());
"set"_a=py::set()
);
}); });
m.def("converting_constructors", [](const py::dict &d) { m.def("converting_constructors", [](const py::dict &d) {
return py::dict( return py::dict("bytes"_a = py::bytes(d["bytes"]),
"bytes"_a=py::bytes(d["bytes"]), "bytearray"_a = py::bytearray(d["bytearray"]),
"bytearray"_a=py::bytearray(d["bytearray"]), "str"_a = py::str(d["str"]),
"str"_a=py::str(d["str"]), "bool"_a = py::bool_(d["bool"]),
"bool"_a=py::bool_(d["bool"]), "int"_a = py::int_(d["int"]),
"int"_a=py::int_(d["int"]), "float"_a = py::float_(d["float"]),
"float"_a=py::float_(d["float"]), "tuple"_a = py::tuple(d["tuple"]),
"tuple"_a=py::tuple(d["tuple"]), "list"_a = py::list(d["list"]),
"list"_a=py::list(d["list"]), "dict"_a = py::dict(d["dict"]),
"dict"_a=py::dict(d["dict"]), "set"_a = py::set(d["set"]),
"set"_a=py::set(d["set"]), "memoryview"_a = py::memoryview(d["memoryview"]));
"memoryview"_a=py::memoryview(d["memoryview"])
);
}); });
m.def("cast_functions", [](const py::dict &d) { m.def("cast_functions", [](const py::dict &d) {
// When converting between Python types, obj.cast<T>() should be the same as T(obj) // When converting between Python types, obj.cast<T>() should be the same as T(obj)
return py::dict( return py::dict("bytes"_a = d["bytes"].cast<py::bytes>(),
"bytes"_a=d["bytes"].cast<py::bytes>(), "bytearray"_a = d["bytearray"].cast<py::bytearray>(),
"bytearray"_a=d["bytearray"].cast<py::bytearray>(), "str"_a = d["str"].cast<py::str>(),
"str"_a=d["str"].cast<py::str>(), "bool"_a = d["bool"].cast<py::bool_>(),
"bool"_a=d["bool"].cast<py::bool_>(), "int"_a = d["int"].cast<py::int_>(),
"int"_a=d["int"].cast<py::int_>(), "float"_a = d["float"].cast<py::float_>(),
"float"_a=d["float"].cast<py::float_>(), "tuple"_a = d["tuple"].cast<py::tuple>(),
"tuple"_a=d["tuple"].cast<py::tuple>(), "list"_a = d["list"].cast<py::list>(),
"list"_a=d["list"].cast<py::list>(), "dict"_a = d["dict"].cast<py::dict>(),
"dict"_a=d["dict"].cast<py::dict>(), "set"_a = d["set"].cast<py::set>(),
"set"_a=d["set"].cast<py::set>(), "memoryview"_a = d["memoryview"].cast<py::memoryview>());
"memoryview"_a=d["memoryview"].cast<py::memoryview>()
);
}); });
m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); }); m.def("convert_to_pybind11_str", [](const py::object &o) { return py::str(o); });
...@@ -341,10 +332,7 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -341,10 +332,7 @@ TEST_SUBMODULE(pytypes, m) {
l.append(py::cast(12)); l.append(py::cast(12));
l.append(py::int_(15)); l.append(py::int_(15));
return py::dict( return py::dict("d"_a = d, "l"_a = l);
"d"_a=d,
"l"_a=l
);
}); });
// test_print // test_print
...@@ -352,16 +340,17 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -352,16 +340,17 @@ TEST_SUBMODULE(pytypes, m) {
py::print("Hello, World!"); py::print("Hello, World!");
py::print(1, 2.0, "three", true, std::string("-- multiple args")); py::print(1, 2.0, "three", true, std::string("-- multiple args"));
auto args = py::make_tuple("and", "a", "custom", "separator"); auto args = py::make_tuple("and", "a", "custom", "separator");
py::print("*args", *args, "sep"_a="-"); py::print("*args", *args, "sep"_a = "-");
py::print("no new line here", "end"_a=" -- "); py::print("no new line here", "end"_a = " -- ");
py::print("next print"); py::print("next print");
auto py_stderr = py::module_::import("sys").attr("stderr"); auto py_stderr = py::module_::import("sys").attr("stderr");
py::print("this goes to stderr", "file"_a=py_stderr); py::print("this goes to stderr", "file"_a = py_stderr);
py::print("flush", "flush"_a=true); py::print("flush", "flush"_a = true);
py::print("{a} + {b} = {c}"_s.format("a"_a="py::print", "b"_a="str.format", "c"_a="this")); py::print(
"{a} + {b} = {c}"_s.format("a"_a = "py::print", "b"_a = "str.format", "c"_a = "this"));
}); });
m.def("print_failure", []() { py::print(42, UnregisteredType()); }); m.def("print_failure", []() { py::print(42, UnregisteredType()); });
...@@ -406,8 +395,8 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -406,8 +395,8 @@ TEST_SUBMODULE(pytypes, m) {
[](const py::buffer &b) { return py::memoryview(b.request()); }); [](const py::buffer &b) { return py::memoryview(b.request()); });
m.def("test_memoryview_from_buffer", [](bool is_unsigned) { m.def("test_memoryview_from_buffer", [](bool is_unsigned) {
static const int16_t si16[] = { 3, 1, 4, 1, 5 }; static const int16_t si16[] = {3, 1, 4, 1, 5};
static const uint16_t ui16[] = { 2, 7, 1, 8 }; static const uint16_t ui16[] = {2, 7, 1, 8};
if (is_unsigned) { if (is_unsigned) {
return py::memoryview::from_buffer(ui16, {4}, {sizeof(uint16_t)}); return py::memoryview::from_buffer(ui16, {4}, {sizeof(uint16_t)});
} }
...@@ -415,32 +404,29 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -415,32 +404,29 @@ TEST_SUBMODULE(pytypes, m) {
}); });
m.def("test_memoryview_from_buffer_nativeformat", []() { m.def("test_memoryview_from_buffer_nativeformat", []() {
static const char* format = "@i"; static const char *format = "@i";
static const int32_t arr[] = { 4, 7, 5 }; static const int32_t arr[] = {4, 7, 5};
return py::memoryview::from_buffer( return py::memoryview::from_buffer(arr, sizeof(int32_t), format, {3}, {sizeof(int32_t)});
arr, sizeof(int32_t), format, { 3 }, { sizeof(int32_t) });
}); });
m.def("test_memoryview_from_buffer_empty_shape", []() { m.def("test_memoryview_from_buffer_empty_shape", []() {
static const char* buf = ""; static const char *buf = "";
return py::memoryview::from_buffer(buf, 1, "B", { }, { }); return py::memoryview::from_buffer(buf, 1, "B", {}, {});
}); });
m.def("test_memoryview_from_buffer_invalid_strides", []() { m.def("test_memoryview_from_buffer_invalid_strides", []() {
static const char* buf = "\x02\x03\x04"; static const char *buf = "\x02\x03\x04";
return py::memoryview::from_buffer(buf, 1, "B", { 3 }, { }); return py::memoryview::from_buffer(buf, 1, "B", {3}, {});
}); });
m.def("test_memoryview_from_buffer_nullptr", []() { m.def("test_memoryview_from_buffer_nullptr", []() {
return py::memoryview::from_buffer( return py::memoryview::from_buffer(static_cast<void *>(nullptr), 1, "B", {}, {});
static_cast<void*>(nullptr), 1, "B", { }, { });
}); });
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
m.def("test_memoryview_from_memory", []() { m.def("test_memoryview_from_memory", []() {
const char* buf = "\xff\xe1\xab\x37"; const char *buf = "\xff\xe1\xab\x37";
return py::memoryview::from_memory( return py::memoryview::from_memory(buf, static_cast<py::ssize_t>(strlen(buf)));
buf, static_cast<py::ssize_t>(strlen(buf)));
}); });
#endif #endif
...@@ -461,8 +447,7 @@ TEST_SUBMODULE(pytypes, m) { ...@@ -461,8 +447,7 @@ TEST_SUBMODULE(pytypes, m) {
m.def("pass_to_std_string", [](const std::string &s) { return s.size(); }); m.def("pass_to_std_string", [](const std::string &s) { return s.size(); });
// test_weakref // test_weakref
m.def("weakref_from_handle", m.def("weakref_from_handle", [](py::handle h) { return py::weakref(h); });
[](py::handle h) { return py::weakref(h); });
m.def("weakref_from_handle_and_function", m.def("weakref_from_handle_and_function",
[](py::handle h, py::function f) { return py::weakref(h, std::move(f)); }); [](py::handle h, py::function f) { return py::weakref(h, std::move(f)); });
m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); }); m.def("weakref_from_object", [](const py::object &o) { return py::weakref(o); });
......
...@@ -8,44 +8,52 @@ ...@@ -8,44 +8,52 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/operators.h> #include <pybind11/operators.h>
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <vector> #include <vector>
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
#include <optional> # include <optional>
#endif // PYBIND11_HAS_OPTIONAL #endif // PYBIND11_HAS_OPTIONAL
template<typename T> template <typename T>
class NonZeroIterator { class NonZeroIterator {
const T* ptr_; const T *ptr_;
public: public:
explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {} explicit NonZeroIterator(const T *ptr) : ptr_(ptr) {}
const T& operator*() const { return *ptr_; } const T &operator*() const { return *ptr_; }
NonZeroIterator& operator++() { ++ptr_; return *this; } NonZeroIterator &operator++() {
++ptr_;
return *this;
}
}; };
class NonZeroSentinel {}; class NonZeroSentinel {};
template<typename A, typename B> template <typename A, typename B>
bool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentinel&) { bool operator==(const NonZeroIterator<std::pair<A, B>> &it, const NonZeroSentinel &) {
return !(*it).first || !(*it).second; return !(*it).first || !(*it).second;
} }
/* Iterator where dereferencing returns prvalues instead of references. */ /* Iterator where dereferencing returns prvalues instead of references. */
template<typename T> template <typename T>
class NonRefIterator { class NonRefIterator {
const T* ptr_; const T *ptr_;
public: public:
explicit NonRefIterator(const T *ptr) : ptr_(ptr) {} explicit NonRefIterator(const T *ptr) : ptr_(ptr) {}
T operator*() const { return T(*ptr_); } T operator*() const { return T(*ptr_); }
NonRefIterator& operator++() { ++ptr_; return *this; } NonRefIterator &operator++() {
++ptr_;
return *this;
}
bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; } bool operator==(const NonRefIterator &other) const { return ptr_ == other.ptr_; }
}; };
...@@ -54,17 +62,18 @@ public: ...@@ -54,17 +62,18 @@ public:
explicit NonCopyableInt(int value) : value_(value) {} explicit NonCopyableInt(int value) : value_(value) {}
NonCopyableInt(const NonCopyableInt &) = delete; NonCopyableInt(const NonCopyableInt &) = delete;
NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) { NonCopyableInt(NonCopyableInt &&other) noexcept : value_(other.value_) {
other.value_ = -1; // detect when an unwanted move occurs other.value_ = -1; // detect when an unwanted move occurs
} }
NonCopyableInt &operator=(const NonCopyableInt &) = delete; NonCopyableInt &operator=(const NonCopyableInt &) = delete;
NonCopyableInt &operator=(NonCopyableInt &&other) noexcept { NonCopyableInt &operator=(NonCopyableInt &&other) noexcept {
value_ = other.value_; value_ = other.value_;
other.value_ = -1; // detect when an unwanted move occurs other.value_ = -1; // detect when an unwanted move occurs
return *this; return *this;
} }
int get() const { return value_; } int get() const { return value_; }
void set(int value) { value_ = value; } void set(int value) { value_ = value; }
~NonCopyableInt() = default; ~NonCopyableInt() = default;
private: private:
int value_; int value_;
}; };
...@@ -81,7 +90,9 @@ py::list test_random_access_iterator(PythonType x) { ...@@ -81,7 +90,9 @@ py::list test_random_access_iterator(PythonType x) {
auto checks = py::list(); auto checks = py::list();
auto assert_equal = [&checks](py::handle a, py::handle b) { auto assert_equal = [&checks](py::handle a, py::handle b) {
auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ); auto result = PyObject_RichCompareBool(a.ptr(), b.ptr(), Py_EQ);
if (result == -1) { throw py::error_already_set(); } if (result == -1) {
throw py::error_already_set();
}
checks.append(result != 0); checks.append(result != 0);
}; };
...@@ -116,7 +127,7 @@ py::list test_random_access_iterator(PythonType x) { ...@@ -116,7 +127,7 @@ py::list test_random_access_iterator(PythonType x) {
TEST_SUBMODULE(sequences_and_iterators, m) { TEST_SUBMODULE(sequences_and_iterators, m) {
// test_sliceable // test_sliceable
class Sliceable{ class Sliceable {
public: public:
explicit Sliceable(int n) : size(n) {} explicit Sliceable(int n) : size(n) {}
int start, stop, step; int start, stop, step;
...@@ -130,18 +141,20 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -130,18 +141,20 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
throw py::error_already_set(); throw py::error_already_set();
} }
int istart = static_cast<int>(start); int istart = static_cast<int>(start);
int istop = static_cast<int>(stop); int istop = static_cast<int>(stop);
int istep = static_cast<int>(step); int istep = static_cast<int>(step);
return std::make_tuple(istart, istop, istep); return std::make_tuple(istart, istop, istep);
}); });
m.def("make_forward_slice_size_t", []() { return py::slice(0, -1, 1); }); m.def("make_forward_slice_size_t", []() { return py::slice(0, -1, 1); });
m.def("make_reversed_slice_object", []() { return py::slice(py::none(), py::none(), py::int_(-1)); }); m.def("make_reversed_slice_object",
[]() { return py::slice(py::none(), py::none(), py::int_(-1)); });
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
m.attr("has_optional") = true; m.attr("has_optional") = true;
m.def("make_reversed_slice_size_t_optional_verbose", []() { return py::slice(std::nullopt, std::nullopt, -1); }); m.def("make_reversed_slice_size_t_optional_verbose",
// Warning: The following spelling may still compile if optional<> is not present and give wrong answers. []() { return py::slice(std::nullopt, std::nullopt, -1); });
// Please use with caution. // Warning: The following spelling may still compile if optional<> is not present and give
// wrong answers. Please use with caution.
m.def("make_reversed_slice_size_t_optional", []() { return py::slice({}, {}, -1); }); m.def("make_reversed_slice_size_t_optional", []() { return py::slice({}, {}, -1); });
#else #else
m.attr("has_optional") = false; m.attr("has_optional") = false;
...@@ -166,7 +179,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -166,7 +179,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
print_copy_created(this); print_copy_created(this);
// NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer) // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
m_data = new float[m_size]; m_data = new float[m_size];
memcpy(m_data, s.m_data, sizeof(float)*m_size); memcpy(m_data, s.m_data, sizeof(float) * m_size);
} }
Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) { Sequence(Sequence &&s) noexcept : m_size(s.m_size), m_data(s.m_data) {
print_move_created(this); print_move_created(this);
...@@ -174,14 +187,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -174,14 +187,17 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
s.m_data = nullptr; s.m_data = nullptr;
} }
~Sequence() { print_destroyed(this); delete[] m_data; } ~Sequence() {
print_destroyed(this);
delete[] m_data;
}
Sequence &operator=(const Sequence &s) { Sequence &operator=(const Sequence &s) {
if (&s != this) { if (&s != this) {
delete[] m_data; delete[] m_data;
m_size = s.m_size; m_size = s.m_size;
m_data = new float[m_size]; m_data = new float[m_size];
memcpy(m_data, s.m_data, sizeof(float)*m_size); memcpy(m_data, s.m_data, sizeof(float) * m_size);
} }
print_copy_assigned(this); print_copy_assigned(this);
return *this; return *this;
...@@ -235,7 +251,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -235,7 +251,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
size_t size() const { return m_size; } size_t size() const { return m_size; }
const float *begin() const { return m_data; } const float *begin() const { return m_data; }
const float *end() const { return m_data+m_size; } const float *end() const { return m_data + m_size; }
private: private:
size_t m_size; size_t m_size;
...@@ -303,8 +319,8 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -303,8 +319,8 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
; ;
// test_map_iterator // test_map_iterator
// Interface of a map-like object that isn't (directly) an unordered_map, but provides some basic // Interface of a map-like object that isn't (directly) an unordered_map, but provides some
// map-like functionality. // basic map-like functionality.
class StringMap { class StringMap {
public: public:
StringMap() = default; StringMap() = default;
...@@ -314,8 +330,10 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -314,8 +330,10 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
void set(const std::string &key, std::string val) { map[key] = std::move(val); } void set(const std::string &key, std::string val) { map[key] = std::move(val); }
std::string get(const std::string &key) const { return map.at(key); } std::string get(const std::string &key) const { return map.at(key); }
size_t size() const { return map.size(); } size_t size() const { return map.size(); }
private: private:
std::unordered_map<std::string, std::string> map; std::unordered_map<std::string, std::string> map;
public: public:
decltype(map.cbegin()) begin() const { return map.cbegin(); } decltype(map.cbegin()) begin() const { return map.cbegin(); }
decltype(map.cend()) end() const { return map.cend(); } decltype(map.cend()) end() const { return map.cend(); }
...@@ -350,90 +368,115 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -350,90 +368,115 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
class IntPairs { class IntPairs {
public: public:
explicit IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {} explicit IntPairs(std::vector<std::pair<int, int>> data) : data_(std::move(data)) {}
const std::pair<int, int>* begin() const { return data_.data(); } const std::pair<int, int> *begin() const { return data_.data(); }
// .end() only required for py::make_iterator(self) overload // .end() only required for py::make_iterator(self) overload
const std::pair<int, int>* end() const { return data_.data() + data_.size(); } const std::pair<int, int> *end() const { return data_.data() + data_.size(); }
private: private:
std::vector<std::pair<int, int>> data_; std::vector<std::pair<int, int>> data_;
}; };
py::class_<IntPairs>(m, "IntPairs") py::class_<IntPairs>(m, "IntPairs")
.def(py::init<std::vector<std::pair<int, int>>>()) .def(py::init<std::vector<std::pair<int, int>>>())
.def("nonzero", [](const IntPairs& s) { .def(
return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); "nonzero",
}, py::keep_alive<0, 1>()) [](const IntPairs &s) {
.def("nonzero_keys", [](const IntPairs& s) { return py::make_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); NonZeroSentinel());
}, py::keep_alive<0, 1>()) },
.def("nonzero_values", [](const IntPairs& s) { py::keep_alive<0, 1>())
return py::make_value_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()), NonZeroSentinel()); .def(
}, py::keep_alive<0, 1>()) "nonzero_keys",
[](const IntPairs &s) {
return py::make_key_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
NonZeroSentinel());
},
py::keep_alive<0, 1>())
.def(
"nonzero_values",
[](const IntPairs &s) {
return py::make_value_iterator(NonZeroIterator<std::pair<int, int>>(s.begin()),
NonZeroSentinel());
},
py::keep_alive<0, 1>())
// test iterator that returns values instead of references // test iterator that returns values instead of references
.def("nonref", [](const IntPairs& s) { .def(
return py::make_iterator(NonRefIterator<std::pair<int, int>>(s.begin()), "nonref",
NonRefIterator<std::pair<int, int>>(s.end())); [](const IntPairs &s) {
}, py::keep_alive<0, 1>()) return py::make_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
.def("nonref_keys", [](const IntPairs& s) { NonRefIterator<std::pair<int, int>>(s.end()));
return py::make_key_iterator(NonRefIterator<std::pair<int, int>>(s.begin()), },
NonRefIterator<std::pair<int, int>>(s.end())); py::keep_alive<0, 1>())
}, py::keep_alive<0, 1>()) .def(
.def("nonref_values", [](const IntPairs& s) { "nonref_keys",
return py::make_value_iterator(NonRefIterator<std::pair<int, int>>(s.begin()), [](const IntPairs &s) {
NonRefIterator<std::pair<int, int>>(s.end())); return py::make_key_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
}, py::keep_alive<0, 1>()) NonRefIterator<std::pair<int, int>>(s.end()));
},
py::keep_alive<0, 1>())
.def(
"nonref_values",
[](const IntPairs &s) {
return py::make_value_iterator(NonRefIterator<std::pair<int, int>>(s.begin()),
NonRefIterator<std::pair<int, int>>(s.end()));
},
py::keep_alive<0, 1>())
// test single-argument make_iterator // test single-argument make_iterator
.def("simple_iterator", [](IntPairs& self) { .def(
return py::make_iterator(self); "simple_iterator",
}, py::keep_alive<0, 1>()) [](IntPairs &self) { return py::make_iterator(self); },
.def("simple_keys", [](IntPairs& self) { py::keep_alive<0, 1>())
return py::make_key_iterator(self); .def(
}, py::keep_alive<0, 1>()) "simple_keys",
.def("simple_values", [](IntPairs& self) { [](IntPairs &self) { return py::make_key_iterator(self); },
return py::make_value_iterator(self); py::keep_alive<0, 1>())
}, py::keep_alive<0, 1>()) .def(
"simple_values",
[](IntPairs &self) { return py::make_value_iterator(self); },
py::keep_alive<0, 1>())
// Test iterator with an Extra (doesn't do anything useful, so not used // Test iterator with an Extra (doesn't do anything useful, so not used
// at runtime, but tests need to be able to compile with the correct // at runtime, but tests need to be able to compile with the correct
// overload. See PR #3293. // overload. See PR #3293.
.def("_make_iterator_extras", [](IntPairs& self) { .def(
return py::make_iterator(self, py::call_guard<int>()); "_make_iterator_extras",
}, py::keep_alive<0, 1>()) [](IntPairs &self) { return py::make_iterator(self, py::call_guard<int>()); },
.def("_make_key_extras", [](IntPairs& self) { py::keep_alive<0, 1>())
return py::make_key_iterator(self, py::call_guard<int>()); .def(
}, py::keep_alive<0, 1>()) "_make_key_extras",
.def("_make_value_extras", [](IntPairs& self) { [](IntPairs &self) { return py::make_key_iterator(self, py::call_guard<int>()); },
return py::make_value_iterator(self, py::call_guard<int>()); py::keep_alive<0, 1>())
}, py::keep_alive<0, 1>()) .def(
; "_make_value_extras",
[](IntPairs &self) { return py::make_value_iterator(self, py::call_guard<int>()); },
py::keep_alive<0, 1>());
// test_iterater_referencing // test_iterater_referencing
py::class_<NonCopyableInt>(m, "NonCopyableInt") py::class_<NonCopyableInt>(m, "NonCopyableInt")
.def(py::init<int>()) .def(py::init<int>())
.def("set", &NonCopyableInt::set) .def("set", &NonCopyableInt::set)
.def("__int__", &NonCopyableInt::get) .def("__int__", &NonCopyableInt::get);
;
py::class_<std::vector<NonCopyableInt>>(m, "VectorNonCopyableInt") py::class_<std::vector<NonCopyableInt>>(m, "VectorNonCopyableInt")
.def(py::init<>()) .def(py::init<>())
.def("append", [](std::vector<NonCopyableInt> &vec, int value) { .def("append",
vec.emplace_back(value); [](std::vector<NonCopyableInt> &vec, int value) { vec.emplace_back(value); })
})
.def("__iter__", [](std::vector<NonCopyableInt> &vec) { .def("__iter__", [](std::vector<NonCopyableInt> &vec) {
return py::make_iterator(vec.begin(), vec.end()); return py::make_iterator(vec.begin(), vec.end());
}) });
;
py::class_<std::vector<NonCopyableIntPair>>(m, "VectorNonCopyableIntPair") py::class_<std::vector<NonCopyableIntPair>>(m, "VectorNonCopyableIntPair")
.def(py::init<>()) .def(py::init<>())
.def("append", [](std::vector<NonCopyableIntPair> &vec, const std::pair<int, int> &value) { .def("append",
vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second)); [](std::vector<NonCopyableIntPair> &vec, const std::pair<int, int> &value) {
}) vec.emplace_back(NonCopyableInt(value.first), NonCopyableInt(value.second));
.def("keys", [](std::vector<NonCopyableIntPair> &vec) { })
return py::make_key_iterator(vec.begin(), vec.end()); .def("keys",
}) [](std::vector<NonCopyableIntPair> &vec) {
return py::make_key_iterator(vec.begin(), vec.end());
})
.def("values", [](std::vector<NonCopyableIntPair> &vec) { .def("values", [](std::vector<NonCopyableIntPair> &vec) {
return py::make_value_iterator(vec.begin(), vec.end()); return py::make_value_iterator(vec.begin(), vec.end());
}) });
;
#if 0 #if 0
// Obsolete: special data structure for exposing custom iterator types to python // Obsolete: special data structure for exposing custom iterator types to python
...@@ -511,7 +554,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) { ...@@ -511,7 +554,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) {
// test_iterator_rvp // test_iterator_rvp
// #388: Can't make iterators via make_iterator() with different r/v policies // #388: Can't make iterators via make_iterator() with different r/v policies
static std::vector<int> list = { 1, 2, 3 }; static std::vector<int> list = {1, 2, 3};
m.def("make_iterator_1", []() { return py::make_iterator<py::return_value_policy::copy>(list); }); m.def("make_iterator_1",
m.def("make_iterator_2", []() { return py::make_iterator<py::return_value_policy::automatic>(list); }); []() { return py::make_iterator<py::return_value_policy::copy>(list); });
m.def("make_iterator_2",
[]() { return py::make_iterator<py::return_value_policy::automatic>(list); });
} }
...@@ -8,21 +8,23 @@ ...@@ -8,21 +8,23 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC #if defined(_MSC_VER) && _MSC_VER < 1910 // VS 2015's MSVC
# pragma warning(disable: 4702) // unreachable code in system header (xatomic.h(382)) # pragma warning(disable : 4702) // unreachable code in system header (xatomic.h(382))
#endif #endif
#include "pybind11_tests.h"
#include "object.h" #include "object.h"
#include "pybind11_tests.h"
namespace { namespace {
// This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the // This is just a wrapper around unique_ptr, but with extra fields to deliberately bloat up the
// holder size to trigger the non-simple-layout internal instance layout for single inheritance with // holder size to trigger the non-simple-layout internal instance layout for single inheritance
// large holder type: // with large holder type:
template <typename T> class huge_unique_ptr { template <typename T>
class huge_unique_ptr {
std::unique_ptr<T> ptr; std::unique_ptr<T> ptr;
uint64_t padding[10]; uint64_t padding[10];
public: public:
explicit huge_unique_ptr(T *p) : ptr(p) {} explicit huge_unique_ptr(T *p) : ptr(p) {}
T *get() { return ptr.get(); } T *get() { return ptr.get(); }
...@@ -32,10 +34,11 @@ public: ...@@ -32,10 +34,11 @@ public:
template <typename T> template <typename T>
class custom_unique_ptr { class custom_unique_ptr {
std::unique_ptr<T> impl; std::unique_ptr<T> impl;
public: public:
explicit custom_unique_ptr(T *p) : impl(p) {} explicit custom_unique_ptr(T *p) : impl(p) {}
T* get() const { return impl.get(); } T *get() const { return impl.get(); }
T* release_ptr() { return impl.release(); } T *release_ptr() { return impl.release(); }
}; };
// Simple custom holder that works like shared_ptr and has operator& overload // Simple custom holder that works like shared_ptr and has operator& overload
...@@ -44,11 +47,12 @@ public: ...@@ -44,11 +47,12 @@ public:
template <typename T> template <typename T>
class shared_ptr_with_addressof_operator { class shared_ptr_with_addressof_operator {
std::shared_ptr<T> impl; std::shared_ptr<T> impl;
public: public:
shared_ptr_with_addressof_operator( ) = default; shared_ptr_with_addressof_operator() = default;
explicit shared_ptr_with_addressof_operator(T *p) : impl(p) {} explicit shared_ptr_with_addressof_operator(T *p) : impl(p) {}
T* get() const { return impl.get(); } T *get() const { return impl.get(); }
T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
}; };
// Simple custom holder that works like unique_ptr and has operator& overload // Simple custom holder that works like unique_ptr and has operator& overload
...@@ -57,12 +61,13 @@ public: ...@@ -57,12 +61,13 @@ public:
template <typename T> template <typename T>
class unique_ptr_with_addressof_operator { class unique_ptr_with_addressof_operator {
std::unique_ptr<T> impl; std::unique_ptr<T> impl;
public: public:
unique_ptr_with_addressof_operator() = default; unique_ptr_with_addressof_operator() = default;
explicit unique_ptr_with_addressof_operator(T *p) : impl(p) {} explicit unique_ptr_with_addressof_operator(T *p) : impl(p) {}
T* get() const { return impl.get(); } T *get() const { return impl.get(); }
T* release_ptr() { return impl.release(); } T *release_ptr() { return impl.release(); }
T** operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); } T **operator&() { throw std::logic_error("Call of overloaded operator& is not expected"); }
}; };
// Custom object with builtin reference counting (see 'object.h' for the implementation) // Custom object with builtin reference counting (see 'object.h' for the implementation)
...@@ -70,8 +75,10 @@ class MyObject1 : public Object { ...@@ -70,8 +75,10 @@ class MyObject1 : public Object {
public: public:
explicit MyObject1(int value) : value(value) { print_created(this, toString()); } explicit MyObject1(int value) : value(value) { print_created(this, toString()); }
std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; } std::string toString() const override { return "MyObject1[" + std::to_string(value) + "]"; }
protected: protected:
~MyObject1() override { print_destroyed(this); } ~MyObject1() override { print_destroyed(this); }
private: private:
int value; int value;
}; };
...@@ -83,6 +90,7 @@ public: ...@@ -83,6 +90,7 @@ public:
explicit MyObject2(int value) : value(value) { print_created(this, toString()); } explicit MyObject2(int value) : value(value) { print_created(this, toString()); }
std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; } std::string toString() const { return "MyObject2[" + std::to_string(value) + "]"; }
virtual ~MyObject2() { print_destroyed(this); } virtual ~MyObject2() { print_destroyed(this); }
private: private:
int value; int value;
}; };
...@@ -94,6 +102,7 @@ public: ...@@ -94,6 +102,7 @@ public:
explicit MyObject3(int value) : value(value) { print_created(this, toString()); } explicit MyObject3(int value) : value(value) { print_created(this, toString()); }
std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; } std::string toString() const { return "MyObject3[" + std::to_string(value) + "]"; }
virtual ~MyObject3() { print_destroyed(this); } virtual ~MyObject3() { print_destroyed(this); }
private: private:
int value; int value;
}; };
...@@ -117,6 +126,7 @@ public: ...@@ -117,6 +126,7 @@ public:
delete o; delete o;
} }
} }
private: private:
~MyObject4() { ~MyObject4() {
myobject4_instances.erase(this); myobject4_instances.erase(this);
...@@ -144,6 +154,7 @@ public: ...@@ -144,6 +154,7 @@ public:
delete o; delete o;
} }
} }
protected: protected:
virtual ~MyObject4a() { virtual ~MyObject4a() {
myobject4a_instances.erase(this); myobject4a_instances.erase(this);
...@@ -232,14 +243,14 @@ struct TypeForMoveOnlyHolderWithAddressOf { ...@@ -232,14 +243,14 @@ struct TypeForMoveOnlyHolderWithAddressOf {
}; };
// test_smart_ptr_from_default // test_smart_ptr_from_default
struct HeldByDefaultHolder { }; struct HeldByDefaultHolder {};
// test_shared_ptr_gc // test_shared_ptr_gc
// #187: issue involving std::shared_ptr<> return value policy & garbage collection // #187: issue involving std::shared_ptr<> return value policy & garbage collection
struct ElementBase { struct ElementBase {
virtual ~ElementBase() = default; /* Force creation of virtual table */ virtual ~ElementBase() = default; /* Force creation of virtual table */
ElementBase() = default; ElementBase() = default;
ElementBase(const ElementBase&) = delete; ElementBase(const ElementBase &) = delete;
}; };
struct ElementA : ElementBase { struct ElementA : ElementBase {
...@@ -259,11 +270,12 @@ struct ElementList { ...@@ -259,11 +270,12 @@ struct ElementList {
// It is always possible to construct a ref<T> from an Object* pointer without // It is always possible to construct a ref<T> from an Object* pointer without
// possible inconsistencies, hence the 'true' argument at the end. // possible inconsistencies, hence the 'true' argument at the end.
// Make pybind11 aware of the non-standard getter member function // Make pybind11 aware of the non-standard getter member function
namespace pybind11 { namespace detail { namespace pybind11 {
template <typename T> namespace detail {
struct holder_helper<ref<T>> { template <typename T>
static const T *get(const ref<T> &p) { return p.get_ptr(); } struct holder_helper<ref<T>> {
}; static const T *get(const ref<T> &p) { return p.get_ptr(); }
};
} // namespace detail } // namespace detail
} // namespace pybind11 } // namespace pybind11
...@@ -287,8 +299,7 @@ TEST_SUBMODULE(smart_ptr, m) { ...@@ -287,8 +299,7 @@ TEST_SUBMODULE(smart_ptr, m) {
py::class_<Object, ref<Object>> obj(m, "Object"); py::class_<Object, ref<Object>> obj(m, "Object");
obj.def("getRefCount", &Object::getRefCount); obj.def("getRefCount", &Object::getRefCount);
py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj) py::class_<MyObject1, ref<MyObject1>>(m, "MyObject1", obj).def(py::init<int>());
.def(py::init<int>());
py::implicitly_convertible<py::int_, MyObject1>(); py::implicitly_convertible<py::int_, MyObject1>();
m.def("make_object_1", []() -> Object * { return new MyObject1(1); }); m.def("make_object_1", []() -> Object * { return new MyObject1(1); });
...@@ -307,25 +318,27 @@ TEST_SUBMODULE(smart_ptr, m) { ...@@ -307,25 +318,27 @@ TEST_SUBMODULE(smart_ptr, m) {
// Expose constructor stats for the ref type // Expose constructor stats for the ref type
m.def("cstats_ref", &ConstructorStats::get<ref_tag>); m.def("cstats_ref", &ConstructorStats::get<ref_tag>);
py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2") py::class_<MyObject2, std::shared_ptr<MyObject2>>(m, "MyObject2").def(py::init<int>());
.def(py::init<int>());
m.def("make_myobject2_1", []() { return new MyObject2(6); }); m.def("make_myobject2_1", []() { return new MyObject2(6); });
m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); }); m.def("make_myobject2_2", []() { return std::make_shared<MyObject2>(7); });
m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); }); m.def("print_myobject2_1", [](const MyObject2 *obj) { py::print(obj->toString()); });
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); }); m.def("print_myobject2_2", [](std::shared_ptr<MyObject2> obj) { py::print(obj->toString()); });
m.def("print_myobject2_3", [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); }); m.def("print_myobject2_3",
m.def("print_myobject2_4", [](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); }); [](const std::shared_ptr<MyObject2> &obj) { py::print(obj->toString()); });
m.def("print_myobject2_4",
[](const std::shared_ptr<MyObject2> *obj) { py::print((*obj)->toString()); });
py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3") py::class_<MyObject3, std::shared_ptr<MyObject3>>(m, "MyObject3").def(py::init<int>());
.def(py::init<int>());
m.def("make_myobject3_1", []() { return new MyObject3(8); }); m.def("make_myobject3_1", []() { return new MyObject3(8); });
m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); }); m.def("make_myobject3_2", []() { return std::make_shared<MyObject3>(9); });
m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); }); m.def("print_myobject3_1", [](const MyObject3 *obj) { py::print(obj->toString()); });
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); }); m.def("print_myobject3_2", [](std::shared_ptr<MyObject3> obj) { py::print(obj->toString()); });
m.def("print_myobject3_3", [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); }); m.def("print_myobject3_3",
m.def("print_myobject3_4", [](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); }); [](const std::shared_ptr<MyObject3> &obj) { py::print(obj->toString()); });
m.def("print_myobject3_4",
[](const std::shared_ptr<MyObject3> *obj) { py::print((*obj)->toString()); });
// test_smart_ptr_refcounting // test_smart_ptr_refcounting
m.def("test_object1_refcounting", []() { m.def("test_object1_refcounting", []() {
...@@ -421,11 +434,18 @@ TEST_SUBMODULE(smart_ptr, m) { ...@@ -421,11 +434,18 @@ TEST_SUBMODULE(smart_ptr, m) {
[](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); }); [](const HolderWithAddressOf *obj) { py::print((*obj).get()->toString()); });
// test_move_only_holder_with_addressof_operator // test_move_only_holder_with_addressof_operator
using MoveOnlyHolderWithAddressOf = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>; using MoveOnlyHolderWithAddressOf
py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(m, "TypeForMoveOnlyHolderWithAddressOf") = unique_ptr_with_addressof_operator<TypeForMoveOnlyHolderWithAddressOf>;
.def_static("make", []() { return MoveOnlyHolderWithAddressOf(new TypeForMoveOnlyHolderWithAddressOf(0)); }) py::class_<TypeForMoveOnlyHolderWithAddressOf, MoveOnlyHolderWithAddressOf>(
m, "TypeForMoveOnlyHolderWithAddressOf")
.def_static("make",
[]() {
return MoveOnlyHolderWithAddressOf(
new TypeForMoveOnlyHolderWithAddressOf(0));
})
.def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value) .def_readwrite("value", &TypeForMoveOnlyHolderWithAddressOf::value)
.def("print_object", [](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); }); .def("print_object",
[](const TypeForMoveOnlyHolderWithAddressOf *obj) { py::print(obj->toString()); });
// test_smart_ptr_from_default // test_smart_ptr_from_default
py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder") py::class_<HeldByDefaultHolder, std::unique_ptr<HeldByDefaultHolder>>(m, "HeldByDefaultHolder")
......
...@@ -7,39 +7,43 @@ ...@@ -7,39 +7,43 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL #ifndef PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
#define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL # define PYBIND11_HAS_FILESYSTEM_IS_OPTIONAL
#endif #endif
#include <pybind11/stl/filesystem.h> #include <pybind11/stl/filesystem.h>
#include <vector>
#include <string> #include <string>
#include <vector>
#if defined(PYBIND11_TEST_BOOST) #if defined(PYBIND11_TEST_BOOST)
#include <boost/optional.hpp> # include <boost/optional.hpp>
namespace pybind11 { namespace detail { namespace pybind11 {
namespace detail {
template <typename T> template <typename T>
struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {}; struct type_caster<boost::optional<T>> : optional_caster<boost::optional<T>> {};
template <> template <>
struct type_caster<boost::none_t> : void_caster<boost::none_t> {}; struct type_caster<boost::none_t> : void_caster<boost::none_t> {};
}} // namespace pybind11::detail } // namespace detail
} // namespace pybind11
#endif #endif
// Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14 // Test with `std::variant` in C++17 mode, or with `boost::variant` in C++11/14
#if defined(PYBIND11_HAS_VARIANT) #if defined(PYBIND11_HAS_VARIANT)
using std::variant; using std::variant;
#elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910) #elif defined(PYBIND11_TEST_BOOST) && (!defined(_MSC_VER) || _MSC_VER >= 1910)
# include <boost/variant.hpp> # include <boost/variant.hpp>
# define PYBIND11_HAS_VARIANT 1 # define PYBIND11_HAS_VARIANT 1
using boost::variant; using boost::variant;
namespace pybind11 { namespace detail { namespace pybind11 {
namespace detail {
template <typename... Ts> template <typename... Ts>
struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {}; struct type_caster<boost::variant<Ts...>> : variant_caster<boost::variant<Ts...>> {};
...@@ -50,7 +54,8 @@ struct visit_helper<boost::variant> { ...@@ -50,7 +54,8 @@ struct visit_helper<boost::variant> {
return boost::apply_visitor(args...); return boost::apply_visitor(args...);
} }
}; };
}} // namespace pybind11::detail } // namespace detail
} // namespace pybind11
#endif #endif
PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>); PYBIND11_MAKE_OPAQUE(std::vector<std::string, std::allocator<std::string>>);
...@@ -63,26 +68,23 @@ struct TplCtorClass { ...@@ -63,26 +68,23 @@ struct TplCtorClass {
}; };
namespace std { namespace std {
template <> template <>
struct hash<TplCtorClass> { size_t operator()(const TplCtorClass &) const { return 0; } }; struct hash<TplCtorClass> {
size_t operator()(const TplCtorClass &) const { return 0; }
};
} // namespace std } // namespace std
template <template <typename> class OptionalImpl, typename T> template <template <typename> class OptionalImpl, typename T>
struct OptionalHolder struct OptionalHolder {
{
// NOLINTNEXTLINE(modernize-use-equals-default): breaks GCC 4.8 // NOLINTNEXTLINE(modernize-use-equals-default): breaks GCC 4.8
OptionalHolder() {}; OptionalHolder(){};
bool member_initialized() const { bool member_initialized() const { return member && member->initialized; }
return member && member->initialized;
}
OptionalImpl<T> member = T{}; OptionalImpl<T> member = T{};
}; };
enum class EnumType { enum class EnumType {
kSet = 42, kSet = 42,
kUnset = 85, kUnset = 85,
}; };
// This is used to test that return-by-ref and return-by-copy policies are // This is used to test that return-by-ref and return-by-copy policies are
...@@ -102,7 +104,7 @@ public: ...@@ -102,7 +104,7 @@ public:
value = EnumType::kUnset; value = EnumType::kUnset;
} }
OptionalEnumValue& access_by_ref() { return value; } OptionalEnumValue &access_by_ref() { return value; }
OptionalEnumValue access_by_copy() { return value; } OptionalEnumValue access_by_copy() { return value; }
private: private:
...@@ -122,62 +124,56 @@ public: ...@@ -122,62 +124,56 @@ public:
ReferenceSensitiveOptional() = default; ReferenceSensitiveOptional() = default;
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
ReferenceSensitiveOptional(const T& value) : storage{value} {} ReferenceSensitiveOptional(const T &value) : storage{value} {}
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
ReferenceSensitiveOptional(T&& value) : storage{std::move(value)} {} ReferenceSensitiveOptional(T &&value) : storage{std::move(value)} {}
ReferenceSensitiveOptional& operator=(const T& value) { ReferenceSensitiveOptional &operator=(const T &value) {
storage = {value}; storage = {value};
return *this; return *this;
} }
ReferenceSensitiveOptional& operator=(T&& value) { ReferenceSensitiveOptional &operator=(T &&value) {
storage = {std::move(value)}; storage = {std::move(value)};
return *this; return *this;
} }
template <typename... Args> template <typename... Args>
T& emplace(Args&&... args) { T &emplace(Args &&...args) {
storage.clear(); storage.clear();
storage.emplace_back(std::forward<Args>(args)...); storage.emplace_back(std::forward<Args>(args)...);
return storage.back(); return storage.back();
} }
const T& value() const noexcept { const T &value() const noexcept {
assert(!storage.empty()); assert(!storage.empty());
return storage[0]; return storage[0];
} }
const T& operator*() const noexcept { const T &operator*() const noexcept { return value(); }
return value();
}
const T* operator->() const noexcept { const T *operator->() const noexcept { return &value(); }
return &value();
}
explicit operator bool() const noexcept { explicit operator bool() const noexcept { return !storage.empty(); }
return !storage.empty();
}
private: private:
std::vector<T> storage; std::vector<T> storage;
}; };
namespace pybind11 { namespace detail { namespace pybind11 {
namespace detail {
template <typename T> template <typename T>
struct type_caster<ReferenceSensitiveOptional<T>> : optional_caster<ReferenceSensitiveOptional<T>> {}; struct type_caster<ReferenceSensitiveOptional<T>>
: optional_caster<ReferenceSensitiveOptional<T>> {};
} // namespace detail } // namespace detail
} // namespace pybind11 } // namespace pybind11
TEST_SUBMODULE(stl, m) { TEST_SUBMODULE(stl, m) {
// test_vector // test_vector
m.def("cast_vector", []() { return std::vector<int>{1}; }); m.def("cast_vector", []() { return std::vector<int>{1}; });
m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; }); m.def("load_vector", [](const std::vector<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
// `std::vector<bool>` is special because it returns proxy objects instead of references // `std::vector<bool>` is special because it returns proxy objects instead of references
m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; }); m.def("cast_bool_vector", []() { return std::vector<bool>{true, false}; });
m.def("load_bool_vector", [](const std::vector<bool> &v) { m.def("load_bool_vector",
return v.at(0) == true && v.at(1) == false; [](const std::vector<bool> &v) { return v.at(0) == true && v.at(1) == false; });
});
// Unnumbered regression (caused by #936): pointers to stl containers aren't castable // Unnumbered regression (caused by #936): pointers to stl containers aren't castable
static std::vector<RValueCaster> lvv{2}; static std::vector<RValueCaster> lvv{2};
m.def("cast_ptr_vector", []() { return &lvv; }); m.def("cast_ptr_vector", []() { return &lvv; });
...@@ -187,12 +183,12 @@ TEST_SUBMODULE(stl, m) { ...@@ -187,12 +183,12 @@ TEST_SUBMODULE(stl, m) {
m.def("load_deque", [](const std::deque<int> &v) { return v.at(0) == 1 && v.at(1) == 2; }); m.def("load_deque", [](const std::deque<int> &v) { return v.at(0) == 1 && v.at(1) == 2; });
// test_array // test_array
m.def("cast_array", []() { return std::array<int, 2> {{1 , 2}}; }); m.def("cast_array", []() { return std::array<int, 2>{{1, 2}}; });
m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; }); m.def("load_array", [](const std::array<int, 2> &a) { return a[0] == 1 && a[1] == 2; });
// test_valarray // test_valarray
m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; }); m.def("cast_valarray", []() { return std::valarray<int>{1, 4, 9}; });
m.def("load_valarray", [](const std::valarray<int>& v) { m.def("load_valarray", [](const std::valarray<int> &v) {
return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9; return v.size() == 3 && v[0] == 1 && v[1] == 4 && v[2] == 9;
}); });
...@@ -214,10 +210,12 @@ TEST_SUBMODULE(stl, m) { ...@@ -214,10 +210,12 @@ TEST_SUBMODULE(stl, m) {
// NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`), // NB: map and set keys are `const`, so while we technically do move them (as `const Type &&`),
// casters don't typically do anything with that, which means they fall to the `const Type &` // casters don't typically do anything with that, which means they fall to the `const Type &`
// caster. // caster.
m.def("cast_rv_map", []() { return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}}; }); m.def("cast_rv_map", []() {
return std::unordered_map<std::string, RValueCaster>{{"a", RValueCaster{}}};
});
m.def("cast_rv_nested", []() { m.def("cast_rv_nested", []() {
std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v; std::vector<std::array<std::list<std::unordered_map<std::string, RValueCaster>>, 2>> v;
v.emplace_back(); // add an array v.emplace_back(); // add an array
v.back()[0].emplace_back(); // add a map to the array v.back()[0].emplace_back(); // add a map to the array
v.back()[0].back().emplace("b", RValueCaster{}); v.back()[0].back().emplace("b", RValueCaster{});
v.back()[0].back().emplace("c", RValueCaster{}); v.back()[0].back().emplace("c", RValueCaster{});
...@@ -226,13 +224,15 @@ TEST_SUBMODULE(stl, m) { ...@@ -226,13 +224,15 @@ TEST_SUBMODULE(stl, m) {
return v; return v;
}); });
static std::array<RValueCaster, 2> lva; static std::array<RValueCaster, 2> lva;
static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}}, {"b", RValueCaster{}}}; static std::unordered_map<std::string, RValueCaster> lvm{{"a", RValueCaster{}},
static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>> lvn; {"b", RValueCaster{}}};
lvn["a"].emplace_back(); // add a list static std::unordered_map<std::string, std::vector<std::list<std::array<RValueCaster, 2>>>>
lvn;
lvn["a"].emplace_back(); // add a list
lvn["a"].back().emplace_back(); // add an array lvn["a"].back().emplace_back(); // add an array
lvn["a"].emplace_back(); // another list lvn["a"].emplace_back(); // another list
lvn["a"].back().emplace_back(); // add an array lvn["a"].back().emplace_back(); // add an array
lvn["b"].emplace_back(); // add a list lvn["b"].emplace_back(); // add a list
lvn["b"].back().emplace_back(); // add an array lvn["b"].back().emplace_back(); // add an array
lvn["b"].back().emplace_back(); // add another array lvn["b"].back().emplace_back(); // add another array
m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; }); m.def("cast_lv_vector", []() -> const decltype(lvv) & { return lvv; });
...@@ -253,7 +253,9 @@ TEST_SUBMODULE(stl, m) { ...@@ -253,7 +253,9 @@ TEST_SUBMODULE(stl, m) {
// test_move_out_container // test_move_out_container
struct MoveOutContainer { struct MoveOutContainer {
struct Value { int value; }; struct Value {
int value;
};
std::list<Value> move_list() const { return {{0}, {1}, {2}}; } std::list<Value> move_list() const { return {{0}, {1}, {2}}; }
}; };
py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue") py::class_<MoveOutContainer::Value>(m, "MoveOutContainerValue")
...@@ -266,7 +268,7 @@ TEST_SUBMODULE(stl, m) { ...@@ -266,7 +268,7 @@ TEST_SUBMODULE(stl, m) {
struct NoAssign { struct NoAssign {
int value; int value;
explicit NoAssign(int value = 0) : value(value) { } explicit NoAssign(int value = 0) : value(value) {}
NoAssign(const NoAssign &) = default; NoAssign(const NoAssign &) = default;
NoAssign(NoAssign &&) = default; NoAssign(NoAssign &&) = default;
...@@ -277,13 +279,10 @@ TEST_SUBMODULE(stl, m) { ...@@ -277,13 +279,10 @@ TEST_SUBMODULE(stl, m) {
.def(py::init<>()) .def(py::init<>())
.def(py::init<int>()); .def(py::init<int>());
struct MoveOutDetector {
struct MoveOutDetector
{
MoveOutDetector() = default; MoveOutDetector() = default;
MoveOutDetector(const MoveOutDetector&) = default; MoveOutDetector(const MoveOutDetector &) = default;
MoveOutDetector(MoveOutDetector&& other) noexcept MoveOutDetector(MoveOutDetector &&other) noexcept : initialized(other.initialized) {
: initialized(other.initialized) {
// steal underlying resource // steal underlying resource
other.initialized = false; other.initialized = false;
} }
...@@ -293,23 +292,22 @@ TEST_SUBMODULE(stl, m) { ...@@ -293,23 +292,22 @@ TEST_SUBMODULE(stl, m) {
.def(py::init<>()) .def(py::init<>())
.def_readonly("initialized", &MoveOutDetector::initialized); .def_readonly("initialized", &MoveOutDetector::initialized);
#ifdef PYBIND11_HAS_OPTIONAL #ifdef PYBIND11_HAS_OPTIONAL
// test_optional // test_optional
m.attr("has_optional") = true; m.attr("has_optional") = true;
using opt_int = std::optional<int>; using opt_int = std::optional<int>;
using opt_no_assign = std::optional<NoAssign>; using opt_no_assign = std::optional<NoAssign>;
m.def("double_or_zero", [](const opt_int& x) -> int { m.def("double_or_zero", [](const opt_int &x) -> int { return x.value_or(0) * 2; });
return x.value_or(0) * 2;
});
m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); }); m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); });
m.def("test_nullopt", [](opt_int x) { m.def(
return x.value_or(42); "test_nullopt",
}, py::arg_v("x", std::nullopt, "None")); [](opt_int x) { return x.value_or(42); },
m.def("test_no_assign", [](const opt_no_assign &x) { py::arg_v("x", std::nullopt, "None"));
return x ? x->value : 42; m.def(
}, py::arg_v("x", std::nullopt, "None")); "test_no_assign",
[](const opt_no_assign &x) { return x ? x->value : 42; },
py::arg_v("x", std::nullopt, "None"));
m.def("nodefer_none_optional", [](std::optional<int>) { return true; }); m.def("nodefer_none_optional", [](std::optional<int>) { return true; });
m.def("nodefer_none_optional", [](const py::none &) { return false; }); m.def("nodefer_none_optional", [](const py::none &) { return false; });
...@@ -333,18 +331,17 @@ TEST_SUBMODULE(stl, m) { ...@@ -333,18 +331,17 @@ TEST_SUBMODULE(stl, m) {
using exp_opt_int = std::experimental::optional<int>; using exp_opt_int = std::experimental::optional<int>;
using exp_opt_no_assign = std::experimental::optional<NoAssign>; using exp_opt_no_assign = std::experimental::optional<NoAssign>;
m.def("double_or_zero_exp", [](const exp_opt_int& x) -> int { m.def("double_or_zero_exp", [](const exp_opt_int &x) -> int { return x.value_or(0) * 2; });
return x.value_or(0) * 2; m.def("half_or_none_exp",
}); [](int x) -> exp_opt_int { return x ? exp_opt_int(x / 2) : exp_opt_int(); });
m.def("half_or_none_exp", [](int x) -> exp_opt_int { m.def(
return x ? exp_opt_int(x / 2) : exp_opt_int(); "test_nullopt_exp",
}); [](exp_opt_int x) { return x.value_or(42); },
m.def("test_nullopt_exp", [](exp_opt_int x) { py::arg_v("x", std::experimental::nullopt, "None"));
return x.value_or(42); m.def(
}, py::arg_v("x", std::experimental::nullopt, "None")); "test_no_assign_exp",
m.def("test_no_assign_exp", [](const exp_opt_no_assign &x) { [](const exp_opt_no_assign &x) { return x ? x->value : 42; },
return x ? x->value : 42; py::arg_v("x", std::experimental::nullopt, "None"));
}, py::arg_v("x", std::experimental::nullopt, "None"));
using opt_exp_holder = OptionalHolder<std::experimental::optional, MoveOutDetector>; using opt_exp_holder = OptionalHolder<std::experimental::optional, MoveOutDetector>;
py::class_<opt_exp_holder>(m, "OptionalExpHolder", "Class with optional member") py::class_<opt_exp_holder>(m, "OptionalExpHolder", "Class with optional member")
...@@ -365,18 +362,17 @@ TEST_SUBMODULE(stl, m) { ...@@ -365,18 +362,17 @@ TEST_SUBMODULE(stl, m) {
using boost_opt_int = boost::optional<int>; using boost_opt_int = boost::optional<int>;
using boost_opt_no_assign = boost::optional<NoAssign>; using boost_opt_no_assign = boost::optional<NoAssign>;
m.def("double_or_zero_boost", [](const boost_opt_int& x) -> int { m.def("double_or_zero_boost", [](const boost_opt_int &x) -> int { return x.value_or(0) * 2; });
return x.value_or(0) * 2; m.def("half_or_none_boost",
}); [](int x) -> boost_opt_int { return x != 0 ? boost_opt_int(x / 2) : boost_opt_int(); });
m.def("half_or_none_boost", [](int x) -> boost_opt_int { m.def(
return x != 0 ? boost_opt_int(x / 2) : boost_opt_int(); "test_nullopt_boost",
}); [](boost_opt_int x) { return x.value_or(42); },
m.def("test_nullopt_boost", [](boost_opt_int x) { py::arg_v("x", boost::none, "None"));
return x.value_or(42); m.def(
}, py::arg_v("x", boost::none, "None")); "test_no_assign_boost",
m.def("test_no_assign_boost", [](const boost_opt_no_assign &x) { [](const boost_opt_no_assign &x) { return x ? x->value : 42; },
return x ? x->value : 42; py::arg_v("x", boost::none, "None"));
}, py::arg_v("x", boost::none, "None"));
using opt_boost_holder = OptionalHolder<boost::optional, MoveOutDetector>; using opt_boost_holder = OptionalHolder<boost::optional, MoveOutDetector>;
py::class_<opt_boost_holder>(m, "OptionalBoostHolder", "Class with optional member") py::class_<opt_boost_holder>(m, "OptionalBoostHolder", "Class with optional member")
...@@ -394,9 +390,8 @@ TEST_SUBMODULE(stl, m) { ...@@ -394,9 +390,8 @@ TEST_SUBMODULE(stl, m) {
// test_refsensitive_optional // test_refsensitive_optional
using refsensitive_opt_int = ReferenceSensitiveOptional<int>; using refsensitive_opt_int = ReferenceSensitiveOptional<int>;
using refsensitive_opt_no_assign = ReferenceSensitiveOptional<NoAssign>; using refsensitive_opt_no_assign = ReferenceSensitiveOptional<NoAssign>;
m.def("double_or_zero_refsensitive", [](const refsensitive_opt_int& x) -> int { m.def("double_or_zero_refsensitive",
return (x ? x.value() : 0) * 2; [](const refsensitive_opt_int &x) -> int { return (x ? x.value() : 0) * 2; });
});
m.def("half_or_none_refsensitive", [](int x) -> refsensitive_opt_int { m.def("half_or_none_refsensitive", [](int x) -> refsensitive_opt_int {
return x != 0 ? refsensitive_opt_int(x / 2) : refsensitive_opt_int(); return x != 0 ? refsensitive_opt_int(x / 2) : refsensitive_opt_int();
}); });
...@@ -405,12 +400,14 @@ TEST_SUBMODULE(stl, m) { ...@@ -405,12 +400,14 @@ TEST_SUBMODULE(stl, m) {
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)
[](refsensitive_opt_int x) { return x ? x.value() : 42; }, [](refsensitive_opt_int x) { return x ? x.value() : 42; },
py::arg_v("x", refsensitive_opt_int(), "None")); py::arg_v("x", refsensitive_opt_int(), "None"));
m.def("test_no_assign_refsensitive", [](const refsensitive_opt_no_assign &x) { m.def(
return x ? x->value : 42; "test_no_assign_refsensitive",
}, py::arg_v("x", refsensitive_opt_no_assign(), "None")); [](const refsensitive_opt_no_assign &x) { return x ? x->value : 42; },
py::arg_v("x", refsensitive_opt_no_assign(), "None"));
using opt_refsensitive_holder = OptionalHolder<ReferenceSensitiveOptional, MoveOutDetector>; using opt_refsensitive_holder = OptionalHolder<ReferenceSensitiveOptional, MoveOutDetector>;
py::class_<opt_refsensitive_holder>(m, "OptionalRefSensitiveHolder", "Class with optional member") py::class_<opt_refsensitive_holder>(
m, "OptionalRefSensitiveHolder", "Class with optional member")
.def(py::init<>()) .def(py::init<>())
.def_readonly("member", &opt_refsensitive_holder::member) .def_readonly("member", &opt_refsensitive_holder::member)
.def("member_initialized", &opt_refsensitive_holder::member_initialized); .def("member_initialized", &opt_refsensitive_holder::member_initialized);
...@@ -424,7 +421,7 @@ TEST_SUBMODULE(stl, m) { ...@@ -424,7 +421,7 @@ TEST_SUBMODULE(stl, m) {
#ifdef PYBIND11_HAS_FILESYSTEM #ifdef PYBIND11_HAS_FILESYSTEM
// test_fs_path // test_fs_path
m.attr("has_filesystem") = true; m.attr("has_filesystem") = true;
m.def("parent_path", [](const std::filesystem::path& p) { return p.parent_path(); }); m.def("parent_path", [](const std::filesystem::path &p) { return p.parent_path(); });
#endif #endif
#ifdef PYBIND11_HAS_VARIANT #ifdef PYBIND11_HAS_VARIANT
...@@ -472,13 +469,13 @@ TEST_SUBMODULE(stl, m) { ...@@ -472,13 +469,13 @@ TEST_SUBMODULE(stl, m) {
// #171: Can't return STL structures containing reference wrapper // #171: Can't return STL structures containing reference wrapper
m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) { m.def("return_vec_of_reference_wrapper", [](std::reference_wrapper<UserType> p4) {
static UserType p1{1}, p2{2}, p3{3}; static UserType p1{1}, p2{2}, p3{3};
return std::vector<std::reference_wrapper<UserType>> { return std::vector<std::reference_wrapper<UserType>>{
std::ref(p1), std::ref(p2), std::ref(p3), p4 std::ref(p1), std::ref(p2), std::ref(p3), p4};
};
}); });
// test_stl_pass_by_pointer // test_stl_pass_by_pointer
m.def("stl_pass_by_pointer", [](std::vector<int>* v) { return *v; }, "v"_a=nullptr); m.def(
"stl_pass_by_pointer", [](std::vector<int> *v) { return *v; }, "v"_a = nullptr);
// #1258: pybind11/stl.h converts string to vector<string> // #1258: pybind11/stl.h converts string to vector<string>
m.def("func_with_string_or_vector_string_arg_overload", m.def("func_with_string_or_vector_string_arg_overload",
...@@ -496,19 +493,24 @@ TEST_SUBMODULE(stl, m) { ...@@ -496,19 +493,24 @@ TEST_SUBMODULE(stl, m) {
py::class_<Placeholder>(m, "Placeholder"); py::class_<Placeholder>(m, "Placeholder");
/// test_stl_vector_ownership /// test_stl_vector_ownership
m.def("test_stl_ownership", m.def(
[]() { "test_stl_ownership",
std::vector<Placeholder *> result; []() {
result.push_back(new Placeholder()); std::vector<Placeholder *> result;
return result; result.push_back(new Placeholder());
}, return result;
py::return_value_policy::take_ownership); },
py::return_value_policy::take_ownership);
m.def("array_cast_sequence", [](std::array<int, 3> x) { return x; }); m.def("array_cast_sequence", [](std::array<int, 3> x) { return x; });
/// test_issue_1561 /// test_issue_1561
struct Issue1561Inner { std::string data; }; struct Issue1561Inner {
struct Issue1561Outer { std::vector<Issue1561Inner> list; }; std::string data;
};
struct Issue1561Outer {
std::vector<Issue1561Inner> list;
};
py::class_<Issue1561Inner>(m, "Issue1561Inner") py::class_<Issue1561Inner>(m, "Issue1561Inner")
.def(py::init<std::string>()) .def(py::init<std::string>())
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include <pybind11/numpy.h>
#include <pybind11/stl_bind.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <pybind11/stl_bind.h>
#include <pybind11/numpy.h>
#include <map>
#include <deque> #include <deque>
#include <map>
#include <unordered_map> #include <unordered_map>
class El { class El {
...@@ -23,7 +24,7 @@ public: ...@@ -23,7 +24,7 @@ public:
int a; int a;
}; };
std::ostream & operator<<(std::ostream &s, El const&v) { std::ostream &operator<<(std::ostream &s, El const &v) {
s << "El{" << v.a << '}'; s << "El{" << v.a << '}';
return s; return s;
} }
...@@ -40,7 +41,8 @@ public: ...@@ -40,7 +41,8 @@ public:
int value; int value;
}; };
template <class Container> Container *one_to_n(int n) { template <class Container>
Container *one_to_n(int n) {
auto *v = new Container(); auto *v = new Container();
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
v->emplace_back(i); v->emplace_back(i);
...@@ -48,7 +50,8 @@ template <class Container> Container *one_to_n(int n) { ...@@ -48,7 +50,8 @@ template <class Container> Container *one_to_n(int n) {
return v; return v;
} }
template <class Map> Map *times_ten(int n) { template <class Map>
Map *times_ten(int n) {
auto *m = new Map(); auto *m = new Map();
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
m->emplace(int(i), E_nc(10 * i)); m->emplace(int(i), E_nc(10 * i));
...@@ -56,7 +59,8 @@ template <class Map> Map *times_ten(int n) { ...@@ -56,7 +59,8 @@ template <class Map> Map *times_ten(int n) {
return m; return m;
} }
template <class NestMap> NestMap *times_hundred(int n) { template <class NestMap>
NestMap *times_hundred(int n) {
auto *m = new NestMap(); auto *m = new NestMap();
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) { for (int j = 1; j <= n; j++) {
...@@ -71,8 +75,7 @@ TEST_SUBMODULE(stl_binders, m) { ...@@ -71,8 +75,7 @@ TEST_SUBMODULE(stl_binders, m) {
py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol()); py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
// test_vector_custom // test_vector_custom
py::class_<El>(m, "El") py::class_<El>(m, "El").def(py::init<int>());
.def(py::init<int>());
py::bind_vector<std::vector<El>>(m, "VectorEl"); py::bind_vector<std::vector<El>>(m, "VectorEl");
py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl"); py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl");
...@@ -82,11 +85,10 @@ TEST_SUBMODULE(stl_binders, m) { ...@@ -82,11 +85,10 @@ TEST_SUBMODULE(stl_binders, m) {
// test_map_string_double_const // test_map_string_double_const
py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst"); py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst");
py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst"); py::bind_map<std::unordered_map<std::string, double const>>(m,
"UnorderedMapStringDoubleConst");
py::class_<E_nc>(m, "ENC") py::class_<E_nc>(m, "ENC").def(py::init<int>()).def_readwrite("value", &E_nc::value);
.def(py::init<int>())
.def_readwrite("value", &E_nc::value);
// test_noncopyable_containers // test_noncopyable_containers
py::bind_vector<std::vector<E_nc>>(m, "VectorENC"); py::bind_vector<std::vector<E_nc>>(m, "VectorENC");
...@@ -116,17 +118,31 @@ TEST_SUBMODULE(stl_binders, m) { ...@@ -116,17 +118,31 @@ TEST_SUBMODULE(stl_binders, m) {
// test_vector_buffer // test_vector_buffer
py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol()); py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
// no dtype declared for this version: // no dtype declared for this version:
struct VUndeclStruct { bool w; uint32_t x; double y; bool z; }; struct VUndeclStruct {
m.def("create_undeclstruct", [m] () mutable { bool w;
py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol()); uint32_t x;
double y;
bool z;
};
m.def("create_undeclstruct", [m]() mutable {
py::bind_vector<std::vector<VUndeclStruct>>(
m, "VectorUndeclStruct", py::buffer_protocol());
}); });
// The rest depends on numpy: // The rest depends on numpy:
try { py::module_::import("numpy"); } try {
catch (...) { return; } py::module_::import("numpy");
} catch (...) {
return;
}
// test_vector_buffer_numpy // test_vector_buffer_numpy
struct VStruct { bool w; uint32_t x; double y; bool z; }; struct VStruct {
bool w;
uint32_t x;
double y;
bool z;
};
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z); PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x); py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol()); py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
struct Animal #include "pybind11_tests.h"
{
struct Animal {
// Make this type also a "standard" polymorphic type, to confirm that // Make this type also a "standard" polymorphic type, to confirm that
// specializing polymorphic_type_hook using enable_if_t still works // specializing polymorphic_type_hook using enable_if_t still works
// (https://github.com/pybind/pybind11/pull/2016/). // (https://github.com/pybind/pybind11/pull/2016/).
...@@ -20,57 +20,54 @@ struct Animal ...@@ -20,57 +20,54 @@ struct Animal
// Enum for tag-based polymorphism. // Enum for tag-based polymorphism.
enum class Kind { enum class Kind {
Unknown = 0, Unknown = 0,
Dog = 100, Labrador, Chihuahua, LastDog = 199, Dog = 100,
Cat = 200, Panther, LastCat = 299 Labrador,
Chihuahua,
LastDog = 199,
Cat = 200,
Panther,
LastCat = 299
}; };
static const std::type_info* type_of_kind(Kind kind); static const std::type_info *type_of_kind(Kind kind);
static std::string name_of_kind(Kind kind); static std::string name_of_kind(Kind kind);
const Kind kind; const Kind kind;
const std::string name; const std::string name;
protected: protected:
Animal(const std::string& _name, Kind _kind) Animal(const std::string &_name, Kind _kind) : kind(_kind), name(_name) {}
: kind(_kind), name(_name)
{}
}; };
struct Dog : Animal struct Dog : Animal {
{
explicit Dog(const std::string &_name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {} explicit Dog(const std::string &_name, Kind _kind = Kind::Dog) : Animal(_name, _kind) {}
std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; } std::string bark() const { return name_of_kind(kind) + " " + name + " goes " + sound; }
std::string sound = "WOOF!"; std::string sound = "WOOF!";
}; };
struct Labrador : Dog struct Labrador : Dog {
{
explicit Labrador(const std::string &_name, int _excitement = 9001) explicit Labrador(const std::string &_name, int _excitement = 9001)
: Dog(_name, Kind::Labrador), excitement(_excitement) {} : Dog(_name, Kind::Labrador), excitement(_excitement) {}
int excitement; int excitement;
}; };
struct Chihuahua : Dog struct Chihuahua : Dog {
{
explicit Chihuahua(const std::string &_name) : Dog(_name, Kind::Chihuahua) { explicit Chihuahua(const std::string &_name) : Dog(_name, Kind::Chihuahua) {
sound = "iyiyiyiyiyi"; sound = "iyiyiyiyiyi";
} }
std::string bark() const { return Dog::bark() + " and runs in circles"; } std::string bark() const { return Dog::bark() + " and runs in circles"; }
}; };
struct Cat : Animal struct Cat : Animal {
{
explicit Cat(const std::string &_name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {} explicit Cat(const std::string &_name, Kind _kind = Kind::Cat) : Animal(_name, _kind) {}
std::string purr() const { return "mrowr"; } std::string purr() const { return "mrowr"; }
}; };
struct Panther : Cat struct Panther : Cat {
{
explicit Panther(const std::string &_name) : Cat(_name, Kind::Panther) {} explicit Panther(const std::string &_name) : Cat(_name, Kind::Panther) {}
std::string purr() const { return "mrrrRRRRRR"; } std::string purr() const { return "mrrrRRRRRR"; }
}; };
std::vector<std::unique_ptr<Animal>> create_zoo() std::vector<std::unique_ptr<Animal>> create_zoo() {
{
std::vector<std::unique_ptr<Animal>> ret; std::vector<std::unique_ptr<Animal>> ret;
ret.emplace_back(new Labrador("Fido", 15000)); ret.emplace_back(new Labrador("Fido", 15000));
...@@ -85,19 +82,24 @@ std::vector<std::unique_ptr<Animal>> create_zoo() ...@@ -85,19 +82,24 @@ std::vector<std::unique_ptr<Animal>> create_zoo()
return ret; return ret;
} }
const std::type_info* Animal::type_of_kind(Kind kind) const std::type_info *Animal::type_of_kind(Kind kind) {
{
switch (kind) { switch (kind) {
case Kind::Unknown: case Kind::Unknown:
case Kind::Dog: break; case Kind::Dog:
break;
case Kind::Labrador: return &typeid(Labrador); case Kind::Labrador:
case Kind::Chihuahua: return &typeid(Chihuahua); return &typeid(Labrador);
case Kind::Chihuahua:
return &typeid(Chihuahua);
case Kind::LastDog: case Kind::LastDog:
case Kind::Cat: break; case Kind::Cat:
case Kind::Panther: return &typeid(Panther); break;
case Kind::LastCat: break; case Kind::Panther:
return &typeid(Panther);
case Kind::LastCat:
break;
} }
if (kind >= Kind::Dog && kind <= Kind::LastDog) { if (kind >= Kind::Dog && kind <= Kind::LastDog) {
...@@ -109,25 +111,24 @@ const std::type_info* Animal::type_of_kind(Kind kind) ...@@ -109,25 +111,24 @@ const std::type_info* Animal::type_of_kind(Kind kind)
return nullptr; return nullptr;
} }
std::string Animal::name_of_kind(Kind kind) std::string Animal::name_of_kind(Kind kind) {
{
std::string raw_name = type_of_kind(kind)->name(); std::string raw_name = type_of_kind(kind)->name();
py::detail::clean_type_id(raw_name); py::detail::clean_type_id(raw_name);
return raw_name; return raw_name;
} }
namespace pybind11 { namespace pybind11 {
template <typename itype> template <typename itype>
struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>> struct polymorphic_type_hook<itype, detail::enable_if_t<std::is_base_of<Animal, itype>::value>> {
{ static const void *get(const itype *src, const std::type_info *&type) {
static const void *get(const itype *src, const std::type_info*& type) type = src ? Animal::type_of_kind(src->kind) : nullptr;
{ type = src ? Animal::type_of_kind(src->kind) : nullptr; return src; } return src;
}; }
};
} // namespace pybind11 } // namespace pybind11
TEST_SUBMODULE(tagbased_polymorphic, m) { TEST_SUBMODULE(tagbased_polymorphic, m) {
py::class_<Animal>(m, "Animal") py::class_<Animal>(m, "Animal").def_readonly("name", &Animal::name);
.def_readonly("name", &Animal::name);
py::class_<Dog, Animal>(m, "Dog") py::class_<Dog, Animal>(m, "Dog")
.def(py::init<std::string>()) .def(py::init<std::string>())
.def_readwrite("sound", &Dog::sound) .def_readwrite("sound", &Dog::sound)
...@@ -138,9 +139,7 @@ TEST_SUBMODULE(tagbased_polymorphic, m) { ...@@ -138,9 +139,7 @@ TEST_SUBMODULE(tagbased_polymorphic, m) {
py::class_<Chihuahua, Dog>(m, "Chihuahua") py::class_<Chihuahua, Dog>(m, "Chihuahua")
.def(py::init<std::string>()) .def(py::init<std::string>())
.def("bark", &Chihuahua::bark); .def("bark", &Chihuahua::bark);
py::class_<Cat, Animal>(m, "Cat") py::class_<Cat, Animal>(m, "Cat").def(py::init<std::string>()).def("purr", &Cat::purr);
.def(py::init<std::string>())
.def("purr", &Cat::purr);
py::class_<Panther, Cat>(m, "Panther") py::class_<Panther, Cat>(m, "Panther")
.def(py::init<std::string>()) .def(py::init<std::string>())
.def("purr", &Panther::purr); .def("purr", &Panther::purr);
......
...@@ -10,20 +10,20 @@ ...@@ -10,20 +10,20 @@
#include <pybind11/cast.h> #include <pybind11/cast.h>
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include "pybind11_tests.h"
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include "pybind11_tests.h"
namespace py = pybind11; namespace py = pybind11;
namespace { namespace {
struct IntStruct { struct IntStruct {
explicit IntStruct(int v) : value(v) {}; explicit IntStruct(int v) : value(v){};
~IntStruct() { value = -value; } ~IntStruct() { value = -value; }
IntStruct(const IntStruct&) = default; IntStruct(const IntStruct &) = default;
IntStruct& operator=(const IntStruct&) = default; IntStruct &operator=(const IntStruct &) = default;
int value; int value;
}; };
......
...@@ -7,13 +7,15 @@ ...@@ -7,13 +7,15 @@
BSD-style license that can be found in the LICENSE file. BSD-style license that can be found in the LICENSE file.
*/ */
#include "pybind11_tests.h"
#include "constructor_stats.h"
#include <pybind11/functional.h> #include <pybind11/functional.h>
#include "constructor_stats.h"
#include "pybind11_tests.h"
#include <thread> #include <thread>
/* This is an example class that we'll want to be able to extend from Python */ /* This is an example class that we'll want to be able to extend from Python */
class ExampleVirt { class ExampleVirt {
public: public:
explicit ExampleVirt(int state) : state(state) { print_created(this, state); } explicit ExampleVirt(int state) : state(state) { print_created(this, state); }
ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); } ExampleVirt(const ExampleVirt &e) : state(e.state) { print_copy_created(this); }
...@@ -25,7 +27,8 @@ public: ...@@ -25,7 +27,8 @@ public:
virtual int run(int value) { virtual int run(int value) {
py::print("Original implementation of " py::print("Original implementation of "
"ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(state, value, get_string1(), *get_string2())); "ExampleVirt::run(state={}, value={}, str1={}, str2={})"_s.format(
state, value, get_string1(), *get_string2()));
return state + value; return state + value;
} }
...@@ -33,8 +36,8 @@ public: ...@@ -33,8 +36,8 @@ public:
virtual void pure_virtual() = 0; virtual void pure_virtual() = 0;
// Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a // Returning a reference/pointer to a type converted from python (numbers, strings, etc.) is a
// bit trickier, because the actual int& or std::string& or whatever only exists temporarily, so // bit trickier, because the actual int& or std::string& or whatever only exists temporarily,
// we have to handle it specially in the trampoline class (see below). // so we have to handle it specially in the trampoline class (see below).
virtual const std::string &get_string1() { return str1; } virtual const std::string &get_string1() { return str1; }
virtual const std::string *get_string2() { return &str2; } virtual const std::string *get_string2() { return &str2; }
...@@ -50,59 +53,53 @@ public: ...@@ -50,59 +53,53 @@ public:
int run(int value) override { int run(int value) override {
/* Generate wrapping code that enables native function overloading */ /* Generate wrapping code that enables native function overloading */
PYBIND11_OVERRIDE( PYBIND11_OVERRIDE(int, /* Return type */
int, /* Return type */ ExampleVirt, /* Parent class */
ExampleVirt, /* Parent class */ run, /* Name of function */
run, /* Name of function */ value /* Argument(s) */
value /* Argument(s) */
); );
} }
bool run_bool() override { bool run_bool() override {
PYBIND11_OVERRIDE_PURE( PYBIND11_OVERRIDE_PURE(bool, /* Return type */
bool, /* Return type */ ExampleVirt, /* Parent class */
ExampleVirt, /* Parent class */ run_bool, /* Name of function */
run_bool, /* Name of function */ /* This function has no arguments. The trailing comma
/* This function has no arguments. The trailing comma in the previous line is needed for some compilers */
in the previous line is needed for some compilers */
); );
} }
void pure_virtual() override { void pure_virtual() override {
PYBIND11_OVERRIDE_PURE( PYBIND11_OVERRIDE_PURE(void, /* Return type */
void, /* Return type */ ExampleVirt, /* Parent class */
ExampleVirt, /* Parent class */ pure_virtual, /* Name of function */
pure_virtual, /* Name of function */ /* This function has no arguments. The trailing comma
/* This function has no arguments. The trailing comma in the previous line is needed for some compilers */
in the previous line is needed for some compilers */
); );
} }
// We can return reference types for compatibility with C++ virtual interfaces that do so, but // We can return reference types for compatibility with C++ virtual interfaces that do so, but
// note they have some significant limitations (see the documentation). // note they have some significant limitations (see the documentation).
const std::string &get_string1() override { const std::string &get_string1() override {
PYBIND11_OVERRIDE( PYBIND11_OVERRIDE(const std::string &, /* Return type */
const std::string &, /* Return type */ ExampleVirt, /* Parent class */
ExampleVirt, /* Parent class */ get_string1, /* Name of function */
get_string1, /* Name of function */ /* (no arguments) */
/* (no arguments) */
); );
} }
const std::string *get_string2() override { const std::string *get_string2() override {
PYBIND11_OVERRIDE( PYBIND11_OVERRIDE(const std::string *, /* Return type */
const std::string *, /* Return type */ ExampleVirt, /* Parent class */
ExampleVirt, /* Parent class */ get_string2, /* Name of function */
get_string2, /* Name of function */ /* (no arguments) */
/* (no arguments) */
); );
} }
}; };
class NonCopyable { class NonCopyable {
public: public:
NonCopyable(int a, int b) : value{new int(a*b)} { print_created(this, a, b); } NonCopyable(int a, int b) : value{new int(a * b)} { print_created(this, a, b); }
NonCopyable(NonCopyable &&o) noexcept : value{std::move(o.value)} { print_move_created(this); } NonCopyable(NonCopyable &&o) noexcept : value{std::move(o.value)} { print_move_created(this); }
NonCopyable(const NonCopyable &) = delete; NonCopyable(const NonCopyable &) = delete;
NonCopyable() = delete; NonCopyable() = delete;
...@@ -124,11 +121,12 @@ private: ...@@ -124,11 +121,12 @@ private:
// when it is not referenced elsewhere, but copied if it is still referenced. // when it is not referenced elsewhere, but copied if it is still referenced.
class Movable { class Movable {
public: public:
Movable(int a, int b) : value{a+b} { print_created(this, a, b); } Movable(int a, int b) : value{a + b} { print_created(this, a, b); }
Movable(const Movable &m) : value{m.value} { print_copy_created(this); } Movable(const Movable &m) : value{m.value} { print_copy_created(this); }
Movable(Movable &&m) noexcept : value{m.value} { print_move_created(this); } Movable(Movable &&m) noexcept : value{m.value} { print_move_created(this); }
std::string get_value() const { return std::to_string(value); } std::string get_value() const { return std::to_string(value); }
~Movable() { print_destroyed(this); } ~Movable() { print_destroyed(this); }
private: private:
int value; int value;
}; };
...@@ -137,7 +135,7 @@ class NCVirt { ...@@ -137,7 +135,7 @@ class NCVirt {
public: public:
virtual ~NCVirt() = default; virtual ~NCVirt() = default;
NCVirt() = default; NCVirt() = default;
NCVirt(const NCVirt&) = delete; NCVirt(const NCVirt &) = delete;
virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); } virtual NonCopyable get_noncopyable(int a, int b) { return NonCopyable(a, b); }
virtual Movable get_movable(int a, int b) = 0; virtual Movable get_movable(int a, int b) = 0;
...@@ -160,7 +158,7 @@ struct Base { ...@@ -160,7 +158,7 @@ struct Base {
virtual std::string dispatch() const { return {}; }; virtual std::string dispatch() const { return {}; };
virtual ~Base() = default; virtual ~Base() = default;
Base() = default; Base() = default;
Base(const Base&) = delete; Base(const Base &) = delete;
}; };
struct DispatchIssue : Base { struct DispatchIssue : Base {
...@@ -173,33 +171,33 @@ struct DispatchIssue : Base { ...@@ -173,33 +171,33 @@ struct DispatchIssue : Base {
// objects and send the result to the visitor functor // objects and send the result to the visitor functor
struct AdderBase { struct AdderBase {
struct Data {}; struct Data {};
using DataVisitor = std::function<void (const Data&)>; using DataVisitor = std::function<void(const Data &)>;
virtual void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const = 0; virtual void
operator()(const Data &first, const Data &second, const DataVisitor &visitor) const = 0;
virtual ~AdderBase() = default; virtual ~AdderBase() = default;
AdderBase() = default; AdderBase() = default;
AdderBase(const AdderBase&) = delete; AdderBase(const AdderBase &) = delete;
}; };
struct Adder : AdderBase { struct Adder : AdderBase {
void operator()(const Data& first, const Data& second, const DataVisitor& visitor) const override { void
PYBIND11_OVERRIDE_PURE_NAME(void, AdderBase, "__call__", operator(), first, second, visitor); operator()(const Data &first, const Data &second, const DataVisitor &visitor) const override {
PYBIND11_OVERRIDE_PURE_NAME(
void, AdderBase, "__call__", operator(), first, second, visitor);
} }
}; };
static void test_gil() { static void test_gil() {
{ {
py::gil_scoped_acquire lock; py::gil_scoped_acquire lock;
py::print("1st lock acquired"); py::print("1st lock acquired");
} }
{ {
py::gil_scoped_acquire lock; py::gil_scoped_acquire lock;
py::print("2nd lock acquired"); py::print("2nd lock acquired");
} }
} }
static void test_gil_from_thread() { static void test_gil_from_thread() {
...@@ -225,12 +223,12 @@ class test_override_cache_helper_trampoline : public test_override_cache_helper ...@@ -225,12 +223,12 @@ class test_override_cache_helper_trampoline : public test_override_cache_helper
int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); } int func() override { PYBIND11_OVERRIDE(int, test_override_cache_helper, func); }
}; };
inline int test_override_cache(std::shared_ptr<test_override_cache_helper> const &instance) { return instance->func(); } inline int test_override_cache(std::shared_ptr<test_override_cache_helper> const &instance) {
return instance->func();
}
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are // Forward declaration (so that we can put the main tests here; the inherited virtual approaches
// rather long). // are rather long).
void initialize_inherited_virtuals(py::module_ &m); void initialize_inherited_virtuals(py::module_ &m);
TEST_SUBMODULE(virtual_functions, m) { TEST_SUBMODULE(virtual_functions, m) {
...@@ -242,11 +240,9 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -242,11 +240,9 @@ TEST_SUBMODULE(virtual_functions, m) {
.def("run_bool", &ExampleVirt::run_bool) .def("run_bool", &ExampleVirt::run_bool)
.def("pure_virtual", &ExampleVirt::pure_virtual); .def("pure_virtual", &ExampleVirt::pure_virtual);
py::class_<NonCopyable>(m, "NonCopyable") py::class_<NonCopyable>(m, "NonCopyable").def(py::init<int, int>());
.def(py::init<int, int>());
py::class_<Movable>(m, "Movable") py::class_<Movable>(m, "Movable").def(py::init<int, int>());
.def(py::init<int, int>());
// test_move_support // test_move_support
#if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__) #if !defined(__INTEL_COMPILER) && !defined(__CUDACC__) && !defined(__PGIC__)
...@@ -259,7 +255,7 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -259,7 +255,7 @@ TEST_SUBMODULE(virtual_functions, m) {
#endif #endif
m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); }); m.def("runExampleVirt", [](ExampleVirt *ex, int value) { return ex->run(value); });
m.def("runExampleVirtBool", [](ExampleVirt* ex) { return ex->run_bool(); }); m.def("runExampleVirtBool", [](ExampleVirt *ex) { return ex->run_bool(); });
m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); }); m.def("runExampleVirtVirtual", [](ExampleVirt *ex) { ex->pure_virtual(); });
m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>); m.def("cstats_debug", &ConstructorStats::get<ExampleVirt>);
...@@ -270,27 +266,25 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -270,27 +266,25 @@ TEST_SUBMODULE(virtual_functions, m) {
// that were not extended on the Python side // that were not extended on the Python side
struct A { struct A {
A() = default; A() = default;
A(const A&) = delete; A(const A &) = delete;
virtual ~A() = default; virtual ~A() = default;
virtual void f() { py::print("A.f()"); } virtual void f() { py::print("A.f()"); }
}; };
struct PyA : A { struct PyA : A {
PyA() { py::print("PyA.PyA()"); } PyA() { py::print("PyA.PyA()"); }
PyA(const PyA&) = delete; PyA(const PyA &) = delete;
~PyA() override { py::print("PyA.~PyA()"); } ~PyA() override { py::print("PyA.~PyA()"); }
void f() override { void f() override {
py::print("PyA.f()"); py::print("PyA.f()");
// This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to protect // This convolution just gives a `void`, but tests that PYBIND11_TYPE() works to
// a type containing a , // protect a type containing a ,
PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f); PYBIND11_OVERRIDE(PYBIND11_TYPE(typename std::enable_if<true, void>::type), A, f);
} }
}; };
py::class_<A, PyA>(m, "A") py::class_<A, PyA>(m, "A").def(py::init<>()).def("f", &A::f);
.def(py::init<>())
.def("f", &A::f);
m.def("call_f", [](A *a) { a->f(); }); m.def("call_f", [](A *a) { a->f(); });
...@@ -298,14 +292,14 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -298,14 +292,14 @@ TEST_SUBMODULE(virtual_functions, m) {
// ... unless we explicitly request it, as in this example: // ... unless we explicitly request it, as in this example:
struct A2 { struct A2 {
A2() = default; A2() = default;
A2(const A2&) = delete; A2(const A2 &) = delete;
virtual ~A2() = default; virtual ~A2() = default;
virtual void f() { py::print("A2.f()"); } virtual void f() { py::print("A2.f()"); }
}; };
struct PyA2 : A2 { struct PyA2 : A2 {
PyA2() { py::print("PyA2.PyA2()"); } PyA2() { py::print("PyA2.PyA2()"); }
PyA2(const PyA2&) = delete; PyA2(const PyA2 &) = delete;
~PyA2() override { py::print("PyA2.~PyA2()"); } ~PyA2() override { py::print("PyA2.~PyA2()"); }
void f() override { void f() override {
py::print("PyA2.f()"); py::print("PyA2.f()");
...@@ -326,7 +320,7 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -326,7 +320,7 @@ TEST_SUBMODULE(virtual_functions, m) {
.def(py::init<>()) .def(py::init<>())
.def("dispatch", &Base::dispatch); .def("dispatch", &Base::dispatch);
m.def("dispatch_issue_go", [](const Base * b) { return b->dispatch(); }); m.def("dispatch_issue_go", [](const Base *b) { return b->dispatch(); });
// test_recursive_dispatch_issue // test_recursive_dispatch_issue
// #3357: Recursive dispatch fails to find python function override // #3357: Recursive dispatch fails to find python function override
...@@ -334,31 +328,39 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -334,31 +328,39 @@ TEST_SUBMODULE(virtual_functions, m) {
.def(pybind11::init<>()) .def(pybind11::init<>())
.def("__call__", &AdderBase::operator()); .def("__call__", &AdderBase::operator());
pybind11::class_<AdderBase::Data>(m, "Data") pybind11::class_<AdderBase::Data>(m, "Data").def(pybind11::init<>());
.def(pybind11::init<>());
m.def("add2",
m.def("add2", [](const AdderBase::Data& first, const AdderBase::Data& second, [](const AdderBase::Data &first,
const AdderBase& adder, const AdderBase::DataVisitor& visitor) { const AdderBase::Data &second,
adder(first, second, visitor); const AdderBase &adder,
}); const AdderBase::DataVisitor &visitor) { adder(first, second, visitor); });
m.def("add3", [](const AdderBase::Data& first, const AdderBase::Data& second, const AdderBase::Data& third, m.def("add3",
const AdderBase& adder, const AdderBase::DataVisitor& visitor) { [](const AdderBase::Data &first,
adder(first, second, [&] (const AdderBase::Data& first_plus_second) { const AdderBase::Data &second,
adder(first_plus_second, third, visitor); // NOLINT(readability-suspicious-call-argument) const AdderBase::Data &third,
}); const AdderBase &adder,
}); const AdderBase::DataVisitor &visitor) {
adder(first, second, [&](const AdderBase::Data &first_plus_second) {
adder(first_plus_second,
third,
visitor); // NOLINT(readability-suspicious-call-argument)
});
});
// test_override_ref // test_override_ref
// #392/397: overriding reference-returning functions // #392/397: overriding reference-returning functions
class OverrideTest { class OverrideTest {
public: public:
struct A { std::string value = "hi"; }; struct A {
std::string value = "hi";
};
std::string v; std::string v;
A a; A a;
explicit OverrideTest(const std::string &v) : v{v} {} explicit OverrideTest(const std::string &v) : v{v} {}
OverrideTest() = default; OverrideTest() = default;
OverrideTest(const OverrideTest&) = delete; OverrideTest(const OverrideTest &) = delete;
virtual std::string str_value() { return v; } virtual std::string str_value() { return v; }
virtual std::string &str_ref() { return v; } virtual std::string &str_ref() { return v; }
virtual A A_value() { return a; } virtual A A_value() { return a; }
...@@ -369,17 +371,22 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -369,17 +371,22 @@ TEST_SUBMODULE(virtual_functions, m) {
class PyOverrideTest : public OverrideTest { class PyOverrideTest : public OverrideTest {
public: public:
using OverrideTest::OverrideTest; using OverrideTest::OverrideTest;
std::string str_value() override { PYBIND11_OVERRIDE(std::string, OverrideTest, str_value); } std::string str_value() override {
PYBIND11_OVERRIDE(std::string, OverrideTest, str_value);
}
// Not allowed (enabling the below should hit a static_assert failure): we can't get a // Not allowed (enabling the below should hit a static_assert failure): we can't get a
// reference to a python numeric value, since we only copy values in the numeric type // reference to a python numeric value, since we only copy values in the numeric type
// caster: // caster:
#ifdef PYBIND11_NEVER_DEFINED_EVER #ifdef PYBIND11_NEVER_DEFINED_EVER
std::string &str_ref() override { PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref); } std::string &str_ref() override {
PYBIND11_OVERRIDE(std::string &, OverrideTest, str_ref);
}
#endif #endif
// But we can work around it like this: // But we can work around it like this:
private: private:
std::string _tmp; std::string _tmp;
std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); } std::string str_ref_helper() { PYBIND11_OVERRIDE(std::string, OverrideTest, str_ref); }
public: public:
std::string &str_ref() override { return _tmp = str_ref_helper(); } std::string &str_ref() override { return _tmp = str_ref_helper(); }
...@@ -398,14 +405,15 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -398,14 +405,15 @@ TEST_SUBMODULE(virtual_functions, m) {
.def("A_value", &OverrideTest::A_value) .def("A_value", &OverrideTest::A_value)
.def("A_ref", &OverrideTest::A_ref); .def("A_ref", &OverrideTest::A_ref);
py::class_<test_override_cache_helper, test_override_cache_helper_trampoline, std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper") py::class_<test_override_cache_helper,
test_override_cache_helper_trampoline,
std::shared_ptr<test_override_cache_helper>>(m, "test_override_cache_helper")
.def(py::init_alias<>()) .def(py::init_alias<>())
.def("func", &test_override_cache_helper::func); .def("func", &test_override_cache_helper::func);
m.def("test_override_cache", test_override_cache); m.def("test_override_cache", test_override_cache);
} }
// Inheriting virtual methods. We do two versions here: the repeat-everything version and the // Inheriting virtual methods. We do two versions here: the repeat-everything version and the
// templated trampoline versions mentioned in docs/advanced.rst. // templated trampoline versions mentioned in docs/advanced.rst.
// //
...@@ -414,83 +422,96 @@ TEST_SUBMODULE(virtual_functions, m) { ...@@ -414,83 +422,96 @@ TEST_SUBMODULE(virtual_functions, m) {
// properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to // properly (pybind11, sensibly, doesn't allow us to bind the same C++ class to
// multiple python classes). // multiple python classes).
class A_Repeat { class A_Repeat {
#define A_METHODS \ #define A_METHODS \
public: \ public: \
virtual int unlucky_number() = 0; \ virtual int unlucky_number() = 0; \
virtual std::string say_something(unsigned times) { \ virtual std::string say_something(unsigned times) { \
std::string s = ""; \ std::string s = ""; \
for (unsigned i = 0; i < times; ++i) \ for (unsigned i = 0; i < times; ++i) \
s += "hi"; \ s += "hi"; \
return s; \ return s; \
} \ } \
std::string say_everything() { \ std::string say_everything() { \
return say_something(1) + " " + std::to_string(unlucky_number()); \ return say_something(1) + " " + std::to_string(unlucky_number()); \
} }
A_METHODS A_METHODS
A_Repeat() = default; A_Repeat() = default;
A_Repeat(const A_Repeat&) = delete; A_Repeat(const A_Repeat &) = delete;
virtual ~A_Repeat() = default; virtual ~A_Repeat() = default;
}; };
class B_Repeat : public A_Repeat { class B_Repeat : public A_Repeat {
#define B_METHODS \ #define B_METHODS \
public: \ public: \
int unlucky_number() override { return 13; } \ int unlucky_number() override { return 13; } \
std::string say_something(unsigned times) override { \ std::string say_something(unsigned times) override { \
return "B says hi " + std::to_string(times) + " times"; \ return "B says hi " + std::to_string(times) + " times"; \
} \ } \
virtual double lucky_number() { return 7.0; } virtual double lucky_number() { return 7.0; }
B_METHODS B_METHODS
}; };
class C_Repeat : public B_Repeat { class C_Repeat : public B_Repeat {
#define C_METHODS \ #define C_METHODS \
public: \ public: \
int unlucky_number() override { return 4444; } \ int unlucky_number() override { return 4444; } \
double lucky_number() override { return 888; } double lucky_number() override { return 888; }
C_METHODS C_METHODS
}; };
class D_Repeat : public C_Repeat { class D_Repeat : public C_Repeat {
#define D_METHODS // Nothing overridden. #define D_METHODS // Nothing overridden.
D_METHODS D_METHODS
}; };
// Base classes for templated inheritance trampolines. Identical to the repeat-everything version: // Base classes for templated inheritance trampolines. Identical to the repeat-everything version:
class A_Tpl { class A_Tpl {
A_METHODS; A_METHODS;
A_Tpl() = default; A_Tpl() = default;
A_Tpl(const A_Tpl&) = delete; A_Tpl(const A_Tpl &) = delete;
virtual ~A_Tpl() = default; virtual ~A_Tpl() = default;
}; };
class B_Tpl : public A_Tpl { B_METHODS }; class B_Tpl : public A_Tpl {
class C_Tpl : public B_Tpl { C_METHODS }; B_METHODS
class D_Tpl : public C_Tpl { D_METHODS }; };
class C_Tpl : public B_Tpl {
C_METHODS
};
class D_Tpl : public C_Tpl {
D_METHODS
};
// Inheritance approach 1: each trampoline gets every virtual method (11 in total) // Inheritance approach 1: each trampoline gets every virtual method (11 in total)
class PyA_Repeat : public A_Repeat { class PyA_Repeat : public A_Repeat {
public: public:
using A_Repeat::A_Repeat; using A_Repeat::A_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); } int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, A_Repeat, unlucky_number, ); }
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times); } std::string say_something(unsigned times) override {
PYBIND11_OVERRIDE(std::string, A_Repeat, say_something, times);
}
}; };
class PyB_Repeat : public B_Repeat { class PyB_Repeat : public B_Repeat {
public: public:
using B_Repeat::B_Repeat; using B_Repeat::B_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); } int unlucky_number() override { PYBIND11_OVERRIDE(int, B_Repeat, unlucky_number, ); }
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times); } std::string say_something(unsigned times) override {
PYBIND11_OVERRIDE(std::string, B_Repeat, say_something, times);
}
double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); } double lucky_number() override { PYBIND11_OVERRIDE(double, B_Repeat, lucky_number, ); }
}; };
class PyC_Repeat : public C_Repeat { class PyC_Repeat : public C_Repeat {
public: public:
using C_Repeat::C_Repeat; using C_Repeat::C_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); } int unlucky_number() override { PYBIND11_OVERRIDE(int, C_Repeat, unlucky_number, ); }
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times); } std::string say_something(unsigned times) override {
PYBIND11_OVERRIDE(std::string, C_Repeat, say_something, times);
}
double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); } double lucky_number() override { PYBIND11_OVERRIDE(double, C_Repeat, lucky_number, ); }
}; };
class PyD_Repeat : public D_Repeat { class PyD_Repeat : public D_Repeat {
public: public:
using D_Repeat::D_Repeat; using D_Repeat::D_Repeat;
int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); } int unlucky_number() override { PYBIND11_OVERRIDE(int, D_Repeat, unlucky_number, ); }
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times); } std::string say_something(unsigned times) override {
PYBIND11_OVERRIDE(std::string, D_Repeat, say_something, times);
}
double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); } double lucky_number() override { PYBIND11_OVERRIDE(double, D_Repeat, lucky_number, ); }
}; };
...@@ -513,7 +534,9 @@ class PyA_Tpl : public Base { ...@@ -513,7 +534,9 @@ class PyA_Tpl : public Base {
public: public:
using Base::Base; // Inherit constructors using Base::Base; // Inherit constructors
int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); } int unlucky_number() override { PYBIND11_OVERRIDE_PURE(int, Base, unlucky_number, ); }
std::string say_something(unsigned times) override { PYBIND11_OVERRIDE(std::string, Base, say_something, times); } std::string say_something(unsigned times) override {
PYBIND11_OVERRIDE(std::string, Base, say_something, times);
}
}; };
template <class Base = B_Tpl> template <class Base = B_Tpl>
class PyB_Tpl : public PyA_Tpl<Base> { class PyB_Tpl : public PyA_Tpl<Base> {
...@@ -548,10 +571,8 @@ void initialize_inherited_virtuals(py::module_ &m) { ...@@ -548,10 +571,8 @@ void initialize_inherited_virtuals(py::module_ &m) {
py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat") py::class_<B_Repeat, A_Repeat, PyB_Repeat>(m, "B_Repeat")
.def(py::init<>()) .def(py::init<>())
.def("lucky_number", &B_Repeat::lucky_number); .def("lucky_number", &B_Repeat::lucky_number);
py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat") py::class_<C_Repeat, B_Repeat, PyC_Repeat>(m, "C_Repeat").def(py::init<>());
.def(py::init<>()); py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat").def(py::init<>());
py::class_<D_Repeat, C_Repeat, PyD_Repeat>(m, "D_Repeat")
.def(py::init<>());
// test_ // test_
// Method 2: Templated trampolines // Method 2: Templated trampolines
...@@ -563,11 +584,8 @@ void initialize_inherited_virtuals(py::module_ &m) { ...@@ -563,11 +584,8 @@ void initialize_inherited_virtuals(py::module_ &m) {
py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl") py::class_<B_Tpl, A_Tpl, PyB_Tpl<>>(m, "B_Tpl")
.def(py::init<>()) .def(py::init<>())
.def("lucky_number", &B_Tpl::lucky_number); .def("lucky_number", &B_Tpl::lucky_number);
py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl") py::class_<C_Tpl, B_Tpl, PyB_Tpl<C_Tpl>>(m, "C_Tpl").def(py::init<>());
.def(py::init<>()); py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl").def(py::init<>());
py::class_<D_Tpl, C_Tpl, PyB_Tpl<D_Tpl>>(m, "D_Tpl")
.def(py::init<>());
// Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7) // Fix issue #1454 (crash when acquiring/releasing GIL on another thread in Python 2.7)
m.def("test_gil", &test_gil); m.def("test_gil", &test_gil);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment