Skip to content
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
39 changes: 32 additions & 7 deletions Include/pymacro.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,40 @@
# endif
#endif

#if ((defined(__GNUC__) || defined(__clang__)) \
&& defined(_Py_TYPEOF) && !defined(__cplusplus))
// Implement Py_MIN(), Py_MAX() and Py_ABS() using _Py_TYPEOF() and
// statement expression to only evaluate each argument only once.
// It cannot be used in C++: ISO C++ forbids braced-groups within
// expressions. Statement expression is a GNU extension. Use __extension__
// to avoid compiler warning in pedantic mode.

/* Minimum value between x and y */
#define Py_MIN(x, y) (((x) > (y)) ? (y) : (x))

/* Maximum value between x and y */
#define Py_MAX(x, y) (((x) > (y)) ? (x) : (y))
/* Minimum value between x and y */
# define Py_MIN(x, y) \
__extension__ \
({ _Py_TYPEOF (x) _x = (x); \
_Py_TYPEOF (y) _y = (y); \
_x < _y ? _x : _y; })
/* Maximum value between x and y */
# define Py_MAX(x, y) \
__extension__ \
({ _Py_TYPEOF (x) _x = (x); \
_Py_TYPEOF (y) _y = (y); \
_x > _y ? _x : _y; })
/* Absolute value of the number x */
# define Py_ABS(x) \
__extension__ \
({ _Py_TYPEOF (x) _x = (x); \
_x < 0 ? -_x : _x; })
#else
/* Minimum value between x and y */
# define Py_MIN(x, y) (((x) > (y)) ? (y) : (x))
/* Maximum value between x and y */
# define Py_MAX(x, y) (((x) > (y)) ? (x) : (y))
/* Absolute value of the number x */
# define Py_ABS(x) ((x) < 0 ? -(x) : (x))
#endif

/* Absolute value of the number x */
#define Py_ABS(x) ((x) < 0 ? -(x) : (x))
/* Safer implementation that avoids an undefined behavior for the minimal
value of the signed integer type if its absolute value is larger than
the maximal value of the signed integer type (in the two's complement
Expand Down
7 changes: 6 additions & 1 deletion Lib/test/test_cext/extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,15 @@ _testcext_exec(PyObject *module)
if (!result) return -1;
Py_DECREF(result);

// test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
// Test Py_BUILD_ASSERT() and Py_BUILD_ASSERT_EXPR()
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);

// Test Py_MIN(), Py_MAX(), Py_ABS()
assert(Py_MIN(5, 11) == 5);
assert(Py_MAX(5, 11) == 11);
assert(Py_ABS(-5) == 5);

// Test Py_CLEAR(): use typeof()/__typeof__() if available, or memcpy()
obj = Py_None;
Py_CLEAR(obj);
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_cppext/extension.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,11 @@ _testcppext_exec(PyObject *module)
Py_BUILD_ASSERT(sizeof(int) == sizeof(unsigned int));
assert(Py_BUILD_ASSERT_EXPR(sizeof(int) == sizeof(unsigned int)) == 0);

// Test Py_MIN(), Py_MAX(), Py_ABS()
assert(Py_MIN(5, 11) == 5);
assert(Py_MAX(5, 11) == 11);
assert(Py_ABS(-5) == 5);

// Test Py_CLEAR(): use typeof()/__typeof__() if available, or memcpy()
PyObject *obj = Py_None;
Py_CLEAR(obj);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
If ``typeof()`` is available, implement :c:macro:`Py_MIN`, :c:macro:`Py_MAX`
and :c:macro:`Py_ABS` using ``typeof()`` and statement expression to only
evaluate each argument once. Patch by Victor Stinner.
3 changes: 2 additions & 1 deletion Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5883,7 +5883,8 @@ _ssl_MemoryBIO_read_impl(PySSLMemoryBIO *self, int len)
{
int avail, nbytes;

avail = (int)Py_MIN(BIO_ctrl_pending(self->bio), INT_MAX);
size_t pending = BIO_ctrl_pending(self->bio);
avail = (int)Py_MIN(pending, (size_t)INT_MAX);
if ((len < 0) || (len > avail))
len = avail;

Expand Down
12 changes: 11 additions & 1 deletion Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -2045,12 +2045,22 @@ test_macros(PyObject *self, PyObject *Py_UNUSED(args))
static_assert(1 == 1, "bug");
Py_BUILD_ASSERT(1 == 1);


// Py_MIN(), Py_MAX(), Py_ABS()
assert(Py_MIN(5, 11) == 5);
assert(Py_MAX(5, 11) == 11);
assert(Py_ABS(-5) == 5);

#if ((defined(__GNUC__) || defined(__clang__)) \
&& defined(_Py_TYPEOF) && !defined(__cplusplus))
// When _Py_TYPEOF() is available, arguments are only evaluated once
int x = 5, y = 11;
assert(Py_MIN(++x, ++y) == 6);
x = 5; y = 11;
assert(Py_MAX(++x, ++y) == 12);
x = -5;
assert(Py_ABS(--x) == 6);
#endif

// Py_STRINGIFY()
assert(strcmp(Py_STRINGIFY(123), "123") == 0);

Expand Down
2 changes: 1 addition & 1 deletion Modules/cjkcodecs/cjkcodecs.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ get_module_state(PyObject *mod)
do { \
Py_UCS4 _c1 = (c1); \
Py_UCS4 _c2 = (c2); \
if (_PyUnicodeWriter_Prepare(writer, 2, Py_MAX(_c1, c2)) < 0) \
if (_PyUnicodeWriter_Prepare(writer, 2, Py_MAX(_c1, _c2)) < 0) \
return MBERR_EXCEPTION; \
PyUnicode_WRITE(writer->kind, writer->data, writer->pos, _c1); \
PyUnicode_WRITE(writer->kind, writer->data, writer->pos + 1, _c2); \
Expand Down
4 changes: 2 additions & 2 deletions Objects/obmalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -3255,10 +3255,10 @@ _PyMem_DebugRawRealloc(void *ctx, void *p, size_t nbytes)
}
else {
size_t i = original_nbytes - ERASED_SIZE;
memcpy(data, save, Py_MIN(nbytes, ERASED_SIZE));
memcpy(data, save, Py_MIN(nbytes, (size_t)ERASED_SIZE));
if (nbytes > i) {
memcpy(data + i, &save[ERASED_SIZE],
Py_MIN(nbytes - i, ERASED_SIZE));
Py_MIN(nbytes - i, (size_t)ERASED_SIZE));
}
}
#endif
Expand Down
Loading