Skip to content

gh-111545: Test PyHash_GetFuncDef() function #112098

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 15, 2023
Merged
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
48 changes: 48 additions & 0 deletions Doc/c-api/hash.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.. highlight:: c

PyHash API
----------

See also the :c:member:`PyTypeObject.tp_hash` member.

.. c:type:: Py_hash_t

Hash value type: signed integer.

.. versionadded:: 3.2

.. c:type:: Py_uhash_t

Hash value type: unsigned integer.

.. versionadded:: 3.2


.. c:type:: PyHash_FuncDef

Hash function definition used by :c:func:`PyHash_GetFuncDef`.

.. c::member:: Py_hash_t (*const hash)(const void *, Py_ssize_t)

Hash function.

.. c:member:: const char *name

Hash function name (UTF-8 encoded string).

.. c:member:: const int hash_bits

Internal size of the hash value in bits.

.. c:member:: const int seed_bits

Size of seed input in bits.

.. versionadded:: 3.4


.. c:function:: PyHash_FuncDef* PyHash_GetFuncDef(void)

Get the hash function definition.

.. versionadded:: 3.4
1 change: 1 addition & 0 deletions Doc/c-api/utilities.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and parsing function arguments and constructing Python values from C values.
marshal.rst
arg.rst
conversion.rst
hash.rst
reflection.rst
codec.rst
perfmaps.rst
33 changes: 33 additions & 0 deletions Lib/test/test_capi/test_hash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import sys
import unittest
from test.support import import_helper
_testcapi = import_helper.import_module('_testcapi')


SIZEOF_PY_HASH_T = _testcapi.SIZEOF_VOID_P


class CAPITest(unittest.TestCase):
def test_hash_getfuncdef(self):
# Test PyHash_GetFuncDef()
hash_getfuncdef = _testcapi.hash_getfuncdef
func_def = hash_getfuncdef()

match func_def.name:
case "fnv":
self.assertEqual(func_def.hash_bits, 8 * SIZEOF_PY_HASH_T)
self.assertEqual(func_def.seed_bits, 16 * SIZEOF_PY_HASH_T)
case "siphash13":
self.assertEqual(func_def.hash_bits, 64)
self.assertEqual(func_def.seed_bits, 128)
case "siphash24":
self.assertEqual(func_def.hash_bits, 64)
self.assertEqual(func_def.seed_bits, 128)
case _:
self.fail(f"unknown function name: {func_def.name!r}")

# compare with sys.hash_info
hash_info = sys.hash_info
self.assertEqual(func_def.name, hash_info.algorithm)
self.assertEqual(func_def.hash_bits, hash_info.hash_bits)
self.assertEqual(func_def.seed_bits, hash_info.seed_bits)
2 changes: 1 addition & 1 deletion Modules/Setup.stdlib.in
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
@MODULE__XXTESTFUZZ_TRUE@_xxtestfuzz _xxtestfuzz/_xxtestfuzz.c _xxtestfuzz/fuzzer.c
@MODULE__TESTBUFFER_TRUE@_testbuffer _testbuffer.c
@MODULE__TESTINTERNALCAPI_TRUE@_testinternalcapi _testinternalcapi.c _testinternalcapi/test_lock.c _testinternalcapi/pytime.c _testinternalcapi/set.c _testinternalcapi/test_critical_sections.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c
@MODULE__TESTCAPI_TRUE@_testcapi _testcapimodule.c _testcapi/vectorcall.c _testcapi/vectorcall_limited.c _testcapi/heaptype.c _testcapi/abstract.c _testcapi/bytearray.c _testcapi/bytes.c _testcapi/unicode.c _testcapi/dict.c _testcapi/set.c _testcapi/list.c _testcapi/tuple.c _testcapi/getargs.c _testcapi/datetime.c _testcapi/docstring.c _testcapi/mem.c _testcapi/watchers.c _testcapi/long.c _testcapi/float.c _testcapi/complex.c _testcapi/numbers.c _testcapi/structmember.c _testcapi/exceptions.c _testcapi/code.c _testcapi/buffer.c _testcapi/pyatomic.c _testcapi/pyos.c _testcapi/file.c _testcapi/codec.c _testcapi/immortal.c _testcapi/heaptype_relative.c _testcapi/gc.c _testcapi/sys.c _testcapi/hash.c
@MODULE__TESTCLINIC_TRUE@_testclinic _testclinic.c
@MODULE__TESTCLINIC_LIMITED_TRUE@_testclinic_limited _testclinic_limited.c

Expand Down
56 changes: 56 additions & 0 deletions Modules/_testcapi/hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#include "parts.h"
#include "util.h"

static PyObject *
hash_getfuncdef(PyObject *Py_UNUSED(module), PyObject *Py_UNUSED(args))
{
// bind PyHash_GetFuncDef()
PyHash_FuncDef *def = PyHash_GetFuncDef();

PyObject *types = PyImport_ImportModule("types");
if (types == NULL) {
return NULL;
}

PyObject *result = PyObject_CallMethod(types, "SimpleNamespace", NULL);
Py_DECREF(types);
if (result == NULL) {
return NULL;
}

// ignore PyHash_FuncDef.hash

PyObject *value = PyUnicode_FromString(def->name);
int res = PyObject_SetAttrString(result, "name", value);
Py_DECREF(value);
if (res < 0) {
return NULL;
}

value = PyLong_FromLong(def->hash_bits);
res = PyObject_SetAttrString(result, "hash_bits", value);
Py_DECREF(value);
if (res < 0) {
return NULL;
}

value = PyLong_FromLong(def->seed_bits);
res = PyObject_SetAttrString(result, "seed_bits", value);
Py_DECREF(value);
if (res < 0) {
return NULL;
}

return result;
}

static PyMethodDef test_methods[] = {
{"hash_getfuncdef", hash_getfuncdef, METH_NOARGS},
{NULL},
};

int
_PyTestCapi_Init_Hash(PyObject *m)
{
return PyModule_AddFunctions(m, test_methods);
}
1 change: 1 addition & 0 deletions Modules/_testcapi/parts.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ int _PyTestCapi_Init_Codec(PyObject *module);
int _PyTestCapi_Init_Immortal(PyObject *module);
int _PyTestCapi_Init_GC(PyObject *module);
int _PyTestCapi_Init_Sys(PyObject *module);
int _PyTestCapi_Init_Hash(PyObject *module);

int _PyTestCapi_Init_VectorcallLimited(PyObject *module);
int _PyTestCapi_Init_HeaptypeRelative(PyObject *module);
Expand Down
3 changes: 3 additions & 0 deletions Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -3995,6 +3995,9 @@ PyInit__testcapi(void)
if (_PyTestCapi_Init_HeaptypeRelative(m) < 0) {
return NULL;
}
if (_PyTestCapi_Init_Hash(m) < 0) {
return NULL;
}

PyState_AddModule(m, &_testcapimodule);
return m;
Expand Down
1 change: 1 addition & 0 deletions PCbuild/_testcapi.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
<ClCompile Include="..\Modules\_testcapi\file.c" />
<ClCompile Include="..\Modules\_testcapi\codec.c" />
<ClCompile Include="..\Modules\_testcapi\sys.c" />
<ClCompile Include="..\Modules\_testcapi\hash.c" />
<ClCompile Include="..\Modules\_testcapi\immortal.c" />
<ClCompile Include="..\Modules\_testcapi\gc.c" />
</ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions PCbuild/_testcapi.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@
<ClCompile Include="..\Modules\_testcapi\sys.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\hash.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Modules\_testcapi\gc.c">
<Filter>Source Files</Filter>
</ClCompile>
Expand Down