mirror of https://github.com/python/cpython
gh-113024: C API: Add PyObject_GenericHash() function (GH-113025)
This commit is contained in:
parent
567ab3bd15
commit
e2e0b4b4b9
|
@ -82,3 +82,14 @@ See also the :c:member:`PyTypeObject.tp_hash` member and :ref:`numeric-hash`.
|
||||||
The function cannot fail: it cannot return ``-1``.
|
The function cannot fail: it cannot return ``-1``.
|
||||||
|
|
||||||
.. versionadded:: 3.13
|
.. versionadded:: 3.13
|
||||||
|
|
||||||
|
.. c:function:: Py_hash_t PyObject_GenericHash(PyObject *obj)
|
||||||
|
|
||||||
|
Generic hashing function that is meant to be put into a type
|
||||||
|
object's ``tp_hash`` slot.
|
||||||
|
Its result only depends on the object's identity.
|
||||||
|
|
||||||
|
.. impl-detail::
|
||||||
|
In CPython, it is equivalent to :c:func:`Py_HashPointer`.
|
||||||
|
|
||||||
|
.. versionadded:: 3.13
|
||||||
|
|
|
@ -883,6 +883,10 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
||||||
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash`, when the subtype's
|
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash`, when the subtype's
|
||||||
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash` are both ``NULL``.
|
:c:member:`~PyTypeObject.tp_richcompare` and :c:member:`~PyTypeObject.tp_hash` are both ``NULL``.
|
||||||
|
|
||||||
|
**Default:**
|
||||||
|
|
||||||
|
:c:data:`PyBaseObject_Type` uses :c:func:`PyObject_GenericHash`.
|
||||||
|
|
||||||
|
|
||||||
.. c:member:: ternaryfunc PyTypeObject.tp_call
|
.. c:member:: ternaryfunc PyTypeObject.tp_call
|
||||||
|
|
||||||
|
|
|
@ -1702,6 +1702,10 @@ New Features
|
||||||
* Add :c:func:`Py_HashPointer` function to hash a pointer.
|
* Add :c:func:`Py_HashPointer` function to hash a pointer.
|
||||||
(Contributed by Victor Stinner in :gh:`111545`.)
|
(Contributed by Victor Stinner in :gh:`111545`.)
|
||||||
|
|
||||||
|
* Add :c:func:`PyObject_GenericHash` function that implements the default
|
||||||
|
hashing function of a Python object.
|
||||||
|
(Contributed by Serhiy Storchaka in :gh:`113024`.)
|
||||||
|
|
||||||
* Add PyTime C API:
|
* Add PyTime C API:
|
||||||
|
|
||||||
* :c:type:`PyTime_t` type.
|
* :c:type:`PyTime_t` type.
|
||||||
|
|
|
@ -43,3 +43,4 @@ typedef struct {
|
||||||
PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void);
|
PyAPI_FUNC(PyHash_FuncDef*) PyHash_GetFuncDef(void);
|
||||||
|
|
||||||
PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr);
|
PyAPI_FUNC(Py_hash_t) Py_HashPointer(const void *ptr);
|
||||||
|
PyAPI_FUNC(Py_hash_t) PyObject_GenericHash(PyObject *);
|
||||||
|
|
|
@ -1001,6 +1001,12 @@ class CAPITest(unittest.TestCase):
|
||||||
self.assertTrue(number_check(0.5))
|
self.assertTrue(number_check(0.5))
|
||||||
self.assertFalse(number_check("1 + 1j"))
|
self.assertFalse(number_check("1 + 1j"))
|
||||||
|
|
||||||
|
def test_object_generichash(self):
|
||||||
|
# Test PyObject_GenericHash()
|
||||||
|
generichash = _testcapi.object_generichash
|
||||||
|
for obj in object(), 1, 'string', []:
|
||||||
|
self.assertEqual(generichash(obj), object.__hash__(obj))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add :c:func:`PyObject_GenericHash` function.
|
|
@ -4780,7 +4780,7 @@ _dec_hash(PyDecObject *v)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (mpd_isnan(MPD(v))) {
|
else if (mpd_isnan(MPD(v))) {
|
||||||
return _Py_HashPointer(v);
|
return PyObject_GenericHash((PyObject *)v);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return py_hash_inf * mpd_arith_sign(MPD(v));
|
return py_hash_inf * mpd_arith_sign(MPD(v));
|
||||||
|
|
|
@ -59,9 +59,20 @@ hash_pointer(PyObject *Py_UNUSED(module), PyObject *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
object_generichash(PyObject *Py_UNUSED(module), PyObject *arg)
|
||||||
|
{
|
||||||
|
NULLABLE(arg);
|
||||||
|
Py_hash_t hash = PyObject_GenericHash(arg);
|
||||||
|
Py_BUILD_ASSERT(sizeof(long long) >= sizeof(hash));
|
||||||
|
return PyLong_FromLongLong(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyMethodDef test_methods[] = {
|
static PyMethodDef test_methods[] = {
|
||||||
{"hash_getfuncdef", hash_getfuncdef, METH_NOARGS},
|
{"hash_getfuncdef", hash_getfuncdef, METH_NOARGS},
|
||||||
{"hash_pointer", hash_pointer, METH_O},
|
{"hash_pointer", hash_pointer, METH_O},
|
||||||
|
{"object_generichash", object_generichash, METH_O},
|
||||||
{NULL},
|
{NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -301,7 +301,7 @@ static Py_hash_t
|
||||||
method_hash(PyMethodObject *a)
|
method_hash(PyMethodObject *a)
|
||||||
{
|
{
|
||||||
Py_hash_t x, y;
|
Py_hash_t x, y;
|
||||||
x = _Py_HashPointer(a->im_self);
|
x = PyObject_GenericHash(a->im_self);
|
||||||
y = PyObject_Hash(a->im_func);
|
y = PyObject_Hash(a->im_func);
|
||||||
if (y == -1)
|
if (y == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -1346,7 +1346,7 @@ wrapper_hash(PyObject *self)
|
||||||
{
|
{
|
||||||
wrapperobject *wp = (wrapperobject *)self;
|
wrapperobject *wp = (wrapperobject *)self;
|
||||||
Py_hash_t x, y;
|
Py_hash_t x, y;
|
||||||
x = _Py_HashPointer(wp->self);
|
x = PyObject_GenericHash(wp->self);
|
||||||
y = _Py_HashPointer(wp->descr);
|
y = _Py_HashPointer(wp->descr);
|
||||||
x = x ^ y;
|
x = x ^ y;
|
||||||
if (x == -1)
|
if (x == -1)
|
||||||
|
|
|
@ -320,7 +320,7 @@ static Py_hash_t
|
||||||
meth_hash(PyCFunctionObject *a)
|
meth_hash(PyCFunctionObject *a)
|
||||||
{
|
{
|
||||||
Py_hash_t x, y;
|
Py_hash_t x, y;
|
||||||
x = _Py_HashPointer(a->m_self);
|
x = PyObject_GenericHash(a->m_self);
|
||||||
y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
|
y = _Py_HashPointer((void*)(a->m_ml->ml_meth));
|
||||||
x ^= y;
|
x ^= y;
|
||||||
if (x == -1)
|
if (x == -1)
|
||||||
|
|
|
@ -6891,12 +6891,6 @@ PyDoc_STRVAR(object_doc,
|
||||||
"When called, it accepts no arguments and returns a new featureless\n"
|
"When called, it accepts no arguments and returns a new featureless\n"
|
||||||
"instance that has no instance attributes and cannot be given any.\n");
|
"instance that has no instance attributes and cannot be given any.\n");
|
||||||
|
|
||||||
static Py_hash_t
|
|
||||||
object_hash(PyObject *obj)
|
|
||||||
{
|
|
||||||
return _Py_HashPointer(obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTypeObject PyBaseObject_Type = {
|
PyTypeObject PyBaseObject_Type = {
|
||||||
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
||||||
"object", /* tp_name */
|
"object", /* tp_name */
|
||||||
|
@ -6911,7 +6905,7 @@ PyTypeObject PyBaseObject_Type = {
|
||||||
0, /* tp_as_number */
|
0, /* tp_as_number */
|
||||||
0, /* tp_as_sequence */
|
0, /* tp_as_sequence */
|
||||||
0, /* tp_as_mapping */
|
0, /* tp_as_mapping */
|
||||||
object_hash, /* tp_hash */
|
PyObject_GenericHash, /* tp_hash */
|
||||||
0, /* tp_call */
|
0, /* tp_call */
|
||||||
object_str, /* tp_str */
|
object_str, /* tp_str */
|
||||||
PyObject_GenericGetAttr, /* tp_getattro */
|
PyObject_GenericGetAttr, /* tp_getattro */
|
||||||
|
|
|
@ -200,7 +200,7 @@ PyHKEY_hashFunc(PyObject *ob)
|
||||||
/* Just use the address.
|
/* Just use the address.
|
||||||
XXX - should we use the handle value?
|
XXX - should we use the handle value?
|
||||||
*/
|
*/
|
||||||
return _Py_HashPointer(ob);
|
return PyObject_GenericHash(ob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ _Py_HashDouble(PyObject *inst, double v)
|
||||||
if (Py_IS_INFINITY(v))
|
if (Py_IS_INFINITY(v))
|
||||||
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
|
return v > 0 ? _PyHASH_INF : -_PyHASH_INF;
|
||||||
else
|
else
|
||||||
return _Py_HashPointer(inst);
|
return PyObject_GenericHash(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
m = frexp(v, &e);
|
m = frexp(v, &e);
|
||||||
|
@ -139,6 +139,12 @@ Py_HashPointer(const void *ptr)
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Py_hash_t
|
||||||
|
PyObject_GenericHash(PyObject *obj)
|
||||||
|
{
|
||||||
|
return Py_HashPointer(obj);
|
||||||
|
}
|
||||||
|
|
||||||
Py_hash_t
|
Py_hash_t
|
||||||
_Py_HashBytes(const void *src, Py_ssize_t len)
|
_Py_HashBytes(const void *src, Py_ssize_t len)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue