Unverified Commit dac74ebd authored by Aaron Gokaslan's avatar Aaron Gokaslan Committed by GitHub
Browse files

fix(clang-tidy): performance fixes applied in tests and CI (#3051)

* Initial fixes

* Whoops

* Finish clang-tidy manual fixes

* Add two missing fixes

* Revert

* Update clang-tidy

* Try to fix unreachable code error

* Move nolint comment

* Apply missing fix

* Don't override clang-tidy config

* Does this fix clang-tidy?

* Make all clang-tidy errors visible

* Add comments about NOLINTs and remove a few

* Fix typo
parent 3b30b0a5
...@@ -18,6 +18,7 @@ modernize-use-noexcept, ...@@ -18,6 +18,7 @@ modernize-use-noexcept,
modernize-use-emplace, modernize-use-emplace,
modernize-use-override, modernize-use-override,
modernize-use-using, modernize-use-using,
*performance*,
readability-container-size-empty, readability-container-size-empty,
readability-make-member-function-const, readability-make-member-function-const,
readability-redundant-function-ptr-dereference, readability-redundant-function-ptr-dereference,
......
...@@ -27,7 +27,7 @@ jobs: ...@@ -27,7 +27,7 @@ jobs:
clang-tidy: clang-tidy:
name: Clang-Tidy name: Clang-Tidy
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: silkeh/clang:10 container: silkeh/clang:12
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
...@@ -37,10 +37,10 @@ jobs: ...@@ -37,10 +37,10 @@ jobs:
- name: Configure - name: Configure
run: > run: >
cmake -S . -B build cmake -S . -B build
-DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy);--warnings-as-errors=*" -DCMAKE_CXX_CLANG_TIDY="$(which clang-tidy)"
-DDOWNLOAD_EIGEN=ON -DDOWNLOAD_EIGEN=ON
-DDOWNLOAD_CATCH=ON -DDOWNLOAD_CATCH=ON
-DCMAKE_CXX_STANDARD=17 -DCMAKE_CXX_STANDARD=17
- name: Build - name: Build
run: cmake --build build -j 2 run: cmake --build build -j 2 -- --keep-going
...@@ -262,7 +262,7 @@ add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") { ...@@ -262,7 +262,7 @@ add_ostream_redirect(module_ m, const std::string &name = "ostream_redirect") {
return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local()) return class_<detail::OstreamRedirect>(std::move(m), name.c_str(), module_local())
.def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true) .def(init<bool, bool>(), arg("stdout") = true, arg("stderr") = true)
.def("__enter__", &detail::OstreamRedirect::enter) .def("__enter__", &detail::OstreamRedirect::enter)
.def("__exit__", [](detail::OstreamRedirect &self_, args) { self_.exit(); }); .def("__exit__", [](detail::OstreamRedirect &self_, const args &) { self_.exit(); });
} }
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
...@@ -1629,12 +1629,13 @@ struct enum_base { ...@@ -1629,12 +1629,13 @@ struct enum_base {
auto static_property = handle((PyObject *) get_internals().static_property_type); auto static_property = handle((PyObject *) get_internals().static_property_type);
m_base.attr("__repr__") = cpp_function( m_base.attr("__repr__") = cpp_function(
[](object arg) -> str { [](const object &arg) -> str {
handle type = type::handle_of(arg); handle type = type::handle_of(arg);
object type_name = type.attr("__name__"); object type_name = type.attr("__name__");
return pybind11::str("<{}.{}: {}>").format(type_name, enum_name(arg), int_(arg)); return pybind11::str("<{}.{}: {}>").format(type_name, enum_name(arg), int_(arg));
}, name("__repr__"), is_method(m_base) },
); name("__repr__"),
is_method(m_base));
m_base.attr("name") = property(cpp_function(&enum_name, name("name"), is_method(m_base))); m_base.attr("name") = property(cpp_function(&enum_name, name("name"), is_method(m_base)));
...@@ -1718,8 +1719,10 @@ struct enum_base { ...@@ -1718,8 +1719,10 @@ struct enum_base {
PYBIND11_ENUM_OP_CONV("__ror__", a | b); PYBIND11_ENUM_OP_CONV("__ror__", a | b);
PYBIND11_ENUM_OP_CONV("__xor__", a ^ b); PYBIND11_ENUM_OP_CONV("__xor__", a ^ b);
PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b); PYBIND11_ENUM_OP_CONV("__rxor__", a ^ b);
m_base.attr("__invert__") = cpp_function( m_base.attr("__invert__")
[](object arg) { return ~(int_(arg)); }, name("__invert__"), is_method(m_base)); = cpp_function([](const object &arg) { return ~(int_(arg)); },
name("__invert__"),
is_method(m_base));
} }
} else { } else {
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
...@@ -1740,10 +1743,10 @@ struct enum_base { ...@@ -1740,10 +1743,10 @@ struct enum_base {
#undef PYBIND11_ENUM_OP_STRICT #undef PYBIND11_ENUM_OP_STRICT
m_base.attr("__getstate__") = cpp_function( m_base.attr("__getstate__") = cpp_function(
[](object arg) { return int_(arg); }, name("__getstate__"), is_method(m_base)); [](const object &arg) { return int_(arg); }, name("__getstate__"), is_method(m_base));
m_base.attr("__hash__") = cpp_function( m_base.attr("__hash__") = cpp_function(
[](object arg) { return int_(arg); }, name("__hash__"), is_method(m_base)); [](const object &arg) { return int_(arg); }, name("__hash__"), is_method(m_base));
} }
PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) { PYBIND11_NOINLINE void value(char const* name_, object value, const char *doc = nullptr) {
......
#pragma once #pragma once
#include <utility>
#include "pybind11_tests.h" #include "pybind11_tests.h"
/// Simple class used to test py::local: /// Simple class used to test py::local:
...@@ -54,7 +56,7 @@ py::class_<T> bind_local(Args && ...args) { ...@@ -54,7 +56,7 @@ py::class_<T> bind_local(Args && ...args) {
namespace pets { namespace pets {
class Pet { class Pet {
public: public:
Pet(std::string name) : name_(name) {} Pet(std::string name) : name_(std::move(name)) {}
std::string name_; std::string name_;
const std::string &name() const { return name_; } const std::string &name() const { return name_; }
}; };
......
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
} }
/// Move constructor /// Move constructor
ref(ref &&r) : m_ptr(r.m_ptr) { ref(ref &&r) noexcept : m_ptr(r.m_ptr) {
r.m_ptr = nullptr; r.m_ptr = nullptr;
print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this); print_move_created(this, "with pointer", m_ptr); track_move_created((ref_tag*) this);
...@@ -96,7 +96,7 @@ public: ...@@ -96,7 +96,7 @@ public:
} }
/// Move another reference into the current one /// Move another reference into the current one
ref& operator=(ref&& r) { ref &operator=(ref &&r) noexcept {
print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this); print_move_assigned(this, "pointer", r.m_ptr); track_move_assigned((ref_tag*) this);
if (*this == r) if (*this == r)
......
...@@ -104,6 +104,8 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -104,6 +104,8 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
m.def("return_self", [](LocalVec *v) { return v; }); m.def("return_self", [](LocalVec *v) { return v; });
m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); }); m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
// Changing this broke things with pygrep. TODO fix
// NOLINTNEXTLINE
class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; }; class Dog : public pets::Pet { public: Dog(std::string name) : Pet(name) {}; };
py::class_<pets::Pet>(m, "Pet", py::module_local()) py::class_<pets::Pet>(m, "Pet", py::module_local())
.def("name", &pets::Pet::name); .def("name", &pets::Pet::name);
...@@ -126,6 +128,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { ...@@ -126,6 +128,7 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) {
// test_missing_header_message // test_missing_header_message
// The main module already includes stl.h, but we need to test the error message // The main module already includes stl.h, but we need to test the error message
// which appears when this header is missing. // which appears when this header is missing.
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("missing_header_arg", [](std::vector<float>) { }); m.def("missing_header_arg", [](std::vector<float>) { });
m.def("missing_header_return", []() { return std::vector<float>(); }); m.def("missing_header_return", []() { return std::vector<float>(); });
} }
...@@ -27,7 +27,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -27,7 +27,7 @@ TEST_SUBMODULE(buffers, m) {
memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols)); memcpy(m_data, s.m_data, sizeof(float) * (size_t) (m_rows * m_cols));
} }
Matrix(Matrix &&s) : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) { Matrix(Matrix &&s) noexcept : m_rows(s.m_rows), m_cols(s.m_cols), m_data(s.m_data) {
print_move_created(this); print_move_created(this);
s.m_rows = 0; s.m_rows = 0;
s.m_cols = 0; s.m_cols = 0;
...@@ -49,7 +49,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -49,7 +49,7 @@ TEST_SUBMODULE(buffers, m) {
return *this; return *this;
} }
Matrix &operator=(Matrix &&s) { Matrix &operator=(Matrix &&s) noexcept {
print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix"); print_move_assigned(this, std::to_string(m_rows) + "x" + std::to_string(m_cols) + " matrix");
if (&s != this) { if (&s != this) {
delete[] m_data; delete[] m_data;
...@@ -79,6 +79,7 @@ TEST_SUBMODULE(buffers, m) { ...@@ -79,6 +79,7 @@ TEST_SUBMODULE(buffers, m) {
py::class_<Matrix>(m, "Matrix", py::buffer_protocol()) py::class_<Matrix>(m, "Matrix", py::buffer_protocol())
.def(py::init<py::ssize_t, py::ssize_t>()) .def(py::init<py::ssize_t, py::ssize_t>())
/// Construct from a buffer /// Construct from a buffer
// NOLINTNEXTLINE(performance-unnecessary-value-param)
.def(py::init([](py::buffer const b) { .def(py::init([](py::buffer const b) {
py::buffer_info info = b.request(); py::buffer_info info = b.request();
if (info.format != py::format_descriptor<float>::format() || info.ndim != 2) if (info.format != py::format_descriptor<float>::format() || info.ndim != 2)
...@@ -89,31 +90,31 @@ TEST_SUBMODULE(buffers, m) { ...@@ -89,31 +90,31 @@ TEST_SUBMODULE(buffers, m) {
return v; return v;
})) }))
.def("rows", &Matrix::rows) .def("rows", &Matrix::rows)
.def("cols", &Matrix::cols) .def("cols", &Matrix::cols)
/// Bare bones interface /// Bare bones interface
.def("__getitem__", [](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) { .def("__getitem__",
if (i.first >= m.rows() || i.second >= m.cols()) [](const Matrix &m, std::pair<py::ssize_t, py::ssize_t> i) {
throw py::index_error(); if (i.first >= m.rows() || i.second >= m.cols())
return m(i.first, i.second); throw py::index_error();
}) return m(i.first, i.second);
.def("__setitem__", [](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) { })
if (i.first >= m.rows() || i.second >= m.cols()) .def("__setitem__",
throw py::index_error(); [](Matrix &m, std::pair<py::ssize_t, py::ssize_t> i, float v) {
m(i.first, i.second) = v; if (i.first >= m.rows() || i.second >= m.cols())
}) throw py::index_error();
/// Provide buffer access m(i.first, i.second) = v;
.def_buffer([](Matrix &m) -> py::buffer_info { })
/// Provide buffer access
.def_buffer([](Matrix &m) -> py::buffer_info {
return py::buffer_info( return py::buffer_info(
m.data(), /* Pointer to buffer */ m.data(), /* Pointer to buffer */
{ m.rows(), m.cols() }, /* Buffer dimensions */ { m.rows(), m.cols() }, /* Buffer dimensions */
{ sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */ { sizeof(float) * size_t(m.cols()), /* Strides (in bytes) for each index */
sizeof(float) } sizeof(float) }
); );
}) });
;
// test_inherited_protocol // test_inherited_protocol
class SquareMatrix : public Matrix { class SquareMatrix : public Matrix {
...@@ -208,7 +209,5 @@ TEST_SUBMODULE(buffers, m) { ...@@ -208,7 +209,5 @@ TEST_SUBMODULE(buffers, m) {
}) })
; ;
m.def("get_buffer_info", [](py::buffer buffer) { m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); });
return buffer.request();
});
} }
...@@ -30,7 +30,11 @@ class type_caster<ConstRefCasted> { ...@@ -30,7 +30,11 @@ class type_caster<ConstRefCasted> {
// cast operator. // cast operator.
bool load(handle, bool) { return true; } bool load(handle, bool) { return true; }
operator ConstRefCasted&&() { value = {1}; return std::move(value); } operator ConstRefCasted &&() {
value = {1};
// NOLINTNEXTLINE(performance-move-const-arg)
return std::move(value);
}
operator ConstRefCasted&() { value = {2}; return value; } operator ConstRefCasted&() { value = {2}; return value; }
operator ConstRefCasted*() { value = {3}; return &value; } operator ConstRefCasted*() { value = {3}; return &value; }
...@@ -101,6 +105,7 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -101,6 +105,7 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_bytes_to_string // test_bytes_to_string
m.def("strlen", [](char *s) { return strlen(s); }); m.def("strlen", [](char *s) { return strlen(s); });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("string_length", [](std::string s) { return s.length(); }); m.def("string_length", [](std::string s) { return s.length(); });
#ifdef PYBIND11_HAS_U8STRING #ifdef PYBIND11_HAS_U8STRING
...@@ -146,6 +151,7 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -146,6 +151,7 @@ TEST_SUBMODULE(builtin_casters, m) {
m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert()); m.def("int_passthrough_noconvert", [](int arg) { return arg; }, py::arg{}.noconvert());
// test_tuple // test_tuple
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("pair_passthrough", [](std::pair<bool, std::string> input) { m.def("pair_passthrough", [](std::pair<bool, std::string> input) {
return std::make_pair(input.second, input.first); return std::make_pair(input.second, input.first);
}, "Return a pair in reversed order"); }, "Return a pair in reversed order");
...@@ -177,10 +183,13 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -177,10 +183,13 @@ TEST_SUBMODULE(builtin_casters, m) {
// test_none_deferred // test_none_deferred
m.def("defer_none_cstring", [](char *) { return false; }); m.def("defer_none_cstring", [](char *) { return false; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("defer_none_cstring", [](py::none) { return true; }); m.def("defer_none_cstring", [](py::none) { return true; });
m.def("defer_none_custom", [](UserType *) { return false; }); m.def("defer_none_custom", [](UserType *) { return false; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("defer_none_custom", [](py::none) { return true; }); m.def("defer_none_custom", [](py::none) { return true; });
m.def("nodefer_none_void", [](void *) { return true; }); m.def("nodefer_none_void", [](void *) { return true; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("nodefer_none_void", [](py::none) { return false; }); m.def("nodefer_none_void", [](py::none) { return false; });
// test_void_caster // test_void_caster
...@@ -231,6 +240,7 @@ TEST_SUBMODULE(builtin_casters, m) { ...@@ -231,6 +240,7 @@ TEST_SUBMODULE(builtin_casters, m) {
}, "copy"_a); }, "copy"_a);
m.def("refwrap_iiw", [](const IncType &w) { return w.value(); }); m.def("refwrap_iiw", [](const IncType &w) { return w.value(); });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("refwrap_call_iiw", [](IncType &w, py::function f) { m.def("refwrap_call_iiw", [](IncType &w, py::function f) {
py::list l; py::list l;
l.append(f(std::ref(w))); l.append(f(std::ref(w)));
......
...@@ -17,8 +17,8 @@ int dummy_function(int i) { return i + 1; } ...@@ -17,8 +17,8 @@ int dummy_function(int i) { return i + 1; }
TEST_SUBMODULE(callbacks, m) { TEST_SUBMODULE(callbacks, m) {
// test_callbacks, test_function_signatures // test_callbacks, test_function_signatures
m.def("test_callback1", [](py::object func) { return func(); }); m.def("test_callback1", [](const py::object &func) { return func(); });
m.def("test_callback2", [](py::object func) { return func("Hello", 'x', true, 5); }); m.def("test_callback2", [](const py::object &func) { return func("Hello", 'x', true, 5); });
m.def("test_callback3", [](const std::function<int(int)> &func) { m.def("test_callback3", [](const std::function<int(int)> &func) {
return "func(43) = " + std::to_string(func(43)); }); return "func(43) = " + std::to_string(func(43)); });
m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; }); m.def("test_callback4", []() -> std::function<int(int)> { return [](int i) { return i+1; }; });
...@@ -27,51 +27,48 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -27,51 +27,48 @@ TEST_SUBMODULE(callbacks, m) {
}); });
// test_keyword_args_and_generalized_unpacking // test_keyword_args_and_generalized_unpacking
m.def("test_tuple_unpacking", [](py::function f) { m.def("test_tuple_unpacking", [](const py::function &f) {
auto t1 = py::make_tuple(2, 3); auto t1 = py::make_tuple(2, 3);
auto t2 = py::make_tuple(5, 6); auto t2 = py::make_tuple(5, 6);
return f("positional", 1, *t1, 4, *t2); return f("positional", 1, *t1, 4, *t2);
}); });
m.def("test_dict_unpacking", [](py::function f) { m.def("test_dict_unpacking", [](const py::function &f) {
auto d1 = py::dict("key"_a="value", "a"_a=1); auto d1 = py::dict("key"_a="value", "a"_a=1);
auto d2 = py::dict(); auto d2 = py::dict();
auto d3 = py::dict("b"_a=2); auto d3 = py::dict("b"_a=2);
return f("positional", 1, **d1, **d2, **d3); return f("positional", 1, **d1, **d2, **d3);
}); });
m.def("test_keyword_args", [](py::function f) { m.def("test_keyword_args", [](const py::function &f) { return f("x"_a = 10, "y"_a = 20); });
return f("x"_a=10, "y"_a=20);
});
m.def("test_unpacking_and_keywords1", [](py::function f) { m.def("test_unpacking_and_keywords1", [](const py::function &f) {
auto args = py::make_tuple(2); auto args = py::make_tuple(2);
auto kwargs = py::dict("d"_a=4); auto kwargs = py::dict("d"_a=4);
return f(1, *args, "c"_a=3, **kwargs); return f(1, *args, "c"_a=3, **kwargs);
}); });
m.def("test_unpacking_and_keywords2", [](py::function f) { m.def("test_unpacking_and_keywords2", [](const py::function &f) {
auto kwargs1 = py::dict("a"_a=1); auto kwargs1 = py::dict("a"_a=1);
auto kwargs2 = py::dict("c"_a=3, "d"_a=4); auto kwargs2 = py::dict("c"_a=3, "d"_a=4);
return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5, return f("positional", *py::make_tuple(1), 2, *py::make_tuple(3, 4), 5,
"key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5); "key"_a="value", **kwargs1, "b"_a=2, **kwargs2, "e"_a=5);
}); });
m.def("test_unpacking_error1", [](py::function f) { m.def("test_unpacking_error1", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3); auto kwargs = py::dict("x"_a=3);
return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword return f("x"_a=1, "y"_a=2, **kwargs); // duplicate ** after keyword
}); });
m.def("test_unpacking_error2", [](py::function f) { m.def("test_unpacking_error2", [](const py::function &f) {
auto kwargs = py::dict("x"_a=3); auto kwargs = py::dict("x"_a=3);
return f(**kwargs, "x"_a=1); // duplicate keyword after ** return f(**kwargs, "x"_a=1); // duplicate keyword after **
}); });
m.def("test_arg_conversion_error1", [](py::function f) { m.def("test_arg_conversion_error1",
f(234, UnregisteredType(), "kw"_a=567); [](const py::function &f) { f(234, UnregisteredType(), "kw"_a = 567); });
});
m.def("test_arg_conversion_error2", [](py::function f) { m.def("test_arg_conversion_error2", [](const py::function &f) {
f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567); f(234, "expected_name"_a=UnregisteredType(), "kw"_a=567);
}); });
...@@ -80,7 +77,7 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -80,7 +77,7 @@ TEST_SUBMODULE(callbacks, m) {
Payload() { print_default_created(this); } Payload() { print_default_created(this); }
~Payload() { print_destroyed(this); } ~Payload() { print_destroyed(this); }
Payload(const Payload &) { print_copy_created(this); } Payload(const Payload &) { print_copy_created(this); }
Payload(Payload &&) { print_move_created(this); } Payload(Payload &&) noexcept { print_move_created(this); }
}; };
// Export the payload constructor statistics for testing purposes: // Export the payload constructor statistics for testing purposes:
m.def("payload_cstats", &ConstructorStats::get<Payload>); m.def("payload_cstats", &ConstructorStats::get<Payload>);
...@@ -127,7 +124,8 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -127,7 +124,8 @@ TEST_SUBMODULE(callbacks, m) {
virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default) virtual ~AbstractBase() {}; // NOLINT(modernize-use-equals-default)
virtual unsigned int func() = 0; virtual unsigned int func() = 0;
}; };
m.def("func_accepting_func_accepting_base", [](std::function<double(AbstractBase&)>) { }); m.def("func_accepting_func_accepting_base",
[](const std::function<double(AbstractBase &)> &) {});
struct MovableObject { struct MovableObject {
bool valid = true; bool valid = true;
...@@ -135,8 +133,8 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -135,8 +133,8 @@ TEST_SUBMODULE(callbacks, m) {
MovableObject() = default; MovableObject() = default;
MovableObject(const MovableObject &) = default; MovableObject(const MovableObject &) = default;
MovableObject &operator=(const MovableObject &) = default; MovableObject &operator=(const MovableObject &) = default;
MovableObject(MovableObject &&o) : valid(o.valid) { o.valid = false; } MovableObject(MovableObject &&o) noexcept : valid(o.valid) { o.valid = false; }
MovableObject &operator=(MovableObject &&o) { MovableObject &operator=(MovableObject &&o) noexcept {
valid = o.valid; valid = o.valid;
o.valid = false; o.valid = false;
return *this; return *this;
...@@ -145,7 +143,7 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -145,7 +143,7 @@ TEST_SUBMODULE(callbacks, m) {
py::class_<MovableObject>(m, "MovableObject"); py::class_<MovableObject>(m, "MovableObject");
// test_movable_object // test_movable_object
m.def("callback_with_movable", [](std::function<void(MovableObject &)> f) { m.def("callback_with_movable", [](const std::function<void(MovableObject &)> &f) {
auto x = MovableObject(); auto x = MovableObject();
f(x); // lvalue reference shouldn't move out object f(x); // lvalue reference shouldn't move out object
return x.valid; // must still return `true` return x.valid; // must still return `true`
...@@ -159,7 +157,7 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -159,7 +157,7 @@ TEST_SUBMODULE(callbacks, m) {
// test async Python callbacks // test async Python callbacks
using callback_f = std::function<void(int)>; using callback_f = std::function<void(int)>;
m.def("test_async_callback", [](callback_f f, py::list work) { m.def("test_async_callback", [](const callback_f &f, const py::list &work) {
// make detached thread that calls `f` with piece of work after a little delay // make detached thread that calls `f` with piece of work after a little delay
auto start_f = [f](int j) { auto start_f = [f](int j) {
auto invoke_f = [f, j] { auto invoke_f = [f, j] {
...@@ -175,7 +173,7 @@ TEST_SUBMODULE(callbacks, m) { ...@@ -175,7 +173,7 @@ TEST_SUBMODULE(callbacks, m) {
start_f(py::cast<int>(i)); start_f(py::cast<int>(i));
}); });
m.def("callback_num_times", [](py::function f, std::size_t num) { m.def("callback_num_times", [](const py::function &f, std::size_t num) {
for (std::size_t i = 0; i < num; i++) { for (std::size_t i = 0; i < num; i++) {
f(); f();
} }
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include "local_bindings.h" #include "local_bindings.h"
#include <pybind11/stl.h> #include <pybind11/stl.h>
#include <utility>
#if defined(_MSC_VER) #if defined(_MSC_VER)
# pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier # pragma warning(disable: 4324) // warning C4324: structure was padded due to alignment specifier
#endif #endif
...@@ -129,6 +131,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -129,6 +131,7 @@ TEST_SUBMODULE(class_, m) {
m.def("return_none", []() -> BaseClass* { return nullptr; }); m.def("return_none", []() -> BaseClass* { return nullptr; });
// test_isinstance // test_isinstance
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("check_instances", [](py::list l) { m.def("check_instances", [](py::list l) {
return py::make_tuple( return py::make_tuple(
py::isinstance<py::tuple>(l[0]), py::isinstance<py::tuple>(l[0]),
...@@ -155,17 +158,13 @@ TEST_SUBMODULE(class_, m) { ...@@ -155,17 +158,13 @@ TEST_SUBMODULE(class_, m) {
return py::type::of<Invalid>(); return py::type::of<Invalid>();
}); });
m.def("get_type_of", [](py::object ob) { m.def("get_type_of", [](py::object ob) { return py::type::of(std::move(ob)); });
return py::type::of(ob);
});
m.def("get_type_classic", [](py::handle h) { m.def("get_type_classic", [](py::handle h) {
return h.get_type(); return h.get_type();
}); });
m.def("as_type", [](py::object ob) { m.def("as_type", [](const py::object &ob) { return py::type(ob); });
return py::type(ob);
});
// test_mismatched_holder // test_mismatched_holder
struct MismatchBase1 { }; struct MismatchBase1 { };
...@@ -219,6 +218,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -219,6 +218,7 @@ TEST_SUBMODULE(class_, m) {
py::implicitly_convertible<UserType, ConvertibleFromUserType>(); py::implicitly_convertible<UserType, ConvertibleFromUserType>();
m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; }); m.def("implicitly_convert_argument", [](const ConvertibleFromUserType &r) { return r.i; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("implicitly_convert_variable", [](py::object o) { m.def("implicitly_convert_variable", [](py::object o) {
// `o` is `UserType` and `r` is a reference to a temporary created by implicit // `o` is `UserType` and `r` is a reference to a temporary created by implicit
// conversion. This is valid when called inside a bound function because the temp // conversion. This is valid when called inside a bound function because the temp
...@@ -397,6 +397,7 @@ TEST_SUBMODULE(class_, m) { ...@@ -397,6 +397,7 @@ TEST_SUBMODULE(class_, m) {
struct StringWrapper { std::string str; }; struct StringWrapper { std::string str; };
m.def("test_error_after_conversions", [](int) {}); m.def("test_error_after_conversions", [](int) {});
m.def("test_error_after_conversions", m.def("test_error_after_conversions",
// NOLINTNEXTLINE(performance-unnecessary-value-param)
[](StringWrapper) -> NotRegistered { return {}; }); [](StringWrapper) -> NotRegistered { return {}; });
py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>()); py::class_<StringWrapper>(m, "StringWrapper").def(py::init<std::string>());
py::implicitly_convertible<std::string, StringWrapper>(); py::implicitly_convertible<std::string, StringWrapper>();
...@@ -461,19 +462,20 @@ TEST_SUBMODULE(class_, m) { ...@@ -461,19 +462,20 @@ TEST_SUBMODULE(class_, m) {
struct OtherDuplicate {}; struct OtherDuplicate {};
struct DuplicateNested {}; struct DuplicateNested {};
struct OtherDuplicateNested {}; struct OtherDuplicateNested {};
m.def("register_duplicate_class_name", [](py::module_ m) {
m.def("register_duplicate_class_name", [](const py::module_ &m) {
py::class_<Duplicate>(m, "Duplicate"); py::class_<Duplicate>(m, "Duplicate");
py::class_<OtherDuplicate>(m, "Duplicate"); py::class_<OtherDuplicate>(m, "Duplicate");
}); });
m.def("register_duplicate_class_type", [](py::module_ m) { m.def("register_duplicate_class_type", [](const py::module_ &m) {
py::class_<OtherDuplicate>(m, "OtherDuplicate"); py::class_<OtherDuplicate>(m, "OtherDuplicate");
py::class_<OtherDuplicate>(m, "YetAnotherDuplicate"); py::class_<OtherDuplicate>(m, "YetAnotherDuplicate");
}); });
m.def("register_duplicate_nested_class_name", [](py::object gt) { m.def("register_duplicate_nested_class_name", [](const py::object &gt) {
py::class_<DuplicateNested>(gt, "DuplicateNested"); py::class_<DuplicateNested>(gt, "DuplicateNested");
py::class_<OtherDuplicateNested>(gt, "DuplicateNested"); py::class_<OtherDuplicateNested>(gt, "DuplicateNested");
}); });
m.def("register_duplicate_nested_class_type", [](py::object gt) { m.def("register_duplicate_nested_class_type", [](const py::object &gt) {
py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested"); py::class_<OtherDuplicateNested>(gt, "OtherDuplicateNested");
py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested"); py::class_<OtherDuplicateNested>(gt, "YetAnotherDuplicateNested");
}); });
......
...@@ -34,7 +34,7 @@ py::bytes return_bytes() { ...@@ -34,7 +34,7 @@ py::bytes return_bytes() {
return std::string(data, 4); return std::string(data, 4);
} }
std::string print_bytes(py::bytes bytes) { std::string print_bytes(const py::bytes &bytes) {
std::string ret = "bytes["; std::string ret = "bytes[";
const auto value = static_cast<std::string>(bytes); const auto value = static_cast<std::string>(bytes);
for (size_t i = 0; i < value.length(); ++i) { for (size_t i = 0; i < value.length(); ++i) {
...@@ -146,8 +146,13 @@ TEST_SUBMODULE(constants_and_functions, m) { ...@@ -146,8 +146,13 @@ TEST_SUBMODULE(constants_and_functions, m) {
LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here LargeCapture capture; // VS 2015's MSVC is acting up if we create the array here
m.def("should_raise", [capture](int) { return capture.zeros[9] + 33; }, py::kw_only(), py::arg()); m.def("should_raise", [capture](int) { return capture.zeros[9] + 33; }, py::kw_only(), py::arg());
}); });
m.def("register_with_raising_repr", [](py::module_ m, py::object default_value) { m.def("register_with_raising_repr", [](py::module_ m, const py::object &default_value) {
m.def("should_raise", [](int, int, py::object) { return 42; }, "some docstring", m.def(
py::arg_v("x", 42), py::arg_v("y", 42, "<the answer>"), py::arg_v("z", default_value)); "should_raise",
[](int, int, const py::object &) { return 42; },
"some docstring",
py::arg_v("x", 42),
py::arg_v("y", 42, "<the answer>"),
py::arg_v("z", default_value));
}); });
} }
...@@ -37,9 +37,16 @@ template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {}; ...@@ -37,9 +37,16 @@ template <> lacking_move_ctor empty<lacking_move_ctor>::instance_ = {};
class MoveOnlyInt { class MoveOnlyInt {
public: public:
MoveOnlyInt() { print_default_created(this); } MoveOnlyInt() { print_default_created(this); }
MoveOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } MoveOnlyInt(int v) : value{v} { print_created(this, value); }
MoveOnlyInt(MoveOnlyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } MoveOnlyInt(MoveOnlyInt &&m) noexcept {
MoveOnlyInt &operator=(MoveOnlyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } print_move_created(this, m.value);
std::swap(value, m.value);
}
MoveOnlyInt &operator=(MoveOnlyInt &&m) noexcept {
print_move_assigned(this, m.value);
std::swap(value, m.value);
return *this;
}
MoveOnlyInt(const MoveOnlyInt &) = delete; MoveOnlyInt(const MoveOnlyInt &) = delete;
MoveOnlyInt &operator=(const MoveOnlyInt &) = delete; MoveOnlyInt &operator=(const MoveOnlyInt &) = delete;
~MoveOnlyInt() { print_destroyed(this); } ~MoveOnlyInt() { print_destroyed(this); }
...@@ -49,9 +56,16 @@ public: ...@@ -49,9 +56,16 @@ public:
class MoveOrCopyInt { class MoveOrCopyInt {
public: public:
MoveOrCopyInt() { print_default_created(this); } MoveOrCopyInt() { print_default_created(this); }
MoveOrCopyInt(int v) : value{std::move(v)} { print_created(this, value); } MoveOrCopyInt(int v) : value{v} { print_created(this, value); }
MoveOrCopyInt(MoveOrCopyInt &&m) { print_move_created(this, m.value); std::swap(value, m.value); } MoveOrCopyInt(MoveOrCopyInt &&m) noexcept {
MoveOrCopyInt &operator=(MoveOrCopyInt &&m) { print_move_assigned(this, m.value); std::swap(value, m.value); return *this; } print_move_created(this, m.value);
std::swap(value, m.value);
}
MoveOrCopyInt &operator=(MoveOrCopyInt &&m) noexcept {
print_move_assigned(this, m.value);
std::swap(value, m.value);
return *this;
}
MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; } MoveOrCopyInt(const MoveOrCopyInt &c) { print_copy_created(this, c.value); value = c.value; }
MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } MoveOrCopyInt &operator=(const MoveOrCopyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
~MoveOrCopyInt() { print_destroyed(this); } ~MoveOrCopyInt() { print_destroyed(this); }
...@@ -61,7 +75,7 @@ public: ...@@ -61,7 +75,7 @@ public:
class CopyOnlyInt { class CopyOnlyInt {
public: public:
CopyOnlyInt() { print_default_created(this); } CopyOnlyInt() { print_default_created(this); }
CopyOnlyInt(int v) : value{std::move(v)} { print_created(this, value); } CopyOnlyInt(int v) : value{v} { print_created(this, value); }
CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; } CopyOnlyInt(const CopyOnlyInt &c) { print_copy_created(this, c.value); value = c.value; }
CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; } CopyOnlyInt &operator=(const CopyOnlyInt &c) { print_copy_assigned(this, c.value); value = c.value; return *this; }
~CopyOnlyInt() { print_destroyed(this); } ~CopyOnlyInt() { print_destroyed(this); }
...@@ -111,6 +125,7 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -111,6 +125,7 @@ TEST_SUBMODULE(copy_move_policies, m) {
py::return_value_policy::move); py::return_value_policy::move);
// test_move_and_copy_casts // test_move_and_copy_casts
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("move_and_copy_casts", [](py::object o) { m.def("move_and_copy_casts", [](py::object o) {
int r = 0; int r = 0;
r += py::cast<MoveOrCopyInt>(o).value; /* moves */ r += py::cast<MoveOrCopyInt>(o).value; /* moves */
...@@ -126,7 +141,9 @@ TEST_SUBMODULE(copy_move_policies, m) { ...@@ -126,7 +141,9 @@ TEST_SUBMODULE(copy_move_policies, m) {
// test_move_and_copy_loads // test_move_and_copy_loads
m.def("move_only", [](MoveOnlyInt m) { return m.value; }); m.def("move_only", [](MoveOnlyInt m) { return m.value; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; }); m.def("move_or_copy", [](MoveOrCopyInt m) { return m.value; });
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("copy_only", [](CopyOnlyInt m) { return m.value; }); m.def("copy_only", [](CopyOnlyInt m) { return m.value; });
m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) { m.def("move_pair", [](std::pair<MoveOnlyInt, MoveOrCopyInt> p) {
return p.first.value + p.second.value; return p.first.value + p.second.value;
......
...@@ -67,9 +67,12 @@ public: ...@@ -67,9 +67,12 @@ public:
DestructionTester() { print_default_created(this); } DestructionTester() { print_default_created(this); }
~DestructionTester() { print_destroyed(this); } ~DestructionTester() { print_destroyed(this); }
DestructionTester(const DestructionTester &) { print_copy_created(this); } DestructionTester(const DestructionTester &) { print_copy_created(this); }
DestructionTester(DestructionTester &&) { print_move_created(this); } DestructionTester(DestructionTester &&) noexcept { print_move_created(this); }
DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; } DestructionTester &operator=(const DestructionTester &) { print_copy_assigned(this); return *this; }
DestructionTester &operator=(DestructionTester &&) { print_move_assigned(this); return *this; } DestructionTester &operator=(DestructionTester &&) noexcept {
print_move_assigned(this);
return *this;
}
}; };
namespace pybind11 { namespace detail { namespace pybind11 { namespace detail {
template <> struct type_caster<DestructionTester> { template <> struct type_caster<DestructionTester> {
...@@ -94,7 +97,11 @@ TEST_SUBMODULE(custom_type_casters, m) { ...@@ -94,7 +97,11 @@ TEST_SUBMODULE(custom_type_casters, m) {
class ArgInspector { class ArgInspector {
public: public:
ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; } ArgInspector1 f(ArgInspector1 a, ArgAlwaysConverts) { return a; }
std::string g(ArgInspector1 a, const ArgInspector1 &b, int c, ArgInspector2 *d, ArgAlwaysConverts) { std::string g(const ArgInspector1 &a,
const ArgInspector1 &b,
int c,
ArgInspector2 *d,
ArgAlwaysConverts) {
return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg; return a.arg + "\n" + b.arg + "\n" + std::to_string(c) + "\n" + d->arg;
} }
static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; } static ArgInspector2 h(ArgInspector2 a, ArgAlwaysConverts) { return a; }
...@@ -106,8 +113,14 @@ TEST_SUBMODULE(custom_type_casters, m) { ...@@ -106,8 +113,14 @@ TEST_SUBMODULE(custom_type_casters, m) {
.def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts()) .def("g", &ArgInspector::g, "a"_a.noconvert(), "b"_a, "c"_a.noconvert()=13, "d"_a=ArgInspector2(), py::arg() = ArgAlwaysConverts())
.def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts()) .def_static("h", &ArgInspector::h, py::arg{}.noconvert(), py::arg() = ArgAlwaysConverts())
; ;
m.def("arg_inspect_func", [](ArgInspector2 a, ArgInspector1 b, ArgAlwaysConverts) { return a.arg + "\n" + b.arg; }, m.def(
py::arg{}.noconvert(false), py::arg_v(nullptr, ArgInspector1()).noconvert(true), py::arg() = ArgAlwaysConverts()); "arg_inspect_func",
[](const ArgInspector2 &a, const ArgInspector1 &b, ArgAlwaysConverts) {
return a.arg + "\n" + b.arg;
},
py::arg{}.noconvert(false),
py::arg_v(nullptr, ArgInspector1()).noconvert(true),
py::arg() = ArgAlwaysConverts());
m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a); m.def("floats_preferred", [](double f) { return 0.5 * f; }, "f"_a);
m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert()); m.def("floats_only", [](double f) { return 0.5 * f; }, "f"_a.noconvert());
......
...@@ -54,8 +54,7 @@ void reset_refs() { ...@@ -54,8 +54,7 @@ void reset_refs() {
} }
// Returns element 2,1 from a matrix (used to test copy/nocopy) // Returns element 2,1 from a matrix (used to test copy/nocopy)
double get_elem(Eigen::Ref<const Eigen::MatrixXd> m) { return m(2, 1); }; double get_elem(const Eigen::Ref<const Eigen::MatrixXd> &m) { return m(2, 1); };
// Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix // Returns a matrix with 10*r + 100*c added to each matrix element (to help test that the matrix
// reference is referencing rows/columns correctly). // reference is referencing rows/columns correctly).
...@@ -94,14 +93,16 @@ TEST_SUBMODULE(eigen, m) { ...@@ -94,14 +93,16 @@ TEST_SUBMODULE(eigen, m) {
m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; }); m.def("double_complex", [](const Eigen::VectorXcf &x) -> Eigen::VectorXcf { return 2.0f * x; });
m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; }); m.def("double_threec", [](py::EigenDRef<Eigen::Vector3f> x) { x *= 2; });
m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; }); m.def("double_threer", [](py::EigenDRef<Eigen::RowVector3f> x) { x *= 2; });
m.def("double_mat_cm", [](Eigen::MatrixXf x) -> Eigen::MatrixXf { return 2.0f * x; }); m.def("double_mat_cm", [](const Eigen::MatrixXf &x) -> Eigen::MatrixXf { return 2.0f * x; });
m.def("double_mat_rm", [](DenseMatrixR x) -> DenseMatrixR { return 2.0f * x; }); m.def("double_mat_rm", [](const DenseMatrixR &x) -> DenseMatrixR { return 2.0f * x; });
// test_eigen_ref_to_python // test_eigen_ref_to_python
// Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended // Different ways of passing via Eigen::Ref; the first and second are the Eigen-recommended
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("cholesky1", [](Eigen::Ref<MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky1", [](Eigen::Ref<MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky2", [](const Eigen::Ref<const MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky3", [](const Eigen::Ref<MatrixXdR> &x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); }); m.def("cholesky4", [](Eigen::Ref<const MatrixXdR> x) -> Eigen::MatrixXd { return x.llt().matrixL(); });
// test_eigen_ref_mutators // test_eigen_ref_mutators
...@@ -247,8 +248,11 @@ TEST_SUBMODULE(eigen, m) { ...@@ -247,8 +248,11 @@ TEST_SUBMODULE(eigen, m) {
m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; }); m.def("fixed_copy_r", [](const FixedMatrixR &m) -> FixedMatrixR { return m; });
m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; }); m.def("fixed_copy_c", [](const FixedMatrixC &m) -> FixedMatrixC { return m; });
// test_mutator_descriptors // test_mutator_descriptors
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("fixed_mutator_r", [](Eigen::Ref<FixedMatrixR>) {}); m.def("fixed_mutator_r", [](Eigen::Ref<FixedMatrixR>) {});
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {}); m.def("fixed_mutator_c", [](Eigen::Ref<FixedMatrixC>) {});
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {}); m.def("fixed_mutator_a", [](py::EigenDRef<FixedMatrixC>) {});
// test_dense // test_dense
m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); }); m.def("dense_r", [mat]() -> DenseMatrixR { return DenseMatrixR(mat); });
...@@ -280,6 +284,7 @@ TEST_SUBMODULE(eigen, m) { ...@@ -280,6 +284,7 @@ TEST_SUBMODULE(eigen, m) {
// that would allow copying (if types or strides don't match) for comparison: // that would allow copying (if types or strides don't match) for comparison:
m.def("get_elem", &get_elem); m.def("get_elem", &get_elem);
// Now this alternative that calls the tells pybind to fail rather than copy: // Now this alternative that calls the tells pybind to fail rather than copy:
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("get_elem_nocopy", [](Eigen::Ref<const Eigen::MatrixXd> m) -> double { return get_elem(m); }, m.def("get_elem_nocopy", [](Eigen::Ref<const Eigen::MatrixXd> m) -> double { return get_elem(m); },
py::arg{}.noconvert()); py::arg{}.noconvert());
// Also test a row-major-only no-copy const ref: // Also test a row-major-only no-copy const ref:
...@@ -295,13 +300,16 @@ TEST_SUBMODULE(eigen, m) { ...@@ -295,13 +300,16 @@ TEST_SUBMODULE(eigen, m) {
// test_issue1105 // test_issue1105
// Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense // Issue #1105: when converting from a numpy two-dimensional (Nx1) or (1xN) value into a dense
// eigen Vector or RowVector, the argument would fail to load because the numpy copy would fail: // eigen Vector or RowVector, the argument would fail to load because the numpy copy would
// numpy won't broadcast a Nx1 into a 1-dimensional vector. // fail: numpy won't broadcast a Nx1 into a 1-dimensional vector. NOLINTNEXTLINE
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("iss1105_col", [](Eigen::VectorXd) { return true; }); m.def("iss1105_col", [](Eigen::VectorXd) { return true; });
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; }); m.def("iss1105_row", [](Eigen::RowVectorXd) { return true; });
// test_named_arguments // test_named_arguments
// Make sure named arguments are working properly: // Make sure named arguments are working properly:
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B) m.def("matrix_multiply", [](const py::EigenDRef<const Eigen::MatrixXd> A, const py::EigenDRef<const Eigen::MatrixXd> B)
-> Eigen::MatrixXd { -> Eigen::MatrixXd {
if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!"); if (A.cols() != B.rows()) throw std::domain_error("Nonconformable matrices!");
...@@ -318,6 +326,7 @@ TEST_SUBMODULE(eigen, m) { ...@@ -318,6 +326,7 @@ TEST_SUBMODULE(eigen, m) {
// In case of a failure (the caster's temp array does not live long enough), creating // In case of a failure (the caster's temp array does not live long enough), creating
// a new array (np.ones(10)) increases the chances that the temp array will be garbage // a new array (np.ones(10)) increases the chances that the temp array will be garbage
// collected and/or that its memory will be overridden with different values. // collected and/or that its memory will be overridden with different values.
// NOLINTNEXTLINE (performance-unnecessary-value-param)
m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) { m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) {
py::module_::import("numpy").attr("ones")(10); py::module_::import("numpy").attr("ones")(10);
return v(5); return v(5);
......
...@@ -8,16 +8,17 @@ ...@@ -8,16 +8,17 @@
#include <catch.hpp> #include <catch.hpp>
#include <thread>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
#include <thread>
#include <utility>
namespace py = pybind11; namespace py = pybind11;
using namespace py::literals; using namespace py::literals;
class Widget { class Widget {
public: public:
Widget(std::string message) : message(message) { } Widget(std::string message) : message(std::move(message)) {}
virtual ~Widget() = default; virtual ~Widget() = default;
std::string the_message() const { return message; } std::string the_message() const { return message; }
......
...@@ -9,7 +9,9 @@ ...@@ -9,7 +9,9 @@
#include <pybind11/eval.h> #include <pybind11/eval.h>
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <utility>
TEST_SUBMODULE(eval_, m) { TEST_SUBMODULE(eval_, m) {
// test_evals // test_evals
...@@ -67,7 +69,7 @@ TEST_SUBMODULE(eval_, m) { ...@@ -67,7 +69,7 @@ TEST_SUBMODULE(eval_, m) {
int val_out; int val_out;
local["call_test2"] = py::cpp_function([&](int value) { val_out = value; }); local["call_test2"] = py::cpp_function([&](int value) { val_out = value; });
auto result = py::eval_file(filename, global, local); auto result = py::eval_file(std::move(filename), global, local);
return val_out == 43 && result.is_none(); return val_out == 43 && result.is_none();
}); });
......
...@@ -8,7 +8,9 @@ ...@@ -8,7 +8,9 @@
*/ */
#include "test_exceptions.h" #include "test_exceptions.h"
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include <utility>
// A type that should be raised as an exception in Python // A type that should be raised as an exception in Python
class MyException : public std::exception { class MyException : public std::exception {
...@@ -199,6 +201,8 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -199,6 +201,8 @@ TEST_SUBMODULE(exceptions, m) {
throw py::error_already_set(); throw py::error_already_set();
}); });
// Changing this broke things. Don't know why
// NOLINTNEXTLINE(performance-unnecessary-value-param)
m.def("python_call_in_destructor", [](py::dict d) { m.def("python_call_in_destructor", [](py::dict d) {
try { try {
PythonCallInDestructor set_dict_in_destructor(d); PythonCallInDestructor set_dict_in_destructor(d);
...@@ -210,21 +214,23 @@ TEST_SUBMODULE(exceptions, m) { ...@@ -210,21 +214,23 @@ TEST_SUBMODULE(exceptions, m) {
return false; return false;
}); });
m.def("python_alreadyset_in_destructor", [](py::str s) { m.def("python_alreadyset_in_destructor", [](const py::str &s) {
PythonAlreadySetInDestructor alreadyset_in_destructor(s); PythonAlreadySetInDestructor alreadyset_in_destructor(s);
return true; return true;
}); });
// test_nested_throws // test_nested_throws
m.def("try_catch", [m](py::object exc_type, py::function f, py::args args) { m.def("try_catch",
try { f(*args); } [m](const py::object &exc_type, const py::function &f, const py::args &args) {
catch (py::error_already_set &ex) { try {
if (ex.matches(exc_type)) f(*args);
py::print(ex.what()); } catch (py::error_already_set &ex) {
else if (ex.matches(exc_type))
throw; py::print(ex.what());
} else
}); throw;
}
});
// Test repr that cannot be displayed // Test repr that cannot be displayed
m.def("simple_bool_passthrough", [](bool x) {return x;}); m.def("simple_bool_passthrough", [](bool x) {return x;});
......
...@@ -8,10 +8,11 @@ ...@@ -8,10 +8,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 "constructor_stats.h" #include "constructor_stats.h"
#include "pybind11_tests.h"
#include <cmath> #include <cmath>
#include <new> #include <new>
#include <utility>
// Classes for testing python construction via C++ factory function: // Classes for testing python construction via C++ factory function:
// Not publicly constructible, copyable, or movable: // Not publicly constructible, copyable, or movable:
...@@ -35,8 +36,15 @@ class TestFactory2 { ...@@ -35,8 +36,15 @@ class TestFactory2 {
TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); } TestFactory2(int v) : value(std::to_string(v)) { print_created(this, value); }
TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); } TestFactory2(std::string v) : value(std::move(v)) { print_created(this, value); }
public: public:
TestFactory2(TestFactory2 &&m) { value = std::move(m.value); print_move_created(this); } TestFactory2(TestFactory2 &&m) noexcept {
TestFactory2 &operator=(TestFactory2 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } value = std::move(m.value);
print_move_created(this);
}
TestFactory2 &operator=(TestFactory2 &&m) noexcept {
value = std::move(m.value);
print_move_assigned(this);
return *this;
}
std::string value; std::string value;
~TestFactory2() { print_destroyed(this); } ~TestFactory2() { print_destroyed(this); }
}; };
...@@ -48,8 +56,15 @@ protected: ...@@ -48,8 +56,15 @@ protected:
TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); } TestFactory3(int v) : value(std::to_string(v)) { print_created(this, value); }
public: public:
TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); } TestFactory3(std::string v) : value(std::move(v)) { print_created(this, value); }
TestFactory3(TestFactory3 &&m) { value = std::move(m.value); print_move_created(this); } TestFactory3(TestFactory3 &&m) noexcept {
TestFactory3 &operator=(TestFactory3 &&m) { value = std::move(m.value); print_move_assigned(this); return *this; } value = std::move(m.value);
print_move_created(this);
}
TestFactory3 &operator=(TestFactory3 &&m) noexcept {
value = std::move(m.value);
print_move_assigned(this);
return *this;
}
std::string value; std::string value;
virtual ~TestFactory3() { print_destroyed(this); } virtual ~TestFactory3() { print_destroyed(this); }
}; };
...@@ -73,7 +88,11 @@ protected: ...@@ -73,7 +88,11 @@ protected:
bool alias = false; bool alias = false;
public: public:
TestFactory6(int i) : value{i} { print_created(this, i); } TestFactory6(int i) : value{i} { print_created(this, i); }
TestFactory6(TestFactory6 &&f) { print_move_created(this); value = f.value; alias = f.alias; } TestFactory6(TestFactory6 &&f) noexcept {
print_move_created(this);
value = f.value;
alias = f.alias;
}
TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; } TestFactory6(const TestFactory6 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
virtual ~TestFactory6() { print_destroyed(this); } virtual ~TestFactory6() { print_destroyed(this); }
virtual int get() { return value; } virtual int get() { return value; }
...@@ -85,7 +104,7 @@ public: ...@@ -85,7 +104,7 @@ public:
// when an alias is needed: // when an alias is needed:
PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); } PyTF6(TestFactory6 &&base) : TestFactory6(std::move(base)) { alias = true; print_created(this, "move", value); }
PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); } PyTF6(int i) : TestFactory6(i) { alias = true; print_created(this, i); }
PyTF6(PyTF6 &&f) : TestFactory6(std::move(f)) { print_move_created(this); } PyTF6(PyTF6 &&f) noexcept : TestFactory6(std::move(f)) { print_move_created(this); }
PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); } PyTF6(const PyTF6 &f) : TestFactory6(f) { print_copy_created(this); }
PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); } PyTF6(std::string s) : TestFactory6((int) s.size()) { alias = true; print_created(this, s); }
~PyTF6() override { print_destroyed(this); } ~PyTF6() override { print_destroyed(this); }
...@@ -98,7 +117,11 @@ protected: ...@@ -98,7 +117,11 @@ protected:
bool alias = false; bool alias = false;
public: public:
TestFactory7(int i) : value{i} { print_created(this, i); } TestFactory7(int i) : value{i} { print_created(this, i); }
TestFactory7(TestFactory7 &&f) { print_move_created(this); value = f.value; alias = f.alias; } TestFactory7(TestFactory7 &&f) noexcept {
print_move_created(this);
value = f.value;
alias = f.alias;
}
TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; } TestFactory7(const TestFactory7 &f) { print_copy_created(this); value = f.value; alias = f.alias; }
virtual ~TestFactory7() { print_destroyed(this); } virtual ~TestFactory7() { print_destroyed(this); }
virtual int get() { return value; } virtual int get() { return value; }
...@@ -107,7 +130,7 @@ public: ...@@ -107,7 +130,7 @@ public:
class PyTF7 : public TestFactory7 { class PyTF7 : public TestFactory7 {
public: public:
PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); } PyTF7(int i) : TestFactory7(i) { alias = true; print_created(this, i); }
PyTF7(PyTF7 &&f) : TestFactory7(std::move(f)) { print_move_created(this); } PyTF7(PyTF7 &&f) noexcept : TestFactory7(std::move(f)) { print_move_created(this); }
PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); } PyTF7(const PyTF7 &f) : TestFactory7(f) { print_copy_created(this); }
~PyTF7() override { print_destroyed(this); } ~PyTF7() override { print_destroyed(this); }
int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); } int get() override { PYBIND11_OVERRIDE(int, TestFactory7, get, /*no args*/); }
...@@ -122,7 +145,9 @@ public: ...@@ -122,7 +145,9 @@ public:
// Holder: // Holder:
static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); } static std::unique_ptr<TestFactory1> construct1(int a) { return std::unique_ptr<TestFactory1>(new TestFactory1(a)); }
// pointer again // pointer again
static TestFactory1 *construct1_string(std::string a) { return new TestFactory1(a); } static TestFactory1 *construct1_string(std::string a) {
return new TestFactory1(std::move(a));
}
// Moveable type: // Moveable type:
// pointer: // pointer:
...@@ -130,7 +155,7 @@ public: ...@@ -130,7 +155,7 @@ public:
// holder: // holder:
static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); } static std::unique_ptr<TestFactory2> construct2(int a) { return std::unique_ptr<TestFactory2>(new TestFactory2(a)); }
// by value moving: // by value moving:
static TestFactory2 construct2(std::string a) { return TestFactory2(a); } static TestFactory2 construct2(std::string a) { return TestFactory2(std::move(a)); }
// shared_ptr holder type: // shared_ptr holder type:
// pointer: // pointer:
...@@ -173,10 +198,11 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -173,10 +198,11 @@ TEST_SUBMODULE(factory_constructors, m) {
; ;
py::class_<TestFactory2>(m, "TestFactory2") py::class_<TestFactory2>(m, "TestFactory2")
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); })) .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
.def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); })) .def(py::init([](unique_ptr_tag, std::string v) {
return TestFactoryHelper::construct2(std::move(v));
}))
.def(py::init([](move_tag) { return TestFactoryHelper::construct2(); })) .def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
.def_readwrite("value", &TestFactory2::value) .def_readwrite("value", &TestFactory2::value);
;
// Stateful & reused: // Stateful & reused:
int c = 1; int c = 1;
...@@ -188,7 +214,9 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -188,7 +214,9 @@ TEST_SUBMODULE(factory_constructors, m) {
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); })) .def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct3(v); }))
.def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); })); .def(py::init([](shared_ptr_tag) { return TestFactoryHelper::construct3(); }));
ignoreOldStyleInitWarnings([&pyTestFactory3]() { ignoreOldStyleInitWarnings([&pyTestFactory3]() {
pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) { new (&self) TestFactory3(v); }); // placement-new ctor pyTestFactory3.def("__init__", [](TestFactory3 &self, std::string v) {
new (&self) TestFactory3(std::move(v));
}); // placement-new ctor
}); });
pyTestFactory3 pyTestFactory3
// factories returning a derived type: // factories returning a derived type:
...@@ -219,52 +247,54 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -219,52 +247,54 @@ TEST_SUBMODULE(factory_constructors, m) {
py::class_<TestFactory6, PyTF6>(m, "TestFactory6") py::class_<TestFactory6, PyTF6>(m, "TestFactory6")
.def(py::init([](base_tag, int i) { return TestFactory6(i); })) .def(py::init([](base_tag, int i) { return TestFactory6(i); }))
.def(py::init([](alias_tag, int i) { return PyTF6(i); })) .def(py::init([](alias_tag, int i) { return PyTF6(i); }))
.def(py::init([](alias_tag, std::string s) { return PyTF6(s); })) .def(py::init([](alias_tag, std::string s) { return PyTF6(std::move(s)); }))
.def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); })) .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF6(i); }))
.def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); })) .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory6(i); }))
.def(py::init([](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); })) .def(py::init(
[](base_tag, alias_tag, pointer_tag, int i) { return (TestFactory6 *) new PyTF6(i); }))
.def("get", &TestFactory6::get) .def("get", &TestFactory6::get)
.def("has_alias", &TestFactory6::has_alias) .def("has_alias", &TestFactory6::has_alias)
.def_static("get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference) .def_static(
.def_static("get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference) "get_cstats", &ConstructorStats::get<TestFactory6>, py::return_value_policy::reference)
; .def_static(
"get_alias_cstats", &ConstructorStats::get<PyTF6>, py::return_value_policy::reference);
// test_init_factory_dual // test_init_factory_dual
// Separate alias constructor testing // Separate alias constructor testing
py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7") py::class_<TestFactory7, PyTF7, std::shared_ptr<TestFactory7>>(m, "TestFactory7")
.def(py::init( .def(py::init([](int i) { return TestFactory7(i); }, [](int i) { return PyTF7(i); }))
[](int i) { return TestFactory7(i); }, .def(py::init([](pointer_tag, int i) { return new TestFactory7(i); },
[](int i) { return PyTF7(i); })) [](pointer_tag, int i) { return new PyTF7(i); }))
.def(py::init( .def(py::init([](mixed_tag, int i) { return new TestFactory7(i); },
[](pointer_tag, int i) { return new TestFactory7(i); }, [](mixed_tag, int i) { return PyTF7(i); }))
[](pointer_tag, int i) { return new PyTF7(i); })) .def(py::init([](mixed_tag, const std::string &s) { return TestFactory7((int) s.size()); },
.def(py::init( [](mixed_tag, const std::string &s) { return new PyTF7((int) s.size()); }))
[](mixed_tag, int i) { return new TestFactory7(i); }, .def(py::init([](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
[](mixed_tag, int i) { return PyTF7(i); })) [](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
.def(py::init( .def(py::init([](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
[](mixed_tag, std::string s) { return TestFactory7((int) s.size()); }, [](alias_tag, pointer_tag, int i) { return new PyTF7(10 * i); }))
[](mixed_tag, std::string s) { return new PyTF7((int) s.size()); }))
.def(py::init(
[](base_tag, pointer_tag, int i) { return new TestFactory7(i); },
[](base_tag, pointer_tag, int i) { return (TestFactory7 *) new PyTF7(i); }))
.def(py::init(
[](alias_tag, pointer_tag, int i) { return new PyTF7(i); },
[](alias_tag, pointer_tag, int i) { return new PyTF7(10*i); }))
.def(py::init( .def(py::init(
[](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); }, [](shared_ptr_tag, base_tag, int i) { return std::make_shared<TestFactory7>(i); },
[](shared_ptr_tag, base_tag, int i) { auto *p = new PyTF7(i); return std::shared_ptr<TestFactory7>(p); })) [](shared_ptr_tag, base_tag, int i) {
.def(py::init( auto *p = new PyTF7(i);
[](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); }, return std::shared_ptr<TestFactory7>(p);
[](shared_ptr_tag, invalid_base_tag, int i) { return std::make_shared<TestFactory7>(i); })) // <-- invalid alias factory }))
.def(py::init([](shared_ptr_tag,
invalid_base_tag,
int i) { return std::make_shared<TestFactory7>(i); },
[](shared_ptr_tag, invalid_base_tag, int i) {
return std::make_shared<TestFactory7>(i);
})) // <-- invalid alias factory
.def("get", &TestFactory7::get) .def("get", &TestFactory7::get)
.def("has_alias", &TestFactory7::has_alias) .def("has_alias", &TestFactory7::has_alias)
.def_static("get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference) .def_static(
.def_static("get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference) "get_cstats", &ConstructorStats::get<TestFactory7>, py::return_value_policy::reference)
; .def_static(
"get_alias_cstats", &ConstructorStats::get<PyTF7>, py::return_value_policy::reference);
// test_placement_new_alternative // test_placement_new_alternative
// Class with a custom new operator but *without* a placement new operator (issue #948) // Class with a custom new operator but *without* a placement new operator (issue #948)
...@@ -331,12 +361,10 @@ TEST_SUBMODULE(factory_constructors, m) { ...@@ -331,12 +361,10 @@ TEST_SUBMODULE(factory_constructors, m) {
pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); })); pyNoisyAlloc.def(py::init([](int i, double) { return new NoisyAlloc(i); }));
// Regular again: requires yet another preallocation // Regular again: requires yet another preallocation
ignoreOldStyleInitWarnings([&pyNoisyAlloc]() { ignoreOldStyleInitWarnings([&pyNoisyAlloc]() {
pyNoisyAlloc.def("__init__", [](NoisyAlloc &a, int i, std::string) { new (&a) NoisyAlloc(i); }); pyNoisyAlloc.def(
"__init__", [](NoisyAlloc &a, int i, const std::string &) { new (&a) NoisyAlloc(i); });
}); });
// static_assert testing (the following def's should all fail with appropriate compilation errors): // static_assert testing (the following def's should all fail with appropriate compilation errors):
#if 0 #if 0
struct BadF1Base {}; struct BadF1Base {};
......
...@@ -35,20 +35,15 @@ TEST_SUBMODULE(gil_scoped, m) { ...@@ -35,20 +35,15 @@ TEST_SUBMODULE(gil_scoped, m) {
.def("virtual_func", &VirtClass::virtual_func) .def("virtual_func", &VirtClass::virtual_func)
.def("pure_virtual_func", &VirtClass::pure_virtual_func); .def("pure_virtual_func", &VirtClass::pure_virtual_func);
m.def("test_callback_py_obj", m.def("test_callback_py_obj", [](py::object &func) { func(); });
[](py::object func) { func(); }); m.def("test_callback_std_func", [](const std::function<void()> &func) { func(); });
m.def("test_callback_std_func", m.def("test_callback_virtual_func", [](VirtClass &virt) { virt.virtual_func(); });
[](const std::function<void()> &func) { func(); }); m.def("test_callback_pure_virtual_func", [](VirtClass &virt) { virt.pure_virtual_func(); });
m.def("test_callback_virtual_func", m.def("test_cross_module_gil", []() {
[](VirtClass &virt) { virt.virtual_func(); }); auto cm = py::module_::import("cross_module_gil_utils");
m.def("test_callback_pure_virtual_func", auto gil_acquire
[](VirtClass &virt) { virt.pure_virtual_func(); }); = reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
m.def("test_cross_module_gil", py::gil_scoped_release gil_release;
[]() { gil_acquire();
auto cm = py::module_::import("cross_module_gil_utils"); });
auto gil_acquire = reinterpret_cast<void (*)()>(
PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
py::gil_scoped_release gil_release;
gil_acquire();
});
} }
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