maint(clang-tidy): Improve code readability with explicit boolean casts (#3148)

* maint(clang-tidy) Improve code readability

* Fix minor typos

* Revert optimization that removed test case

* Fix comment formatting

* Revert another optimization to repro an issue

* Remove make_unique since it C++14 and newer only

* eformat comments

* Fix unsignedness of comparison

* Update comment
This commit is contained in:
Aaron Gokaslan 2021-07-27 18:32:26 -04:00 committed by GitHub
parent 7cc0ebb475
commit 9beaa925db
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 73 additions and 44 deletions

View File

@ -5,13 +5,17 @@ cppcoreguidelines-init-variables,
clang-analyzer-optin.cplusplus.VirtualCall, clang-analyzer-optin.cplusplus.VirtualCall,
llvm-namespace-comment, llvm-namespace-comment,
misc-misplaced-const, misc-misplaced-const,
misc-non-copyable-objects,
misc-static-assert, misc-static-assert,
misc-throw-by-value-catch-by-reference, misc-throw-by-value-catch-by-reference,
misc-uniqueptr-reset-release, misc-uniqueptr-reset-release,
misc-unused-parameters,
modernize-avoid-bind, modernize-avoid-bind,
modernize-make-shared,
modernize-redundant-void-arg, modernize-redundant-void-arg,
modernize-replace-auto-ptr, modernize-replace-auto-ptr,
modernize-replace-disallow-copy-and-assign-macro, modernize-replace-disallow-copy-and-assign-macro,
modernize-replace-random-shuffle,
modernize-shrink-to-fit, modernize-shrink-to-fit,
modernize-use-auto, modernize-use-auto,
modernize-use-bool-literals, modernize-use-bool-literals,
@ -23,13 +27,20 @@ modernize-use-emplace,
modernize-use-override, modernize-use-override,
modernize-use-using, modernize-use-using,
*performance*, *performance*,
readability-avoid-const-params-in-decls,
readability-container-size-empty, readability-container-size-empty,
readability-else-after-return, readability-else-after-return,
readability-delete-null-pointer,
readability-implicit-bool-conversion,
readability-make-member-function-const, readability-make-member-function-const,
readability-misplaced-array-index,
readability-non-const-parameter,
readability-redundant-function-ptr-dereference, readability-redundant-function-ptr-dereference,
readability-redundant-smartptr-get, readability-redundant-smartptr-get,
readability-redundant-string-cstr, readability-redundant-string-cstr,
readability-simplify-subscript-expr, readability-simplify-subscript-expr,
readability-static-accessed-through-instance,
readability-static-definition-in-anonymous-namespace,
readability-string-compare, readability-string-compare,
readability-uniqueptr-delete-release, readability-uniqueptr-delete-release,
' '
@ -39,6 +50,8 @@ CheckOptions:
value: true value: true
- key: performance-unnecessary-value-param.AllowedTypes - key: performance-unnecessary-value-param.AllowedTypes
value: 'exception_ptr$;' value: 'exception_ptr$;'
- key: readability-implicit-bool-conversion.AllowPointerConditions
value: true
HeaderFilterRegex: 'pybind11/.*h' HeaderFilterRegex: 'pybind11/.*h'

View File

@ -181,7 +181,7 @@ public:
// Signed/unsigned checks happen elsewhere // Signed/unsigned checks happen elsewhere
if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) { if (py_err || (std::is_integral<T>::value && sizeof(py_type) != sizeof(T) && py_value != (py_type) (T) py_value)) {
PyErr_Clear(); PyErr_Clear();
if (py_err && convert && PyNumber_Check(src.ptr())) { if (py_err && convert && (PyNumber_Check(src.ptr()) != 0)) {
auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value auto tmp = reinterpret_steal<object>(std::is_floating_point<T>::value
? PyNumber_Float(src.ptr()) ? PyNumber_Float(src.ptr())
: PyNumber_Long(src.ptr())); : PyNumber_Long(src.ptr()));
@ -300,7 +300,7 @@ public:
value = false; value = false;
return true; return true;
} }
if (convert || !std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name)) { if (convert || (std::strcmp("numpy.bool_", Py_TYPE(src.ptr())->tp_name) == 0)) {
// (allow non-implicit conversion for numpy booleans) // (allow non-implicit conversion for numpy booleans)
Py_ssize_t res = -1; Py_ssize_t res = -1;
@ -501,10 +501,14 @@ public:
// can fit into a single char value. // can fit into a single char value.
if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) { if (StringCaster::UTF_N == 8 && str_len > 1 && str_len <= 4) {
auto v0 = static_cast<unsigned char>(value[0]); auto v0 = static_cast<unsigned char>(value[0]);
size_t char0_bytes = !(v0 & 0x80) ? 1 : // low bits only: 0-127 // low bits only: 0-127
(v0 & 0xE0) == 0xC0 ? 2 : // 0b110xxxxx - start of 2-byte sequence // 0b110xxxxx - start of 2-byte sequence
(v0 & 0xF0) == 0xE0 ? 3 : // 0b1110xxxx - start of 3-byte sequence // 0b1110xxxx - start of 3-byte sequence
4; // 0b11110xxx - start of 4-byte sequence // 0b11110xxx - start of 4-byte sequence
size_t char0_bytes = (v0 & 0x80) == 0 ? 1
: (v0 & 0xE0) == 0xC0 ? 2
: (v0 & 0xF0) == 0xE0 ? 3
: 4;
if (char0_bytes == str_len) { if (char0_bytes == str_len) {
// If we have a 128-255 value, we can decode it into a single char: // If we have a 128-255 value, we can decode it into a single char:

View File

@ -129,8 +129,9 @@ extern "C" inline int pybind11_meta_setattro(PyObject* obj, PyObject* name, PyOb
// 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop` // 2. `Type.static_prop = other_static_prop` --> setattro: replace existing `static_prop`
// 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment // 3. `Type.regular_attribute = value` --> setattro: regular attribute assignment
const auto static_prop = (PyObject *) get_internals().static_property_type; const auto static_prop = (PyObject *) get_internals().static_property_type;
const auto call_descr_set = descr && value && PyObject_IsInstance(descr, static_prop) const auto call_descr_set = (descr != nullptr) && (value != nullptr)
&& !PyObject_IsInstance(value, static_prop); && (PyObject_IsInstance(descr, static_prop) != 0)
&& (PyObject_IsInstance(value, static_prop) == 0);
if (call_descr_set) { if (call_descr_set) {
// Call `static_property.__set__()` instead of replacing the `static_property`. // Call `static_property.__set__()` instead of replacing the `static_property`.
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
@ -562,7 +563,7 @@ extern "C" inline int pybind11_getbuffer(PyObject *obj, Py_buffer *view, int fla
view->len = view->itemsize; view->len = view->itemsize;
for (auto s : info->shape) for (auto s : info->shape)
view->len *= s; view->len *= s;
view->readonly = info->readonly; view->readonly = static_cast<int>(info->readonly);
if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT)
view->format = const_cast<char *>(info->format.c_str()); view->format = const_cast<char *>(info->format.c_str());
if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) { if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {

View File

@ -297,7 +297,7 @@ PYBIND11_NOINLINE inline internals &get_internals() {
PyThreadState *tstate = PyThreadState_Get(); PyThreadState *tstate = PyThreadState_Get();
#if PY_VERSION_HEX >= 0x03070000 #if PY_VERSION_HEX >= 0x03070000
internals_ptr->tstate = PyThread_tss_alloc(); internals_ptr->tstate = PyThread_tss_alloc();
if (!internals_ptr->tstate || PyThread_tss_create(internals_ptr->tstate)) if (!internals_ptr->tstate || (PyThread_tss_create(internals_ptr->tstate) != 0))
pybind11_fail("get_internals: could not successfully initialize the TSS key!"); pybind11_fail("get_internals: could not successfully initialize the TSS key!");
PyThread_tss_set(internals_ptr->tstate, tstate); PyThread_tss_set(internals_ptr->tstate, tstate);
#else #else

View File

@ -239,7 +239,7 @@ struct value_and_holder {
bool holder_constructed() const { bool holder_constructed() const {
return inst->simple_layout return inst->simple_layout
? inst->simple_holder_constructed ? inst->simple_holder_constructed
: inst->nonsimple.status[index] & instance::status_holder_constructed; : (inst->nonsimple.status[index] & instance::status_holder_constructed) != 0u;
} }
void set_holder_constructed(bool v = true) const { void set_holder_constructed(bool v = true) const {
if (inst->simple_layout) if (inst->simple_layout)

View File

@ -76,7 +76,7 @@ struct embedded_module {
using init_t = void (*)(); using init_t = void (*)();
#endif #endif
embedded_module(const char *name, init_t init) { embedded_module(const char *name, init_t init) {
if (Py_IsInitialized()) if (Py_IsInitialized() != 0)
pybind11_fail("Can't add new modules after the interpreter has been initialized"); pybind11_fail("Can't add new modules after the interpreter has been initialized");
auto result = PyImport_AppendInittab(name, init); auto result = PyImport_AppendInittab(name, init);
@ -101,7 +101,7 @@ PYBIND11_NAMESPACE_END(detail)
.. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx .. _Python documentation: https://docs.python.org/3/c-api/init.html#c.Py_InitializeEx
\endrst */ \endrst */
inline void initialize_interpreter(bool init_signal_handlers = true) { inline void initialize_interpreter(bool init_signal_handlers = true) {
if (Py_IsInitialized()) if (Py_IsInitialized() != 0)
pybind11_fail("The interpreter is already running"); pybind11_fail("The interpreter is already running");
Py_InitializeEx(init_signal_handlers ? 1 : 0); Py_InitializeEx(init_signal_handlers ? 1 : 0);

View File

@ -465,7 +465,9 @@ public:
explicit dtype(const buffer_info &info) { explicit dtype(const buffer_info &info) {
dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format))); dtype descr(_dtype_from_pep3118()(PYBIND11_STR_TYPE(info.format)));
// If info.itemsize == 0, use the value calculated from the format string // If info.itemsize == 0, use the value calculated from the format string
m_ptr = descr.strip_padding(info.itemsize ? info.itemsize : descr.itemsize()).release().ptr(); m_ptr = descr.strip_padding(info.itemsize != 0 ? info.itemsize : descr.itemsize())
.release()
.ptr();
} }
explicit dtype(const std::string &format) { explicit dtype(const std::string &format) {
@ -486,7 +488,7 @@ public:
/// This is essentially the same as calling numpy.dtype(args) in Python. /// This is essentially the same as calling numpy.dtype(args) in Python.
static dtype from_args(object args) { static dtype from_args(object args) {
PyObject *ptr = nullptr; PyObject *ptr = nullptr;
if (!detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) || !ptr) if ((detail::npy_api::get().PyArray_DescrConverter_(args.ptr(), &ptr) == 0) || !ptr)
throw error_already_set(); throw error_already_set();
return reinterpret_steal<dtype>(ptr); return reinterpret_steal<dtype>(ptr);
} }
@ -542,7 +544,7 @@ private:
auto name = spec[0].cast<pybind11::str>(); auto name = spec[0].cast<pybind11::str>();
auto format = spec[1].cast<tuple>()[0].cast<dtype>(); auto format = spec[1].cast<tuple>()[0].cast<dtype>();
auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>(); auto offset = spec[1].cast<tuple>()[1].cast<pybind11::int_>();
if (!len(name) && format.kind() == 'V') if ((len(name) == 0u) && format.kind() == 'V')
continue; continue;
field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset}); field_descriptors.push_back({(PYBIND11_STR_TYPE) name, format.strip_padding(format.itemsize()), offset});
} }
@ -872,11 +874,12 @@ public:
: array(std::move(shape), std::move(strides), ptr, base) { } : array(std::move(shape), std::move(strides), ptr, base) { }
explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle()) explicit array_t(ShapeContainer shape, const T *ptr = nullptr, handle base = handle())
: array_t(private_ctor{}, std::move(shape), : array_t(private_ctor{},
ExtraFlags & f_style std::move(shape),
? detail::f_strides(*shape, itemsize()) (ExtraFlags & f_style) != 0 ? detail::f_strides(*shape, itemsize())
: detail::c_strides(*shape, itemsize()), : detail::c_strides(*shape, itemsize()),
ptr, base) { } ptr,
base) {}
explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle()) explicit array_t(ssize_t count, const T *ptr = nullptr, handle base = handle())
: array({count}, {}, ptr, base) { } : array({count}, {}, ptr, base) { }

View File

@ -318,7 +318,8 @@ protected:
a.descr = guarded_strdup(repr(a.value).cast<std::string>().c_str()); a.descr = guarded_strdup(repr(a.value).cast<std::string>().c_str());
} }
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__"); rec->is_constructor
= (strcmp(rec->name, "__init__") == 0) || (strcmp(rec->name, "__setstate__") == 0);
#if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING) #if !defined(NDEBUG) && !defined(PYBIND11_DISABLE_NEW_STYLE_INIT_WARNING)
if (rec->is_constructor && !rec->is_new_style_constructor) { if (rec->is_constructor && !rec->is_new_style_constructor) {
@ -1131,7 +1132,8 @@ protected:
pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) + pybind11_fail("generic_type: cannot initialize type \"" + std::string(rec.name) +
"\": an object with that name is already defined"); "\": an object with that name is already defined");
if (rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type)) if ((rec.module_local ? get_local_type_info(*rec.type) : get_global_type_info(*rec.type))
!= nullptr)
pybind11_fail("generic_type: type \"" + std::string(rec.name) + pybind11_fail("generic_type: type \"" + std::string(rec.name) +
"\" is already registered!"); "\" is already registered!");
@ -1209,8 +1211,9 @@ protected:
void def_property_static_impl(const char *name, void def_property_static_impl(const char *name,
handle fget, handle fset, handle fget, handle fset,
detail::function_record *rec_func) { detail::function_record *rec_func) {
const auto is_static = rec_func && !(rec_func->is_method && rec_func->scope); const auto is_static = (rec_func != nullptr) && !(rec_func->is_method && rec_func->scope);
const auto has_doc = rec_func && rec_func->doc && pybind11::options::show_user_defined_docstrings(); const auto has_doc = (rec_func != nullptr) && (rec_func->doc != nullptr)
&& pybind11::options::show_user_defined_docstrings();
auto property = handle((PyObject *) (is_static ? get_internals().static_property_type auto property = handle((PyObject *) (is_static ? get_internals().static_property_type
: &PyProperty_Type)); : &PyProperty_Type));
attr(name) = property(fget.ptr() ? fget : none(), attr(name) = property(fget.ptr() ? fget : none(),
@ -2220,8 +2223,8 @@ inline function get_type_override(const void *this_ptr, const type_info *this_ty
Unfortunately this doesn't work on PyPy. */ Unfortunately this doesn't work on PyPy. */
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
PyFrameObject *frame = PyThreadState_Get()->frame; PyFrameObject *frame = PyThreadState_Get()->frame;
if (frame && (std::string) str(frame->f_code->co_name) == name && if (frame != nullptr && (std::string) str(frame->f_code->co_name) == name
frame->f_code->co_argcount > 0) { && frame->f_code->co_argcount > 0) {
PyFrame_FastToLocals(frame); PyFrame_FastToLocals(frame);
PyObject *self_caller = dict_getitem( PyObject *self_caller = dict_getitem(
frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0)); frame->f_locals, PyTuple_GET_ITEM(frame->f_code->co_varnames, 0));

View File

@ -773,7 +773,11 @@ protected:
dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); } dict_readonly(handle obj, ssize_t pos) : obj(obj), pos(pos) { increment(); }
reference dereference() const { return {key, value}; } reference dereference() const { return {key, value}; }
void increment() { if (!PyDict_Next(obj.ptr(), &pos, &key, &value)) { pos = -1; } } void increment() {
if (PyDict_Next(obj.ptr(), &pos, &key, &value) == 0) {
pos = -1;
}
}
bool equal(const dict_readonly &b) const { return pos == b.pos; } bool equal(const dict_readonly &b) const { return pos == b.pos; }
private: private:
@ -1169,14 +1173,14 @@ public:
bool_() : object(Py_False, borrowed_t{}) { } bool_() : object(Py_False, borrowed_t{}) { }
// Allow implicit conversion from and to `bool`: // Allow implicit conversion from and to `bool`:
bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { } bool_(bool value) : object(value ? Py_True : Py_False, borrowed_t{}) { }
operator bool() const { return m_ptr && PyLong_AsLong(m_ptr) != 0; } operator bool() const { return (m_ptr != nullptr) && PyLong_AsLong(m_ptr) != 0; }
private: private:
/// Return the truth value of an object -- always returns a new reference /// Return the truth value of an object -- always returns a new reference
static PyObject *raw_bool(PyObject *op) { static PyObject *raw_bool(PyObject *op) {
const auto value = PyObject_IsTrue(op); const auto value = PyObject_IsTrue(op);
if (value == -1) return nullptr; if (value == -1) return nullptr;
return handle(value ? Py_True : Py_False).inc_ref().ptr(); return handle(value != 0 ? Py_True : Py_False).inc_ref().ptr();
} }
}; };
@ -1607,7 +1611,7 @@ inline memoryview memoryview::from_buffer(
size_t ndim = shape->size(); size_t ndim = shape->size();
if (ndim != strides->size()) if (ndim != strides->size())
pybind11_fail("memoryview: shape length doesn't match strides length"); pybind11_fail("memoryview: shape length doesn't match strides length");
ssize_t size = ndim ? 1 : 0; ssize_t size = ndim != 0u ? 1 : 0;
for (size_t i = 0; i < ndim; ++i) for (size_t i = 0; i < ndim; ++i)
size *= (*shape)[i]; size *= (*shape)[i];
Py_buffer view; Py_buffer view;

View File

@ -67,7 +67,7 @@ public:
} }
PyObject* native = nullptr; PyObject* native = nullptr;
if constexpr (std::is_same_v<typename T::value_type, char>) { if constexpr (std::is_same_v<typename T::value_type, char>) {
if (PyUnicode_FSConverter(buf, &native)) { if (PyUnicode_FSConverter(buf, &native) != 0) {
if (auto c_str = PyBytes_AsString(native)) { if (auto c_str = PyBytes_AsString(native)) {
// AsString returns a pointer to the internal buffer, which // AsString returns a pointer to the internal buffer, which
// must not be free'd. // must not be free'd.
@ -75,7 +75,7 @@ public:
} }
} }
} else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) { } else if constexpr (std::is_same_v<typename T::value_type, wchar_t>) {
if (PyUnicode_FSDecoder(buf, &native)) { if (PyUnicode_FSDecoder(buf, &native) != 0) {
if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) { if (auto c_str = PyUnicode_AsWideCharString(native, nullptr)) {
// AsWideCharString returns a new string that must be free'd. // AsWideCharString returns a new string that must be free'd.
value = c_str; // Copies the string. value = c_str; // Copies the string.

View File

@ -103,7 +103,7 @@ bool has_pybind11_internals_builtin() {
bool has_pybind11_internals_static() { bool has_pybind11_internals_static() {
auto **&ipp = py::detail::get_internals_pp(); auto **&ipp = py::detail::get_internals_pp();
return ipp && *ipp; return (ipp != nullptr) && (*ipp != nullptr);
} }
TEST_CASE("Restart the interpreter") { TEST_CASE("Restart the interpreter") {

View File

@ -43,6 +43,7 @@ public:
void add6(int other) { value += other; } // passing by value void add6(int other) { value += other; } // passing by value
void add7(int &other) { value += other; } // passing by reference void add7(int &other) { value += other; } // passing by reference
void add8(const int &other) { value += other; } // passing by const reference void add8(const int &other) { value += other; } // passing by const reference
// NOLINTNEXTLINE(readability-non-const-parameter) Deliberately non-const for testing
void add9(int *other) { value += *other; } // passing by pointer void add9(int *other) { value += *other; } // passing by pointer
void add10(const int *other) { value += *other; } // passing by const pointer void add10(const int *other) { value += *other; } // passing by const pointer

View File

@ -108,9 +108,11 @@ PYBIND11_PACKED(struct EnumStruct {
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]; i++) os << v.a[i]; for (size_t i = 0; i < 3 && (v.a[i] != 0); i++)
os << v.a[i];
os << "',b='"; os << "',b='";
for (size_t i = 0; i < 3 && v.b[i]; i++) os << v.b[i]; for (size_t i = 0; i < 3 && (v.b[i] != 0); i++)
os << v.b[i];
return os << "'"; return os << "'";
} }

View File

@ -59,7 +59,7 @@ TEST_SUBMODULE(numpy_vectorize, m) {
.def(py::init<int>()) .def(py::init<int>())
.def_readwrite("value", &NonPODClass::value); .def_readwrite("value", &NonPODClass::value);
m.def("vec_passthrough", m.def("vec_passthrough",
py::vectorize([](double *a, py::vectorize([](const double *a,
double b, double b,
// Changing this broke things // Changing this broke things
// NOLINTNEXTLINE(performance-unnecessary-value-param) // NOLINTNEXTLINE(performance-unnecessary-value-param)

View File

@ -101,7 +101,7 @@ private:
// test_unique_nodelete // test_unique_nodelete
// Object with a private destructor // Object with a private destructor
class MyObject4; class MyObject4;
static std::unordered_set<MyObject4 *> myobject4_instances; std::unordered_set<MyObject4 *> myobject4_instances;
class MyObject4 { class MyObject4 {
public: public:
MyObject4(int value) : value{value} { MyObject4(int value) : value{value} {
@ -127,7 +127,7 @@ private:
// Object with std::unique_ptr<T, D> where D is not matching the base class // Object with std::unique_ptr<T, D> where D is not matching the base class
// Object with a protected destructor // Object with a protected destructor
class MyObject4a; class MyObject4a;
static std::unordered_set<MyObject4a *> myobject4a_instances; std::unordered_set<MyObject4a *> myobject4a_instances;
class MyObject4a { class MyObject4a {
public: public:
MyObject4a(int i) { MyObject4a(int i) {

View File

@ -102,7 +102,7 @@ TEST_SUBMODULE(stl, m) {
// test_set // test_set
m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; }); m.def("cast_set", []() { return std::set<std::string>{"key1", "key2"}; });
m.def("load_set", [](const std::set<std::string> &set) { m.def("load_set", [](const std::set<std::string> &set) {
return set.count("key1") && set.count("key2") && set.count("key3"); return (set.count("key1") != 0u) && (set.count("key2") != 0u) && (set.count("key3") != 0u);
}); });
// test_recursive_casting // test_recursive_casting
@ -196,9 +196,7 @@ TEST_SUBMODULE(stl, m) {
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 { m.def("half_or_none", [](int x) -> opt_int { return x != 0 ? opt_int(x / 2) : opt_int(); });
return x ? opt_int(x / 2) : opt_int();
});
m.def("test_nullopt", [](opt_int x) { m.def("test_nullopt", [](opt_int x) {
return x.value_or(42); return x.value_or(42);
}, py::arg_v("x", std::nullopt, "None")); }, py::arg_v("x", std::nullopt, "None"));