Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use if constexpr #5389

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 20 additions & 16 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,24 +141,25 @@ 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 {
#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)
Expand All @@ -171,7 +175,7 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
}
}
#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());
} else { // signed integer:
py_value = sizeof(T) <= sizeof(long)
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
9 changes: 5 additions & 4 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,10 +275,9 @@ 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
Expand All @@ -284,13 +286,12 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
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