mirror of https://github.com/python/cpython
gh-126061: Add PyLong_IsPositive/Zero/Negative() functions (#126065)
Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com> Co-authored-by: Peter Bierma <zintensitydev@gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
parent
abb90ba46c
commit
8ff7efb46d
|
@ -582,6 +582,39 @@ distinguished from a number. Use :c:func:`PyErr_Occurred` to disambiguate.
|
||||||
.. versionadded:: 3.14
|
.. versionadded:: 3.14
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyLong_IsPositive(PyObject *obj)
|
||||||
|
|
||||||
|
Check if the integer object *obj* is positive (``obj > 0``).
|
||||||
|
|
||||||
|
If *obj* is an instance of :c:type:`PyLongObject` or its subtype,
|
||||||
|
return ``1`` when it's positive and ``0`` otherwise. Else set an
|
||||||
|
exception and return ``-1``.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyLong_IsNegative(PyObject *obj)
|
||||||
|
|
||||||
|
Check if the integer object *obj* is negative (``obj < 0``).
|
||||||
|
|
||||||
|
If *obj* is an instance of :c:type:`PyLongObject` or its subtype,
|
||||||
|
return ``1`` when it's negative and ``0`` otherwise. Else set an
|
||||||
|
exception and return ``-1``.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
|
|
||||||
|
.. c:function:: int PyLong_IsZero(PyObject *obj)
|
||||||
|
|
||||||
|
Check if the integer object *obj* is zero.
|
||||||
|
|
||||||
|
If *obj* is an instance of :c:type:`PyLongObject` or its subtype,
|
||||||
|
return ``1`` when it's zero and ``0`` otherwise. Else set an
|
||||||
|
exception and return ``-1``.
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
|
|
||||||
.. c:function:: PyObject* PyLong_GetInfo(void)
|
.. c:function:: PyObject* PyLong_GetInfo(void)
|
||||||
|
|
||||||
On success, return a read only :term:`named tuple`, that holds
|
On success, return a read only :term:`named tuple`, that holds
|
||||||
|
|
|
@ -807,6 +807,11 @@ New features
|
||||||
an interned string and deallocate it during module shutdown.
|
an interned string and deallocate it during module shutdown.
|
||||||
(Contributed by Eddie Elizondo in :gh:`113601`.)
|
(Contributed by Eddie Elizondo in :gh:`113601`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative`
|
||||||
|
and :c:func:`PyLong_IsZero` for checking if :c:type:`PyLongObject`
|
||||||
|
is positive, negative, or zero, respectively.
|
||||||
|
(Contribued by James Roy and Sergey B Kirpichev in :gh:`126061`.)
|
||||||
|
|
||||||
* Add new functions to convert C ``<stdint.h>`` numbers from/to Python
|
* Add new functions to convert C ``<stdint.h>`` numbers from/to Python
|
||||||
:class:`int`:
|
:class:`int`:
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,24 @@ PyAPI_FUNC(PyObject*) PyLong_FromUnsignedNativeBytes(const void* buffer,
|
||||||
PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op);
|
PyAPI_FUNC(int) PyUnstable_Long_IsCompact(const PyLongObject* op);
|
||||||
PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op);
|
PyAPI_FUNC(Py_ssize_t) PyUnstable_Long_CompactValue(const PyLongObject* op);
|
||||||
|
|
||||||
|
/* PyLong_IsPositive. Check if the integer object is positive.
|
||||||
|
|
||||||
|
- On success, return 1 if *obj is positive, and 0 otherwise.
|
||||||
|
- On failure, set an exception, and return -1. */
|
||||||
|
PyAPI_FUNC(int) PyLong_IsPositive(PyObject *obj);
|
||||||
|
|
||||||
|
/* PyLong_IsNegative. Check if the integer object is negative.
|
||||||
|
|
||||||
|
- On success, return 1 if *obj is negative, and 0 otherwise.
|
||||||
|
- On failure, set an exception, and return -1. */
|
||||||
|
PyAPI_FUNC(int) PyLong_IsNegative(PyObject *obj);
|
||||||
|
|
||||||
|
/* PyLong_IsZero. Check if the integer object is zero.
|
||||||
|
|
||||||
|
- On success, return 1 if *obj is zero, and 0 if it is non-zero.
|
||||||
|
- On failure, set an exception, and return -1. */
|
||||||
|
PyAPI_FUNC(int) PyLong_IsZero(PyObject *obj);
|
||||||
|
|
||||||
/* PyLong_GetSign. Get the sign of an integer object:
|
/* PyLong_GetSign. Get the sign of an integer object:
|
||||||
0, -1 or +1 for zero, negative or positive integer, respectively.
|
0, -1 or +1 for zero, negative or positive integer, respectively.
|
||||||
|
|
||||||
|
|
|
@ -643,6 +643,51 @@ class LongTests(unittest.TestCase):
|
||||||
|
|
||||||
# CRASHES getsign(NULL)
|
# CRASHES getsign(NULL)
|
||||||
|
|
||||||
|
def test_long_ispositive(self):
|
||||||
|
# Test PyLong_IsPositive()
|
||||||
|
ispositive = _testcapi.pylong_ispositive
|
||||||
|
self.assertEqual(ispositive(1), 1)
|
||||||
|
self.assertEqual(ispositive(123), 1)
|
||||||
|
self.assertEqual(ispositive(-1), 0)
|
||||||
|
self.assertEqual(ispositive(0), 0)
|
||||||
|
self.assertEqual(ispositive(True), 1)
|
||||||
|
self.assertEqual(ispositive(False), 0)
|
||||||
|
self.assertEqual(ispositive(IntSubclass(-1)), 0)
|
||||||
|
self.assertRaises(TypeError, ispositive, 1.0)
|
||||||
|
self.assertRaises(TypeError, ispositive, Index(123))
|
||||||
|
|
||||||
|
# CRASHES ispositive(NULL)
|
||||||
|
|
||||||
|
def test_long_isnegative(self):
|
||||||
|
# Test PyLong_IsNegative()
|
||||||
|
isnegative = _testcapi.pylong_isnegative
|
||||||
|
self.assertEqual(isnegative(1), 0)
|
||||||
|
self.assertEqual(isnegative(123), 0)
|
||||||
|
self.assertEqual(isnegative(-1), 1)
|
||||||
|
self.assertEqual(isnegative(0), 0)
|
||||||
|
self.assertEqual(isnegative(True), 0)
|
||||||
|
self.assertEqual(isnegative(False), 0)
|
||||||
|
self.assertEqual(isnegative(IntSubclass(-1)), 1)
|
||||||
|
self.assertRaises(TypeError, isnegative, 1.0)
|
||||||
|
self.assertRaises(TypeError, isnegative, Index(123))
|
||||||
|
|
||||||
|
# CRASHES isnegative(NULL)
|
||||||
|
|
||||||
|
def test_long_iszero(self):
|
||||||
|
# Test PyLong_IsZero()
|
||||||
|
iszero = _testcapi.pylong_iszero
|
||||||
|
self.assertEqual(iszero(1), 0)
|
||||||
|
self.assertEqual(iszero(-1), 0)
|
||||||
|
self.assertEqual(iszero(0), 1)
|
||||||
|
self.assertEqual(iszero(True), 0)
|
||||||
|
self.assertEqual(iszero(False), 1)
|
||||||
|
self.assertEqual(iszero(IntSubclass(-1)), 0)
|
||||||
|
self.assertEqual(iszero(IntSubclass(0)), 1)
|
||||||
|
self.assertRaises(TypeError, iszero, 1.0)
|
||||||
|
self.assertRaises(TypeError, iszero, Index(123))
|
||||||
|
|
||||||
|
# CRASHES iszero(NULL)
|
||||||
|
|
||||||
def test_long_asint32(self):
|
def test_long_asint32(self):
|
||||||
# Test PyLong_AsInt32() and PyLong_FromInt32()
|
# Test PyLong_AsInt32() and PyLong_FromInt32()
|
||||||
to_int32 = _testlimitedcapi.pylong_asint32
|
to_int32 = _testlimitedcapi.pylong_asint32
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
Add :c:func:`PyLong_IsPositive`, :c:func:`PyLong_IsNegative`
|
||||||
|
and :c:func:`PyLong_IsZero` for checking if a :c:type:`PyLongObject`
|
||||||
|
is positive, negative, or zero, respectively.
|
|
@ -105,6 +105,30 @@ pylong_getsign(PyObject *module, PyObject *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pylong_ispositive(PyObject *module, PyObject *arg)
|
||||||
|
{
|
||||||
|
NULLABLE(arg);
|
||||||
|
RETURN_INT(PyLong_IsPositive(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pylong_isnegative(PyObject *module, PyObject *arg)
|
||||||
|
{
|
||||||
|
NULLABLE(arg);
|
||||||
|
RETURN_INT(PyLong_IsNegative(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
pylong_iszero(PyObject *module, PyObject *arg)
|
||||||
|
{
|
||||||
|
NULLABLE(arg);
|
||||||
|
RETURN_INT(PyLong_IsZero(arg));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
pylong_aspid(PyObject *module, PyObject *arg)
|
pylong_aspid(PyObject *module, PyObject *arg)
|
||||||
{
|
{
|
||||||
|
@ -124,6 +148,9 @@ static PyMethodDef test_methods[] = {
|
||||||
{"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS},
|
{"pylong_fromnativebytes", pylong_fromnativebytes, METH_VARARGS},
|
||||||
{"pylong_getsign", pylong_getsign, METH_O},
|
{"pylong_getsign", pylong_getsign, METH_O},
|
||||||
{"pylong_aspid", pylong_aspid, METH_O},
|
{"pylong_aspid", pylong_aspid, METH_O},
|
||||||
|
{"pylong_ispositive", pylong_ispositive, METH_O},
|
||||||
|
{"pylong_isnegative", pylong_isnegative, METH_O},
|
||||||
|
{"pylong_iszero", pylong_iszero, METH_O},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -784,6 +784,39 @@ PyLong_AsUnsignedLongMask(PyObject *op)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyLong_IsPositive(PyObject *obj)
|
||||||
|
{
|
||||||
|
assert(obj != NULL);
|
||||||
|
if (!PyLong_Check(obj)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected int, got %T", obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _PyLong_IsPositive((PyLongObject *)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyLong_IsNegative(PyObject *obj)
|
||||||
|
{
|
||||||
|
assert(obj != NULL);
|
||||||
|
if (!PyLong_Check(obj)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected int, got %T", obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _PyLong_IsNegative((PyLongObject *)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
PyLong_IsZero(PyObject *obj)
|
||||||
|
{
|
||||||
|
assert(obj != NULL);
|
||||||
|
if (!PyLong_Check(obj)) {
|
||||||
|
PyErr_Format(PyExc_TypeError, "expected int, got %T", obj);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return _PyLong_IsZero((PyLongObject *)obj);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
_PyLong_Sign(PyObject *vv)
|
_PyLong_Sign(PyObject *vv)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue