Skip to content

Commit 987f07e

Browse files
committed
Use if constexpr
1 parent 7e418f4 commit 987f07e

File tree

6 files changed

+72
-53
lines changed

6 files changed

+72
-53
lines changed

include/pybind11/cast.h

+38-34
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@
3131
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
3232

3333
PYBIND11_WARNING_DISABLE_MSVC(4127)
34+
#if PYBIND11_HAS_IF_CONSTEXPR
35+
PYBIND11_WARNING_DISABLE_MSVC(4702)
36+
#endif
3437

3538
PYBIND11_NAMESPACE_BEGIN(detail)
3639

@@ -138,46 +141,47 @@ struct type_caster<T, enable_if_t<std::is_arithmetic<T>::value && !is_std_char_t
138141
return false;
139142
}
140143

141-
#if !defined(PYPY_VERSION)
142-
auto index_check = [](PyObject *o) { return PyIndex_Check(o); };
143-
#else
144-
// In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`,
145-
// while CPython only considers the existence of `nb_index`/`__index__`.
146-
auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); };
147-
#endif
148-
149-
if (std::is_floating_point<T>::value) {
144+
if PYBIND11_IF_CONSTEXPR (std::is_floating_point<T>::value) {
150145
if (convert || PyFloat_Check(src.ptr())) {
151146
py_value = (py_type) PyFloat_AsDouble(src.ptr());
152147
} else {
153148
return false;
154149
}
155-
} else if (PyFloat_Check(src.ptr())
156-
|| (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {
157-
return false;
158150
} else {
159-
handle src_or_index = src;
160-
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
151+
#if !defined(PYPY_VERSION)
152+
auto index_check = [](PyObject *o) { return PyIndex_Check(o); };
153+
#else
154+
// In PyPy 7.3.3, `PyIndex_Check` is implemented by calling `__index__`,
155+
// while CPython only considers the existence of `nb_index`/`__index__`.
156+
auto index_check = [](PyObject *o) { return hasattr(o, "__index__"); };
157+
#endif
158+
if (PyFloat_Check(src.ptr())
159+
|| (!convert && !PYBIND11_LONG_CHECK(src.ptr()) && !index_check(src.ptr()))) {
160+
return false;
161+
}
162+
163+
handle src_or_index = src;
164+
// PyPy: 7.3.7's 3.8 does not implement PyLong_*'s __index__ calls.
161165
#if defined(PYPY_VERSION)
162-
object index;
163-
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
164-
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
165-
if (!index) {
166-
PyErr_Clear();
167-
if (!convert)
168-
return false;
169-
} else {
170-
src_or_index = index;
171-
}
166+
object index;
167+
if (!PYBIND11_LONG_CHECK(src.ptr())) { // So: index_check(src.ptr())
168+
index = reinterpret_steal<object>(PyNumber_Index(src.ptr()));
169+
if (!index) {
170+
PyErr_Clear();
171+
if (!convert)
172+
return false;
173+
} else {
174+
src_or_index = index;
172175
}
176+
}
173177
#endif
174-
if (std::is_unsigned<py_type>::value) {
175-
py_value = as_unsigned<py_type>(src_or_index.ptr());
176-
} else { // signed integer:
177-
py_value = sizeof(T) <= sizeof(long)
178-
? (py_type) PyLong_AsLong(src_or_index.ptr())
179-
: (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr());
180-
}
178+
if PYBIND11_IF_CONSTEXPR (std::is_unsigned<py_type>::value) {
179+
py_value = as_unsigned<py_type>(src_or_index.ptr());
180+
} else { // signed integer:
181+
py_value = sizeof(T) <= sizeof(long)
182+
? (py_type) PyLong_AsLong(src_or_index.ptr())
183+
: (py_type) PYBIND11_LONG_AS_LONGLONG(src_or_index.ptr());
184+
}
181185
}
182186

183187
// Python API reported an error
@@ -405,7 +409,7 @@ struct string_caster {
405409

406410
// For UTF-8 we avoid the need for a temporary `bytes` object by using
407411
// `PyUnicode_AsUTF8AndSize`.
408-
if (UTF_N == 8) {
412+
if PYBIND11_IF_CONSTEXPR (UTF_N == 8) {
409413
Py_ssize_t size = -1;
410414
const auto *buffer
411415
= reinterpret_cast<const CharT *>(PyUnicode_AsUTF8AndSize(load_src.ptr(), &size));
@@ -432,7 +436,7 @@ struct string_caster {
432436
= reinterpret_cast<const CharT *>(PYBIND11_BYTES_AS_STRING(utfNbytes.ptr()));
433437
size_t length = (size_t) PYBIND11_BYTES_SIZE(utfNbytes.ptr()) / sizeof(CharT);
434438
// Skip BOM for UTF-16/32
435-
if (UTF_N > 8) {
439+
if PYBIND11_IF_CONSTEXPR (UTF_N > 8) {
436440
buffer++;
437441
length--;
438442
}
@@ -559,7 +563,7 @@ struct type_caster<CharT, enable_if_t<is_std_char_type<CharT>::value>> {
559563
}
560564

561565
static handle cast(CharT src, return_value_policy policy, handle parent) {
562-
if (std::is_same<char, CharT>::value) {
566+
if PYBIND11_IF_CONSTEXPR (std::is_same<char, CharT>::value) {
563567
handle s = PyUnicode_DecodeLatin1((const char *) &src, 1, nullptr);
564568
if (!s) {
565569
throw error_already_set();

include/pybind11/detail/common.h

+8
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@
118118
# endif
119119
#endif
120120

121+
#if defined(__cpp_if_constexpr)
122+
# define PYBIND11_HAS_IF_CONSTEXPR 1
123+
# define PYBIND11_IF_CONSTEXPR constexpr
124+
#else
125+
# define PYBIND11_HAS_IF_CONSTEXPR 0
126+
# define PYBIND11_IF_CONSTEXPR
127+
#endif
128+
121129
#if defined(PYBIND11_CPP20)
122130
# define PYBIND11_CONSTINIT constinit
123131
# define PYBIND11_DTOR_CONSTEXPR constexpr

include/pybind11/eigen/tensor.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ static_assert(__GNUC__ > 5, "Eigen Tensor support in pybind11 requires GCC > 5.0
1919
PYBIND11_WARNING_PUSH
2020
PYBIND11_WARNING_DISABLE_MSVC(4554)
2121
PYBIND11_WARNING_DISABLE_MSVC(4127)
22+
#if PYBIND11_HAS_IF_CONSTEXPR
23+
PYBIND11_WARNING_DISABLE_MSVC(4702)
24+
#endif
2225
#if defined(__MINGW32__)
2326
PYBIND11_WARNING_DISABLE_GCC("-Wmaybe-uninitialized")
2427
#endif
@@ -272,7 +275,7 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
272275
bool writeable = false;
273276
switch (policy) {
274277
case return_value_policy::move:
275-
if (std::is_const<C>::value) {
278+
if PYBIND11_IF_CONSTEXPR (std::is_const<C>::value) {
276279
pybind11_fail("Cannot move from a constant reference");
277280
}
278281

@@ -284,7 +287,7 @@ struct type_caster<Type, typename eigen_tensor_helper<Type>::ValidType> {
284287
break;
285288

286289
case return_value_policy::take_ownership:
287-
if (std::is_const<C>::value) {
290+
if PYBIND11_IF_CONSTEXPR (std::is_const<C>::value) {
288291
// This cast is ugly, and might be UB in some cases, but we don't have an
289292
// alternative here as we must free that memory
290293
Helper::free(const_cast<Type *>(src));

include/pybind11/pybind11.h

+10-9
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ class cpp_function : public function {
204204
auto *rec = unique_rec.get();
205205

206206
/* Store the capture object directly in the function record if there is enough space */
207-
if (sizeof(capture) <= sizeof(rec->data)) {
207+
if PYBIND11_IF_CONSTEXPR (sizeof(capture) <= sizeof(rec->data)) {
208208
/* Without these pragmas, GCC warns that there might not be
209209
enough space to use the placement new operator. However, the
210210
'if' statement above ensures that this is the case. */
@@ -222,7 +222,7 @@ class cpp_function : public function {
222222

223223
// UB without std::launder, but without breaking ABI and/or
224224
// a significant refactoring it's "impossible" to solve.
225-
if (!std::is_trivially_destructible<capture>::value) {
225+
if PYBIND11_IF_CONSTEXPR (!std::is_trivially_destructible<capture>::value) {
226226
rec->free_data = [](function_record *r) {
227227
auto data = PYBIND11_STD_LAUNDER((capture *) &r->data);
228228
(void) data;
@@ -331,7 +331,7 @@ class cpp_function : public function {
331331
using FunctionType = Return (*)(Args...);
332332
constexpr bool is_function_ptr
333333
= std::is_convertible<Func, FunctionType>::value && sizeof(capture) == sizeof(void *);
334-
if (is_function_ptr) {
334+
if PYBIND11_IF_CONSTEXPR (is_function_ptr) {
335335
rec->is_stateless = true;
336336
rec->data[1]
337337
= const_cast<void *>(reinterpret_cast<const void *>(&typeid(FunctionType)));
@@ -1605,7 +1605,7 @@ class class_ : public detail::generic_type {
16051605

16061606
generic_type::initialize(record);
16071607

1608-
if (has_alias) {
1608+
if PYBIND11_IF_CONSTEXPR (has_alias) {
16091609
with_internals([&](internals &internals) {
16101610
auto &instances = record.module_local ? get_local_internals().registered_types_cpp
16111611
: internals.registered_types_cpp;
@@ -2011,7 +2011,8 @@ inline str enum_name(handle arg) {
20112011
struct enum_base {
20122012
enum_base(const handle &base, const handle &parent) : m_base(base), m_parent(parent) {}
20132013

2014-
PYBIND11_NOINLINE void init(bool is_arithmetic, bool is_convertible) {
2014+
template<bool is_arithmetic, bool is_convertible>
2015+
PYBIND11_NOINLINE void init() {
20152016
m_base.attr("__entries") = dict();
20162017
auto property = handle((PyObject *) &PyProperty_Type);
20172018
auto static_property = handle((PyObject *) get_internals().static_property_type);
@@ -2111,11 +2112,11 @@ struct enum_base {
21112112
is_method(m_base), \
21122113
arg("other"))
21132114

2114-
if (is_convertible) {
2115+
if PYBIND11_IF_CONSTEXPR (is_convertible) {
21152116
PYBIND11_ENUM_OP_CONV_LHS("__eq__", !b.is_none() && a.equal(b));
21162117
PYBIND11_ENUM_OP_CONV_LHS("__ne__", b.is_none() || !a.equal(b));
21172118

2118-
if (is_arithmetic) {
2119+
if PYBIND11_IF_CONSTEXPR (is_arithmetic) {
21192120
PYBIND11_ENUM_OP_CONV("__lt__", a < b);
21202121
PYBIND11_ENUM_OP_CONV("__gt__", a > b);
21212122
PYBIND11_ENUM_OP_CONV("__le__", a <= b);
@@ -2135,7 +2136,7 @@ struct enum_base {
21352136
PYBIND11_ENUM_OP_STRICT("__eq__", int_(a).equal(int_(b)), return false);
21362137
PYBIND11_ENUM_OP_STRICT("__ne__", !int_(a).equal(int_(b)), return true);
21372138

2138-
if (is_arithmetic) {
2139+
if PYBIND11_IF_CONSTEXPR (is_arithmetic) {
21392140
#define PYBIND11_THROW throw type_error("Expected an enumeration of matching type!");
21402141
PYBIND11_ENUM_OP_STRICT("__lt__", int_(a) < int_(b), PYBIND11_THROW);
21412142
PYBIND11_ENUM_OP_STRICT("__gt__", int_(a) > int_(b), PYBIND11_THROW);
@@ -2242,7 +2243,7 @@ class enum_ : public class_<Type> {
22422243
: class_<Type>(scope, name, extra...), m_base(*this, scope) {
22432244
constexpr bool is_arithmetic = detail::any_of<std::is_same<arithmetic, Extra>...>::value;
22442245
constexpr bool is_convertible = std::is_convertible<Type, Underlying>::value;
2245-
m_base.init(is_arithmetic, is_convertible);
2246+
m_base.init<is_arithmetic, is_convertible>();
22462247

22472248
def(init([](Scalar i) { return static_cast<Type>(i); }), arg("value"));
22482249
def_property_readonly("value", [](Type value) { return (Scalar) value; });

include/pybind11/pytypes.h

+7-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@
3434
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
3535

3636
PYBIND11_WARNING_DISABLE_MSVC(4127)
37+
#if PYBIND11_HAS_IF_CONSTEXPR
38+
PYBIND11_WARNING_DISABLE_MSVC(4702)
39+
#endif
3740

3841
/* A few forward declarations */
3942
class handle;
@@ -1825,7 +1828,7 @@ PYBIND11_NAMESPACE_BEGIN(detail)
18251828
// unsigned type: (A)-1 != (B)-1 when A and B are unsigned types of different sizes).
18261829
template <typename Unsigned>
18271830
Unsigned as_unsigned(PyObject *o) {
1828-
if (sizeof(Unsigned) <= sizeof(unsigned long)) {
1831+
if PYBIND11_IF_CONSTEXPR (sizeof(Unsigned) <= sizeof(unsigned long)) {
18291832
unsigned long v = PyLong_AsUnsignedLong(o);
18301833
return v == (unsigned long) -1 && PyErr_Occurred() ? (Unsigned) -1 : (Unsigned) v;
18311834
}
@@ -1842,14 +1845,14 @@ class int_ : public object {
18421845
template <typename T, detail::enable_if_t<std::is_integral<T>::value, int> = 0>
18431846
// NOLINTNEXTLINE(google-explicit-constructor)
18441847
int_(T value) {
1845-
if (sizeof(T) <= sizeof(long)) {
1846-
if (std::is_signed<T>::value) {
1848+
if PYBIND11_IF_CONSTEXPR (sizeof(T) <= sizeof(long)) {
1849+
if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
18471850
m_ptr = PyLong_FromLong((long) value);
18481851
} else {
18491852
m_ptr = PyLong_FromUnsignedLong((unsigned long) value);
18501853
}
18511854
} else {
1852-
if (std::is_signed<T>::value) {
1855+
if PYBIND11_IF_CONSTEXPR (std::is_signed<T>::value) {
18531856
m_ptr = PyLong_FromLongLong((long long) value);
18541857
} else {
18551858
m_ptr = PyLong_FromUnsignedLongLong((unsigned long long) value);

include/pybind11/stl.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ struct set_caster {
189189

190190
template <typename T>
191191
static handle cast(T &&src, return_value_policy policy, handle parent) {
192-
if (!std::is_lvalue_reference<T>::value) {
192+
if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
193193
policy = return_value_policy_override<Key>::policy(policy);
194194
}
195195
pybind11::set s;
@@ -256,7 +256,7 @@ struct map_caster {
256256
dict d;
257257
return_value_policy policy_key = policy;
258258
return_value_policy policy_value = policy;
259-
if (!std::is_lvalue_reference<T>::value) {
259+
if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
260260
policy_key = return_value_policy_override<Key>::policy(policy_key);
261261
policy_value = return_value_policy_override<Value>::policy(policy_value);
262262
}
@@ -324,7 +324,7 @@ struct list_caster {
324324
public:
325325
template <typename T>
326326
static handle cast(T &&src, return_value_policy policy, handle parent) {
327-
if (!std::is_lvalue_reference<T>::value) {
327+
if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
328328
policy = return_value_policy_override<Value>::policy(policy);
329329
}
330330
list l(src.size());
@@ -513,7 +513,7 @@ struct optional_caster {
513513
if (!src) {
514514
return none().release();
515515
}
516-
if (!std::is_lvalue_reference<T>::value) {
516+
if PYBIND11_IF_CONSTEXPR (!std::is_lvalue_reference<T>::value) {
517517
policy = return_value_policy_override<Value>::policy(policy);
518518
}
519519
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)

0 commit comments

Comments
 (0)