Use if constexpr

This commit is contained in:
cyy 2024-09-29 22:36:45 +08:00
parent 7e418f4924
commit efbd12c6a5
6 changed files with 73 additions and 56 deletions

View File

@ -31,6 +31,9 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_WARNING_DISABLE_MSVC(4127)
#if PYBIND11_HAS_IF_CONSTEXPR
PYBIND11_WARNING_DISABLE_MSVC(4702)
#endif
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
@ -138,6 +141,13 @@ public:
return false; return false;
} }
if PYBIND11_IF_CONSTEXPR (std::is_floating_point<T>::value) {
if (convert || PyFloat_Check(src.ptr())) {
py_value = (py_type) PyFloat_AsDouble(src.ptr());
} else {
return false;
}
} else {
#if !defined(PYPY_VERSION) #if !defined(PYPY_VERSION)
auto index_check = [](PyObject *o) { return PyIndex_Check(o); }; auto index_check = [](PyObject *o) { return PyIndex_Check(o); };
#else #else
@ -145,17 +155,11 @@ public:
// while CPython only considers the existence of `nb_index`/`__index__`. // while CPython only considers the existence of `nb_index`/`__index__`.
auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); }; auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); };
#endif #endif
if (PyFloat_Check(src.ptr())
if (std::is_floating_point<T>::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()))) { || (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {
return false; return false;
} else { }
handle src_or_index = src; handle src_or_index = src;
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls. // PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
#if defined(PYPY_VERSION) #if defined(PYPY_VERSION)
@ -171,7 +175,7 @@ public:
} }
} }
#endif #endif
if (std::is_unsigned<py_type>::value) { if PYBIND11_IF_CONSTEXPR (std::is_unsigned<py_type>::value) {
py_value = as_unsigned<py_type>(src_or_index.ptr()); py_value = as_unsigned<py_type>(src_or_index.ptr());
} else { // signed integer: } else { // signed integer:
py_value = sizeof(T) <= sizeof(long) py_value = sizeof(T) <= sizeof(long)
@ -405,7 +409,7 @@ struct string_caster {
// For UTF-8 we avoid the need for a temporary `bytes` object by using // For UTF-8 we avoid the need for a temporary `bytes` object by using
// `PyUnicode_AsUTF8AndSize`. // `PyUnicode_AsUTF8AndSize`.
if (UTF_N == 8) { if PYBIND11_IF_CONSTEXPR (UTF_N == 8) {
Py_ssize_t size = -1; Py_ssize_t size = -1;
const auto *buffer const auto *buffer
= reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size)); = reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size));
@ -432,7 +436,7 @@ struct string_caster {
= reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr())); = reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT); size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
// Skip BOM for UTF-16/32 // Skip BOM for UTF-16/32
if (UTF_N > 8) { if PYBIND11_IF_CONSTEXPR (UTF_N > 8) {
buffer++; buffer++;
length--; length--;
} }
@ -559,7 +563,7 @@ public:
} }
static handle cast(CharT src, return_value_policy policy, handle parent) { static handle cast(CharT src, return_value_policy policy, handle parent) {
if (std::is_same<char, CharT>::value) { if PYBIND11_IF_CONSTEXPR (std::is_same<char, CharT>::value) {
handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr); handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);
if (!s) { if (!s) {
throw error_already_set(); throw error_already_set();

View File

@ -118,6 +118,14 @@
# endif # endif
#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) #if defined(PYBIND11_CPP20)
# define PYBIND11_CONSTINIT constinit # define PYBIND11_CONSTINIT constinit
# define PYBIND11_DTOR_CONSTEXPR constexpr # define PYBIND11_DTOR_CONSTEXPR constexpr

View File

@ -33,6 +33,9 @@ static_assert(EIGEN_VERSION_AT_LEAST(3, 3, 0),
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_WARNING_DISABLE_MSVC(4127)
#if PYBIND11_HAS_IF_CONSTEXPR
PYBIND11_WARNING_DISABLE_MSVC(4702)
#endif
PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(detail)
@ -272,10 +275,9 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
bool writeable = false; bool writeable = false;
switch (policy) { switch (policy) {
case return_value_policy::move: case return_value_policy::move:
if (std::is_const<C>::value) { if PYBIND11_IF_CONSTEXPR (std::is_const<C>::value) {
pybind11_fail("Cannot move from a constant reference"); pybind11_fail("Cannot move from a constant reference");
} }
src = Helper::alloc(std::move(*src)); src = Helper::alloc(std::move(*src));
parent_object parent_object
@ -284,13 +286,12 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
break; break;
case return_value_policy::take_ownership: case return_value_policy::take_ownership:
if (std::is_const<C>::value) { if PYBIND11_IF_CONSTEXPR (std::is_const<C>::value) {
// This cast is ugly, and might be UB in some cases, but we don't have an // 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 // alternative here as we must free that memory
Helper::free(const_cast<Type *>(src)); Helper::free(const_cast<Type *>(src));
pybind11_fail("Cannot take ownership of a const reference"); pybind11_fail("Cannot take ownership of a const reference");
} }
parent_object parent_object
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); }); = capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
writeable = true; writeable = true;

View File

@ -204,7 +204,7 @@ protected:
auto *rec = unique_rec.get(); auto *rec = unique_rec.get();
/* Store the capture object directly in the function record if there is enough space */ /* 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 /* Without these pragmas, GCC warns that there might not be
enough space to use the placement new operator. However, the enough space to use the placement new operator. However, the
'if' statement above ensures that this is the case. */ 'if' statement above ensures that this is the case. */
@ -222,7 +222,7 @@ protected:
// UB without std::launder, but without breaking ABI and/or // UB without std::launder, but without breaking ABI and/or
// a significant refactoring it's "impossible" to solve. // a significant refactoring it's "impossible" to solve.
if (!std::is_trivially_destructible<capture>::value) { if PYBIND11_IF_CONSTEXPR (!std::is_trivially_destructible<capture>::value) {
rec->free_data = [](function_record *r) { rec->free_data = [](function_record *r) {
auto data = PYBIND11_STD_LAUNDER((capture *) &r->data); auto data = PYBIND11_STD_LAUNDER((capture *) &r->data);
(void) data; (void) data;
@ -331,7 +331,7 @@ protected:
using FunctionType = Return (*)(Args...); using FunctionType = Return (*)(Args...);
constexpr bool is_function_ptr constexpr bool is_function_ptr
= std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *); = std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);
if (is_function_ptr) { if PYBIND11_IF_CONSTEXPR (is_function_ptr) {
rec->is_stateless = true; rec->is_stateless = true;
rec->data[1] rec->data[1]
= const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType))); = const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
@ -1605,7 +1605,7 @@ public:
generic_type::initialize(record); generic_type::initialize(record);
if (has_alias) { if PYBIND11_IF_CONSTEXPR (has_alias) {
with_internals([&](internals &internals) { with_internals([&](internals &internals) {
auto &instances = record.module_local ? get_local_internals().registered_types_cpp auto &instances = record.module_local ? get_local_internals().registered_types_cpp
: internals.registered_types_cpp; : internals.registered_types_cpp;
@ -2011,7 +2011,8 @@ inline str enum_name(handle arg) {
struct enum_base { struct enum_base {
enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) {} 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<bool is_arithmetic, bool is_convertible>
PYBIND11_NOINLINE void init() {
m_base.attr("__entries") = dict(); m_base.attr("__entries") = dict();
auto property = handle((PyObject *) &PyProperty_Type); auto property = handle((PyObject *) &PyProperty_Type);
auto static_property = handle((PyObject *) get_internals().static_property_type); auto static_property = handle((PyObject *) get_internals().static_property_type);
@ -2111,11 +2112,11 @@ struct enum_base {
is_method(m_base), \ is_method(m_base), \
arg("other")) 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("__eq__", !b.is_none() && a.equal(b));
PYBIND11_ENUM_OP_CONV_LHS("__ne__", 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("__lt__", a < b);
PYBIND11_ENUM_OP_CONV("__gt__", a > b); PYBIND11_ENUM_OP_CONV("__gt__", a > b);
PYBIND11_ENUM_OP_CONV("__le__", 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("__eq__", int_(a).equal(int_(b)), return false);
PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true); 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!"); #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("__lt__", int_(a) < int_(b), PYBIND11_THROW);
PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW); PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW);
@ -2242,7 +2243,7 @@ public:
: class_<Type>(scope, name, extra...), m_base(*this, scope) { : class_<Type>(scope, name, extra...), m_base(*this, scope) {
constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value; constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value; constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value;
m_base.init(is_arithmetic, is_convertible); m_base.init<is_arithmetic, is_convertible>();
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value")); def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
def_property_readonly("value", [](Type value) { return (Scalar) value; }); def_property_readonly("value", [](Type value) { return (Scalar) value; });

View File

@ -34,6 +34,9 @@
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_WARNING_DISABLE_MSVC(4127) PYBIND11_WARNING_DISABLE_MSVC(4127)
#if PYBIND11_HAS_IF_CONSTEXPR
PYBIND11_WARNING_DISABLE_MSVC(4702)
#endif
/* A few forward declarations */ /* A few forward declarations */
class handle; 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). // unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
template <typename Unsigned> template <typename Unsigned>
Unsigned as_unsigned(PyObject *o) { 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); unsigned long v = PyLong_AsUnsignedLong(o);
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v; return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
} }
@ -1842,14 +1845,14 @@ public:
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0> template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor) // NOLINTNEXTLINE(google-explicit-constructor)
int_(T value) { int_(T value) {
if (sizeof(T) <= sizeof(long)) { if PYBIND11_IF_CONSTEXPR (sizeof(T) <= sizeof(long)) {
if (std::is_signed<T>::value) { if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
m_ptr = PyLong_FromLong((long) value); m_ptr = PyLong_FromLong((long) value);
} else { } else {
m_ptr = PyLong_FromUnsignedLong((unsigned long) value); m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
} }
} else { } else {
if (std::is_signed<T>::value) { if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
m_ptr = PyLong_FromLongLong((long long) value); m_ptr = PyLong_FromLongLong((long long) value);
} else { } else {
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value); m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);

View File

@ -189,7 +189,7 @@ public:
template <typename T> template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) { static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!std::is_lvalue_reference<T>::value) { if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Key>::policy(policy); policy = return_value_policy_override<Key>::policy(policy);
} }
pybind11::set s; pybind11::set s;
@ -256,7 +256,7 @@ public:
dict d; dict d;
return_value_policy policy_key = policy; return_value_policy policy_key = policy;
return_value_policy policy_value = policy; return_value_policy policy_value = policy;
if (!std::is_lvalue_reference<T>::value) { if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
policy_key = return_value_policy_override<Key>::policy(policy_key); policy_key = return_value_policy_override<Key>::policy(policy_key);
policy_value = return_value_policy_override<Value>::policy(policy_value); policy_value = return_value_policy_override<Value>::policy(policy_value);
} }
@ -324,7 +324,7 @@ private:
public: public:
template <typename T> template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent) { static handle cast(T &&src, return_value_policy policy, handle parent) {
if (!std::is_lvalue_reference<T>::value) { if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Value>::policy(policy); policy = return_value_policy_override<Value>::policy(policy);
} }
list l(src.size()); list l(src.size());
@ -513,7 +513,7 @@ struct optional_caster {
if (!src) { if (!src) {
return none().release(); return none().release();
} }
if (!std::is_lvalue_reference<T>::value) { if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
policy = return_value_policy_override<Value>::policy(policy); policy = return_value_policy_override<Value>::policy(policy);
} }
// NOLINTNEXTLINE(bugprone-unchecked-optional-access) // NOLINTNEXTLINE(bugprone-unchecked-optional-access)