Skip to content

Commit 669c882

Browse files
authored
Add PyLong_FromUInt64() and PyLong_AsUInt64() (#114)
1 parent 38e2d32 commit 669c882

File tree

4 files changed

+168
-8
lines changed

4 files changed

+168
-8
lines changed

docs/api.rst

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,39 @@ Python 3.14
8989

9090
See `PyUnicodeWriter_Format() documentation <https://docs.python.org/dev/c-api/unicode.html#c.PyUnicodeWriter_Format>`__.
9191

92+
.. c:function:: int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
93+
94+
See `PyLong_AsInt32() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsInt32>`__.
95+
96+
.. c:function:: int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
97+
98+
See `PyLong_AsInt64() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsInt64>`__.
99+
100+
.. c:function:: int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
101+
102+
See `PyLong_AsUInt32() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsUInt32>`__.
103+
104+
.. c:function:: int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
105+
106+
See `PyLong_AsUInt64() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_AsUInt64>`__.
107+
108+
.. c:function:: PyObject* PyLong_FromInt32(int32_t value)
109+
110+
See `PyLong_FromInt32() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FromInt32>`__.
111+
112+
.. c:function:: PyObject* PyLong_FromInt64(int64_t value)
113+
114+
See `PyLong_FromInt64() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FromInt64>`__.
115+
116+
.. c:function:: PyObject* PyLong_FromUInt32(uint32_t value)
117+
118+
See `PyLong_FromUInt32() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FromUInt32>`__.
119+
120+
.. c:function:: PyObject* PyLong_FromUInt64(uint64_t value)
121+
122+
See `PyLong_FromUInt64() documentation <https://docs.python.org/dev/c-api/long.html#c.PyLong_FromUInt64>`__.
123+
124+
92125
Not supported:
93126

94127
* ``PyConfig_Get()``
@@ -108,14 +141,6 @@ Not supported:
108141
* ``PyInitConfig_SetInt()``
109142
* ``PyInitConfig_SetStr()``
110143
* ``PyInitConfig_SetStrList()``
111-
* ``PyLong_AsInt32()``
112-
* ``PyLong_AsInt64()``
113-
* ``PyLong_AsUInt32()``
114-
* ``PyLong_AsUInt64()``
115-
* ``PyLong_FromInt32()``
116-
* ``PyLong_FromInt64()``
117-
* ``PyLong_FromUInt32()``
118-
* ``PyLong_FromUInt64()``
119144
* ``PyType_GetBaseByToken()``
120145
* ``PyUnicodeWriter_DecodeUTF8Stateful()``
121146
* ``Py_InitializeFromInitConfig()``

docs/changelog.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ Changelog
55

66
* ``PyBytes_Join()``
77
* ``PyIter_NextItem()``
8+
* ``PyLong_AsInt32()``
9+
* ``PyLong_AsInt64()``
10+
* ``PyLong_AsUInt32()``
11+
* ``PyLong_AsUInt64()``
12+
* ``PyLong_FromInt32()``
13+
* ``PyLong_FromInt64()``
14+
* ``PyLong_FromUInt32()``
15+
* ``PyLong_FromUInt64()``
816
* ``PyUnicode_Equal()``
917
* ``Py_HashBuffer()``
1018

pythoncapi_compat.h

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ extern "C" {
4545
# define _PyObject_CAST(op) _Py_CAST(PyObject*, op)
4646
#endif
4747

48+
#ifndef Py_BUILD_ASSERT
49+
# define Py_BUILD_ASSERT(cond) \
50+
do { \
51+
(void)sizeof(char [1 - 2 * !(cond)]); \
52+
} while(0)
53+
#endif
54+
4855

4956
// bpo-42262 added Py_NewRef() to Python 3.10.0a3
5057
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
@@ -1605,6 +1612,84 @@ static inline int PyIter_NextItem(PyObject *iter, PyObject **item)
16051612
#endif
16061613

16071614

1615+
#if PY_VERSION_HEX < 0x030E00A0
1616+
static inline PyObject* PyLong_FromInt32(int32_t value)
1617+
{
1618+
Py_BUILD_ASSERT(sizeof(long) >= 4);
1619+
return PyLong_FromLong(value);
1620+
}
1621+
1622+
static inline PyObject* PyLong_FromInt64(int64_t value)
1623+
{
1624+
Py_BUILD_ASSERT(sizeof(long long) >= 8);
1625+
return PyLong_FromLongLong(value);
1626+
}
1627+
1628+
static inline PyObject* PyLong_FromUInt32(uint32_t value)
1629+
{
1630+
Py_BUILD_ASSERT(sizeof(unsigned long) >= 4);
1631+
return PyLong_FromUnsignedLong(value);
1632+
}
1633+
1634+
static inline PyObject* PyLong_FromUInt64(uint64_t value)
1635+
{
1636+
Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8);
1637+
return PyLong_FromUnsignedLongLong(value);
1638+
}
1639+
1640+
static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue)
1641+
{
1642+
Py_BUILD_ASSERT(sizeof(int) == 4);
1643+
int value = PyLong_AsInt(obj);
1644+
if (value == -1 && PyErr_Occurred()) {
1645+
return -1;
1646+
}
1647+
*pvalue = (int32_t)value;
1648+
return 0;
1649+
}
1650+
1651+
static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue)
1652+
{
1653+
Py_BUILD_ASSERT(sizeof(long long) == 8);
1654+
long long value = PyLong_AsLongLong(obj);
1655+
if (value == -1 && PyErr_Occurred()) {
1656+
return -1;
1657+
}
1658+
*pvalue = (int64_t)value;
1659+
return 0;
1660+
}
1661+
1662+
static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue)
1663+
{
1664+
Py_BUILD_ASSERT(sizeof(long) >= 4);
1665+
unsigned long value = PyLong_AsUnsignedLong(obj);
1666+
if (value == (unsigned long)-1 && PyErr_Occurred()) {
1667+
return -1;
1668+
}
1669+
#if SIZEOF_LONG > 4
1670+
if ((unsigned long)UINT32_MAX < value) {
1671+
PyErr_SetString(PyExc_OverflowError,
1672+
"Python int too large to convert to C uint32_t");
1673+
return -1;
1674+
}
1675+
#endif
1676+
*pvalue = (uint32_t)value;
1677+
return 0;
1678+
}
1679+
1680+
static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue)
1681+
{
1682+
Py_BUILD_ASSERT(sizeof(long long) == 8);
1683+
unsigned long long value = PyLong_AsUnsignedLongLong(obj);
1684+
if (value == (unsigned long long)-1 && PyErr_Occurred()) {
1685+
return -1;
1686+
}
1687+
*pvalue = (uint64_t)value;
1688+
return 0;
1689+
}
1690+
#endif
1691+
1692+
16081693
#ifdef __cplusplus
16091694
}
16101695
#endif

tests/test_pythoncapi_compat_cext.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,47 @@ test_iter(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
19711971
}
19721972

19731973

1974+
static PyObject *
1975+
test_long_stdint(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
1976+
{
1977+
PyObject *obj;
1978+
1979+
// Test PyLong_FromInt32() and PyLong_AsInt32()
1980+
obj = PyLong_FromInt32(INT32_C(-0x12345678));
1981+
assert(obj != NULL);
1982+
int32_t i32;
1983+
assert(PyLong_AsInt32(obj, &i32) == 0);
1984+
assert(i32 == INT32_C(-0x12345678));
1985+
Py_DECREF(obj);
1986+
1987+
// Test PyLong_FromUInt32() and PyLong_AsUInt32()
1988+
obj = PyLong_FromUInt32(UINT32_C(0xDEADBEEF));
1989+
assert(obj != NULL);
1990+
uint32_t u32;
1991+
assert(PyLong_AsUInt32(obj, &u32) == 0);
1992+
assert(u32 == UINT32_C(0xDEADBEEF));
1993+
Py_DECREF(obj);
1994+
1995+
// Test PyLong_FromInt64() and PyLong_AsInt64()
1996+
obj = PyLong_FromInt64(INT64_C(-0x12345678DEADBEEF));
1997+
assert(obj != NULL);
1998+
int64_t i64;
1999+
assert(PyLong_AsInt64(obj, &i64) == 0);
2000+
assert(i64 == INT64_C(-0x12345678DEADBEEF));
2001+
Py_DECREF(obj);
2002+
2003+
// Test PyLong_FromUInt64() and PyLong_AsUInt64()
2004+
obj = PyLong_FromUInt64(UINT64_C(0xDEADBEEF12345678));
2005+
assert(obj != NULL);
2006+
uint64_t u64;
2007+
assert(PyLong_AsUInt64(obj, &u64) == 0);
2008+
assert(u64 == UINT64_C(0xDEADBEEF12345678));
2009+
Py_DECREF(obj);
2010+
2011+
Py_RETURN_NONE;
2012+
}
2013+
2014+
19742015
static struct PyMethodDef methods[] = {
19752016
{"test_object", test_object, METH_NOARGS, _Py_NULL},
19762017
{"test_py_is", test_py_is, METH_NOARGS, _Py_NULL},
@@ -2016,6 +2057,7 @@ static struct PyMethodDef methods[] = {
20162057
#endif
20172058
{"test_bytes", test_bytes, METH_NOARGS, _Py_NULL},
20182059
{"test_iter", test_iter, METH_NOARGS, _Py_NULL},
2060+
{"test_long_stdint", test_long_stdint, METH_NOARGS, _Py_NULL},
20192061
{_Py_NULL, _Py_NULL, 0, _Py_NULL}
20202062
};
20212063

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy