From efbd12c6a5f03b1387fc53457a0a0d358cfc0021 Mon Sep 17 00:00:00 2001 From: cyy Date: Sun, 29 Sep 2024 22:36:45 +0800 Subject: [PATCH] Use if constexpr --- include/pybind11/cast.h | 74 +++++++++++++++++--------------- include/pybind11/detail/common.h | 8 ++++ include/pybind11/eigen/tensor.h | 9 ++-- include/pybind11/pybind11.h | 19 ++++---- include/pybind11/pytypes.h | 11 +++-- include/pybind11/stl.h | 8 ++-- 6 files changed, 73 insertions(+), 56 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index e3c8b9f65..621557627 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -31,6 +31,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) +#if PYBIND11_HAS_IF_CONSTEXPR +PYBIND11_WARNING_DISABLE_MSVC(4702) +#endif PYBIND11_NAMESPACE_BEGIN(detail) @@ -138,46 +141,47 @@ public: return false; } -#if !defined(PYPY_VERSION) - auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; -#else - // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`, - // while CPython only considers the existence of `nb_index`/`__index__`. - auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); }; -#endif - - if (std::is_floating_point::value) { + if PYBIND11_IF_CONSTEXPR (std::is_floating_point::value) { if (convert || PyFloat_Check(src.ptr())) { py_value = (py_type) PyFloat_AsDouble(src.ptr()); } else { return false; } - } else if (PyFloat_Check(src.ptr()) - || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { - return false; } else { - handle src_or_index = src; - // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. -#if defined(PYPY_VERSION) - object index; - if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) - index = reinterpret_steal(PyNumber_Index(src.ptr())); - if (!index) { - PyErr_Clear(); - if (!convert) - return false; - } else { - src_or_index = index; - } - } +#if !defined(PYPY_VERSION) + auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; +#else + // In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`, + // while CPython only considers the existence of `nb_index`/`__index__`. + auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); }; #endif - if (std::is_unsigned::value) { - py_value = as_unsigned(src_or_index.ptr()); - } else { // signed integer: - py_value = sizeof(T) <= sizeof(long) - ? (py_type) PyLong_AsLong(src_or_index.ptr()) - : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); + if (PyFloat_Check(src.ptr()) + || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) { + return false; + } + + handle src_or_index = src; + // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. +#if defined(PYPY_VERSION) + object index; + if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr()) + index = reinterpret_steal(PyNumber_Index(src.ptr())); + if (!index) { + PyErr_Clear(); + if (!convert) + return false; + } else { + src_or_index = index; } + } +#endif + if PYBIND11_IF_CONSTEXPR (std::is_unsigned::value) { + py_value = as_unsigned(src_or_index.ptr()); + } else { // signed integer: + py_value = sizeof(T) <= sizeof(long) + ? (py_type) PyLong_AsLong(src_or_index.ptr()) + : (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr()); + } } // Python API reported an error @@ -405,7 +409,7 @@ struct string_caster { // For UTF-8 we avoid the need for a temporary `bytes` object by using // `PyUnicode_AsUTF8AndSize`. - if (UTF_N == 8) { + if PYBIND11_IF_CONSTEXPR (UTF_N == 8) { Py_ssize_t size = -1; const auto *buffer = reinterpret_cast(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); @@ -432,7 +436,7 @@ struct string_caster { = reinterpret_cast(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); // Skip BOM for UTF-16/32 - if (UTF_N > 8) { + if PYBIND11_IF_CONSTEXPR (UTF_N > 8) { buffer++; length--; } @@ -559,7 +563,7 @@ public: } static handle cast(CharT src, return_value_policy policy, handle parent) { - if (std::is_same::value) { + if PYBIND11_IF_CONSTEXPR (std::is_same::value) { handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); if (!s) { throw error_already_set(); diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 2a39e88f3..85c1575c8 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -118,6 +118,14 @@ # endif #endif +#if defined(__cpp_if_constexpr) +# define PYBIND11_HAS_IF_CONSTEXPR 1 +# define PYBIND11_IF_CONSTEXPR constexpr +#else +# define PYBIND11_HAS_IF_CONSTEXPR 0 +# define PYBIND11_IF_CONSTEXPR +#endif + #if defined(PYBIND11_CPP20) # define PYBIND11_CONSTINIT constinit # define PYBIND11_DTOR_CONSTEXPR constexpr diff --git a/include/pybind11/eigen/tensor.h b/include/pybind11/eigen/tensor.h index 0a9d7c252..f692e21f0 100644 --- a/include/pybind11/eigen/tensor.h +++ b/include/pybind11/eigen/tensor.h @@ -33,6 +33,9 @@ static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0), PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) +#if PYBIND11_HAS_IF_CONSTEXPR +PYBIND11_WARNING_DISABLE_MSVC(4702) +#endif PYBIND11_NAMESPACE_BEGIN(detail) @@ -272,10 +275,9 @@ struct type_caster::ValidType> { bool writeable = false; switch (policy) { case return_value_policy::move: - if (std::is_const::value) { + if PYBIND11_IF_CONSTEXPR (std::is_const::value) { pybind11_fail("Cannot move from a constant reference"); } - src = Helper::alloc(std::move(*src)); parent_object @@ -284,13 +286,12 @@ struct type_caster::ValidType> { break; case return_value_policy::take_ownership: - if (std::is_const::value) { + if PYBIND11_IF_CONSTEXPR (std::is_const::value) { // This cast is ugly, and might be UB in some cases, but we don't have an // alternative here as we must free that memory Helper::free(const_cast(src)); pybind11_fail("Cannot take ownership of a const reference"); } - parent_object = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast(ptr)); }); writeable = true; diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index bcdf641f4..f927ac9b1 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -204,7 +204,7 @@ protected: auto *rec = unique_rec.get(); /* Store the capture object directly in the function record if there is enough space */ - if (sizeof(capture) <= sizeof(rec->data)) { + if PYBIND11_IF_CONSTEXPR (sizeof(capture) <= sizeof(rec->data)) { /* Without these pragmas, GCC warns that there might not be enough space to use the placement new operator. However, the 'if' statement above ensures that this is the case. */ @@ -222,7 +222,7 @@ protected: // UB without std::launder, but without breaking ABI and/or // a significant refactoring it's "impossible" to solve. - if (!std::is_trivially_destructible::value) { + if PYBIND11_IF_CONSTEXPR (!std::is_trivially_destructible::value) { rec->free_data = [](function_record *r) { auto data = PYBIND11_STD_LAUNDER((capture *) &r->data); (void) data; @@ -331,7 +331,7 @@ protected: using FunctionType = Return (*)(Args...); constexpr bool is_function_ptr = std::is_convertible::value && sizeof(capture) == sizeof(void *); - if (is_function_ptr) { + if PYBIND11_IF_CONSTEXPR (is_function_ptr) { rec->is_stateless = true; rec->data[1] = const_cast(reinterpret_cast(&typeid(FunctionType))); @@ -1605,7 +1605,7 @@ public: generic_type::initialize(record); - if (has_alias) { + if PYBIND11_IF_CONSTEXPR (has_alias) { with_internals([&](internals &internals) { auto &instances = record.module_local ? get_local_internals().registered_types_cpp : internals.registered_types_cpp; @@ -2011,7 +2011,8 @@ inline str enum_name(handle arg) { struct enum_base { enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) {} - PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) { + template + PYBIND11_NOINLINE void init() { m_base.attr("__entries") = dict(); auto property = handle((PyObject *) &PyProperty_Type); auto static_property = handle((PyObject *) get_internals().static_property_type); @@ -2111,11 +2112,11 @@ struct enum_base { is_method(m_base), \ arg("other")) - if (is_convertible) { + if PYBIND11_IF_CONSTEXPR (is_convertible) { PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b)); PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b)); - if (is_arithmetic) { + if PYBIND11_IF_CONSTEXPR (is_arithmetic) { PYBIND11_ENUM_OP_CONV("__lt__", a < b); PYBIND11_ENUM_OP_CONV("__gt__", a > b); PYBIND11_ENUM_OP_CONV("__le__", a <= b); @@ -2135,7 +2136,7 @@ struct enum_base { PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false); PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true); - if (is_arithmetic) { + if PYBIND11_IF_CONSTEXPR (is_arithmetic) { #define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!"); PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW); PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW); @@ -2242,7 +2243,7 @@ public: : class_(scope, name, extra...), m_base(*this, scope) { constexpr bool is_arithmetic = detail::any_of...>::value; constexpr bool is_convertible = std::is_convertible::value; - m_base.init(is_arithmetic, is_convertible); + m_base.init(); def(init([](Scalar i) { return static_cast(i); }), arg("value")); def_property_readonly("value", [](Type value) { return (Scalar) value; }); diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 1e76d7bc1..c8c161be4 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -34,6 +34,9 @@ PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_WARNING_DISABLE_MSVC(4127) +#if PYBIND11_HAS_IF_CONSTEXPR +PYBIND11_WARNING_DISABLE_MSVC(4702) +#endif /* A few forward declarations */ class handle; @@ -1825,7 +1828,7 @@ PYBIND11_NAMESPACE_BEGIN(detail) // unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes). template Unsigned as_unsigned(PyObject *o) { - if (sizeof(Unsigned) <= sizeof(unsigned long)) { + if PYBIND11_IF_CONSTEXPR (sizeof(Unsigned) <= sizeof(unsigned long)) { unsigned long v = PyLong_AsUnsignedLong(o); return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; } @@ -1842,14 +1845,14 @@ public: template ::value, int> = 0> // NOLINTNEXTLINE(google-explicit-constructor) int_(T value) { - if (sizeof(T) <= sizeof(long)) { - if (std::is_signed::value) { + if PYBIND11_IF_CONSTEXPR (sizeof(T) <= sizeof(long)) { + if PYBIND11_IF_CONSTEXPR (std::is_signed::value) { m_ptr = PyLong_FromLong((long) value); } else { m_ptr = PyLong_FromUnsignedLong((unsigned long) value); } } else { - if (std::is_signed::value) { + if PYBIND11_IF_CONSTEXPR (std::is_signed::value) { m_ptr = PyLong_FromLongLong((long long) value); } else { m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 6a148e740..42fec7e2b 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -189,7 +189,7 @@ public: template static handle cast(T &&src, return_value_policy policy, handle parent) { - if (!std::is_lvalue_reference::value) { + if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference::value) { policy = return_value_policy_override::policy(policy); } pybind11::set s; @@ -256,7 +256,7 @@ public: dict d; return_value_policy policy_key = policy; return_value_policy policy_value = policy; - if (!std::is_lvalue_reference::value) { + if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference::value) { policy_key = return_value_policy_override::policy(policy_key); policy_value = return_value_policy_override::policy(policy_value); } @@ -324,7 +324,7 @@ private: public: template static handle cast(T &&src, return_value_policy policy, handle parent) { - if (!std::is_lvalue_reference::value) { + if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference::value) { policy = return_value_policy_override::policy(policy); } list l(src.size()); @@ -513,7 +513,7 @@ struct optional_caster { if (!src) { return none().release(); } - if (!std::is_lvalue_reference::value) { + if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference::value) { policy = return_value_policy_override::policy(policy); } // NOLINTNEXTLINE(bugprone-unchecked-optional-access)