bpo-29882: Add _Py_popcount32() function (GH-20518) · python/cpython@c6b292c

GitHub

@@ -12,7 +12,7 @@

1212#definePY_SSIZE_T_CLEAN

13131414#include"Python.h"

15-#include"pycore_byteswap.h"// _Py_bswap32()

15+#include"pycore_bitutils.h"// _Py_bswap32()

1616#include"pycore_initconfig.h"// _Py_GetConfigsAsDict()

1717#include"pycore_hashtable.h"// _Py_hashtable_new()

1818#include"pycore_gc.h"// PyGC_Head

@@ -63,6 +63,45 @@ test_bswap(PyObject *self, PyObject *Py_UNUSED(args))

6363}

6464656566+staticint

67+check_popcount(uint32_tx, intexpected)

68+{

69+// Use volatile to prevent the compiler to optimize out the whole test

70+volatileuint32_tu=x;

71+intbits=_Py_popcount32(u);

72+if (bits!=expected) {

73+PyErr_Format(PyExc_AssertionError,

74+"_Py_popcount32(%lu) returns %i, expected %i",

75+ (unsigned long)x, bits, expected);

76+return-1;

77+ }

78+return0;

79+}

80+81+82+staticPyObject*

83+test_popcount(PyObject*self, PyObject*Py_UNUSED(args))

84+{

85+#defineCHECK(X, RESULT) \

86+ do { \

87+ if (check_popcount(X, RESULT) < 0) { \

88+ return NULL; \

89+ } \

90+ } while (0)

91+92+CHECK(0, 0);

93+CHECK(1, 1);

94+CHECK(0x08080808, 4);

95+CHECK(0x10101010, 4);

96+CHECK(0x10204080, 4);

97+CHECK(0xDEADCAFE, 22);

98+CHECK(0xFFFFFFFF, 32);

99+Py_RETURN_NONE;

100+101+#undef CHECK

102+}

103+104+66105#defineTO_PTR(ch) ((void*)(uintptr_t)ch)

67106#defineFROM_PTR(ptr) ((uintptr_t)ptr)

68107#defineVALUE(key) (1 + ((int)(key) - 'a'))

@@ -157,6 +196,7 @@ static PyMethodDef TestMethods[] = {

157196 {"get_configs", get_configs, METH_NOARGS},

158197 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},

159198 {"test_bswap", test_bswap, METH_NOARGS},

199+ {"test_popcount", test_popcount, METH_NOARGS},

160200 {"test_hashtable", test_hashtable, METH_NOARGS},

161201 {NULL, NULL} /* sentinel */

162202};