diff --git a/docs/api.rst b/docs/api.rst index c1ef118..32db605 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -137,6 +137,10 @@ Python 3.13 See `PyDict_PopString() documentation `__. +.. c:function:: Py_hash_t Py_HashPointer(const void *ptr) + + See `Py_HashPointer() documentation `__. + Python 3.12 ----------- diff --git a/docs/changelog.rst b/docs/changelog.rst index 834b4f6..40fdece 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,7 @@ Changelog ========= +* 2023-12-15: Add function ``Py_HashPointer()``. * 2023-11-14: Add functions: * ``PyDict_Pop()`` diff --git a/pythoncapi_compat.h b/pythoncapi_compat.h index 4a3f733..8b356b2 100644 --- a/pythoncapi_compat.h +++ b/pythoncapi_compat.h @@ -1089,6 +1089,25 @@ PyDict_PopString(PyObject *dict, const char *key, PyObject **result) } #endif + +#if PY_VERSION_HEX < 0x030200A4 +// Python 3.2.0a4 added Py_hash_t type +typedef Py_ssize_t Py_hash_t; +#endif + + +// gh-111545 added Py_HashPointer() to Python 3.13.0a3 +#if PY_VERSION_HEX < 0x030D00A3 +static inline Py_hash_t Py_HashPointer(const void *ptr) +{ +#if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION) + return _Py_HashPointer(ptr); +#else + return _Py_HashPointer(_Py_CAST(void*, ptr)); +#endif +} +#endif + #ifdef __cplusplus } #endif diff --git a/tests/test_pythoncapi_compat_cext.c b/tests/test_pythoncapi_compat_cext.c index 83969af..b8d73a5 100644 --- a/tests/test_pythoncapi_compat_cext.c +++ b/tests/test_pythoncapi_compat_cext.c @@ -1498,6 +1498,34 @@ test_list(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) } +static PyObject * +test_hash(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args)) +{ + void *ptr0 = NULL; + assert(Py_HashPointer(ptr0) == 0); + +#ifndef PYPY_VERSION +#if SIZEOF_VOID_P == 8 + void *ptr1 = (void*)(uintptr_t)0xABCDEF1234567890; + assert(Py_HashPointer(ptr1) == (uintptr_t)0x0ABCDEF123456789); +#else + void *ptr1 = (void*)(uintptr_t)0xDEADCAFE; + assert(Py_HashPointer(ptr1) == (uintptr_t)0xEDEADCAF); +#endif +#else + // PyPy +#if SIZEOF_VOID_P == 8 + void *ptr1 = (void*)(uintptr_t)0xABCDEF1234567890; +#else + void *ptr1 = (void*)(uintptr_t)0xDEADCAFE; +#endif + assert(Py_HashPointer(ptr1) == (Py_hash_t)ptr1); +#endif + + Py_RETURN_NONE; +} + + static struct PyMethodDef methods[] = { {"test_object", test_object, METH_NOARGS, _Py_NULL}, {"test_py_is", test_py_is, METH_NOARGS, _Py_NULL}, @@ -1530,6 +1558,7 @@ static struct PyMethodDef methods[] = { #endif {"test_unicode", test_unicode, METH_NOARGS, _Py_NULL}, {"test_list", test_list, METH_NOARGS, _Py_NULL}, + {"test_hash", test_hash, METH_NOARGS, _Py_NULL}, {_Py_NULL, _Py_NULL, 0, _Py_NULL} };