Skip to content

Commit

Permalink
Use if constexpr
Browse files Browse the repository at this point in the history
  • Loading branch information
cyyever committed Sep 29, 2024
1 parent 7e418f4 commit f18b78e
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 56 deletions.
72 changes: 38 additions & 34 deletions include/pybind11/cast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -138,46 +141,47 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
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<T>::value) {
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 (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)
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 (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<object>(PyNumber_Index(src.ptr()));
if (!index) {
PyErr_Clear();
if (!convert)
return false;
} else {
src_or_index = index;
}
object index;
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
if (!index) {
PyErr_Clear();
if (!convert)
return false;
} else {
src_or_index = index;
}
}
#endif
if (std::is_unsigned<py_type>::value) {
py_value = as_unsigned<py_type>(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 PYBIND11_IF_CONSTEXPR (std::is_unsigned<py_type>::value) {
py_value = as_unsigned<py_type>(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
Expand Down Expand Up @@ -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<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size));
Expand All @@ -432,7 +436,7 @@ struct string_caster {
= reinterpret_cast<const CharT *>(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--;
}
Expand Down Expand Up @@ -559,7 +563,7 @@ struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
}

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);
if (!s) {
throw error_already_set();
Expand Down
8 changes: 8 additions & 0 deletions include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 6 additions & 5 deletions include/pybind11/eigen/tensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -272,25 +275,23 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
bool writeable = false;
switch (policy) {
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");
}

src = Helper::alloc(std::move(*src));

parent_object
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
writeable = true;
break;

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
// alternative here as we must free that memory
Helper::free(const_cast<Type *>(src));
pybind11_fail("Cannot take ownership of a const reference");
}

parent_object
= capsule(src, [](void *ptr) { Helper::free(reinterpret_cast<Type *>(ptr)); });
writeable = true;
Expand Down
19 changes: 10 additions & 9 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ class cpp_function : public function {
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. */
Expand All @@ -222,7 +222,7 @@ class cpp_function : public function {

// UB without std::launder, but without breaking ABI and/or
// 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) {
auto data = PYBIND11_STD_LAUNDER((capture *) &r->data);
(void) data;
Expand Down Expand Up @@ -331,7 +331,7 @@ class cpp_function : public function {
using FunctionType = Return (*)(Args...);
constexpr bool is_function_ptr
= 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->data[1]
= const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
Expand Down Expand Up @@ -1605,7 +1605,7 @@ class class_ : public detail::generic_type {

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;
Expand Down Expand Up @@ -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<bool is_arithmetic, bool is_convertible>
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);
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -2242,7 +2243,7 @@ class enum_ : public class_<Type> {
: 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_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_property_readonly("value", [](Type value) { return (Scalar) value; });
Expand Down
11 changes: 7 additions & 4 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 <typename Unsigned>
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;
}
Expand All @@ -1842,14 +1845,14 @@ class int_ : public object {
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
// NOLINTNEXTLINE(google-explicit-constructor)
int_(T value) {
if (sizeof(T) <= sizeof(long)) {
if (std::is_signed<T>::value) {
if PYBIND11_IF_CONSTEXPR (sizeof(T) <= sizeof(long)) {
if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
m_ptr = PyLong_FromLong((long) value);
} else {
m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
}
} else {
if (std::is_signed<T>::value) {
if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
m_ptr = PyLong_FromLongLong((long long) value);
} else {
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);
Expand Down
8 changes: 4 additions & 4 deletions include/pybind11/stl.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ struct set_caster {

template <typename T>
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);
}
pybind11::set s;
Expand Down Expand Up @@ -256,7 +256,7 @@ struct map_caster {
dict d;
return_value_policy policy_key = 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_value = return_value_policy_override<Value>::policy(policy_value);
}
Expand Down Expand Up @@ -324,7 +324,7 @@ struct list_caster {
public:
template <typename T>
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);
}
list l(src.size());
Expand Down Expand Up @@ -513,7 +513,7 @@ struct optional_caster {
if (!src) {
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);
}
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
Expand Down

0 comments on commit f18b78e

Please sign in to comment.