bpo-38075: Port _randommodule.c to PEP-384 (GH-15798)
- Migrate `Random_Type` to `PyType_FromSpec` - To simulate an old use of `PyLong_Type.tp_as_number->nb_absolute`, I added code to the module init function to stash `int.__abs__` for later use. Ideally we'd use `PyType_GetSlot()` instead, but it doesn't currently work for static types in CPython, and implementing it just for this case doesn't seem worth it. - Do exact check for long and dispatch to PyNumber_Absolute, use vector call when not exact.
This commit is contained in:
parent
42671aea2d
commit
04f0bbfbed
|
@ -0,0 +1 @@
|
|||
The random module is now PEP-384 compatible
|
|
@ -79,15 +79,23 @@
|
|||
#define UPPER_MASK 0x80000000U /* most significant w-r bits */
|
||||
#define LOWER_MASK 0x7fffffffU /* least significant r bits */
|
||||
|
||||
typedef struct {
|
||||
PyObject *Random_Type;
|
||||
PyObject *Long___abs__;
|
||||
} _randomstate;
|
||||
|
||||
#define _randomstate(o) ((_randomstate *)PyModule_GetState(o))
|
||||
|
||||
static struct PyModuleDef _randommodule;
|
||||
|
||||
#define _randomstate_global _randomstate(PyState_FindModule(&_randommodule))
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
int index;
|
||||
uint32_t state[N];
|
||||
} RandomObject;
|
||||
|
||||
static PyTypeObject Random_Type;
|
||||
|
||||
#define RandomObject_Check(v) (Py_TYPE(v) == &Random_Type)
|
||||
|
||||
#include "clinic/_randommodule.c.h"
|
||||
|
||||
|
@ -256,6 +264,7 @@ random_seed(RandomObject *self, PyObject *arg)
|
|||
uint32_t *key = NULL;
|
||||
size_t bits, keyused;
|
||||
int res;
|
||||
PyObject *args[1];
|
||||
|
||||
if (arg == NULL || arg == Py_None) {
|
||||
if (random_seed_urandom(self) < 0) {
|
||||
|
@ -272,10 +281,14 @@ random_seed(RandomObject *self, PyObject *arg)
|
|||
* So: if the arg is a PyLong, use its absolute value.
|
||||
* Otherwise use its hash value, cast to unsigned.
|
||||
*/
|
||||
if (PyLong_Check(arg)) {
|
||||
if (PyLong_CheckExact(arg)) {
|
||||
n = PyNumber_Absolute(arg);
|
||||
} else if (PyLong_Check(arg)) {
|
||||
/* Calling int.__abs__() prevents calling arg.__abs__(), which might
|
||||
return an invalid value. See issue #31478. */
|
||||
n = PyLong_Type.tp_as_number->nb_absolute(arg);
|
||||
args[0] = arg;
|
||||
n = _PyObject_Vectorcall(_randomstate_global->Long___abs__, args, 0,
|
||||
NULL);
|
||||
}
|
||||
else {
|
||||
Py_hash_t hash = PyObject_Hash(arg);
|
||||
|
@ -500,10 +513,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||
RandomObject *self;
|
||||
PyObject *tmp;
|
||||
|
||||
if (type == &Random_Type && !_PyArg_NoKeywords("Random", kwds))
|
||||
if (type == (PyTypeObject*)_randomstate_global->Random_Type &&
|
||||
!_PyArg_NoKeywords("Random()", kwds)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
self = (RandomObject *)type->tp_alloc(type, 0);
|
||||
self = (RandomObject *)PyType_GenericAlloc(type, 0);
|
||||
if (self == NULL)
|
||||
return NULL;
|
||||
tmp = random_seed(self, args);
|
||||
|
@ -527,64 +542,55 @@ static PyMethodDef random_methods[] = {
|
|||
PyDoc_STRVAR(random_doc,
|
||||
"Random() -> create a random number generator with its own internal state.");
|
||||
|
||||
static PyTypeObject Random_Type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_random.Random", /*tp_name*/
|
||||
sizeof(RandomObject), /*tp_basicsize*/
|
||||
0, /*tp_itemsize*/
|
||||
/* methods */
|
||||
0, /*tp_dealloc*/
|
||||
0, /*tp_vectorcall_offset*/
|
||||
0, /*tp_getattr*/
|
||||
0, /*tp_setattr*/
|
||||
0, /*tp_as_async*/
|
||||
0, /*tp_repr*/
|
||||
0, /*tp_as_number*/
|
||||
0, /*tp_as_sequence*/
|
||||
0, /*tp_as_mapping*/
|
||||
0, /*tp_hash*/
|
||||
0, /*tp_call*/
|
||||
0, /*tp_str*/
|
||||
PyObject_GenericGetAttr, /*tp_getattro*/
|
||||
0, /*tp_setattro*/
|
||||
0, /*tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
|
||||
random_doc, /*tp_doc*/
|
||||
0, /*tp_traverse*/
|
||||
0, /*tp_clear*/
|
||||
0, /*tp_richcompare*/
|
||||
0, /*tp_weaklistoffset*/
|
||||
0, /*tp_iter*/
|
||||
0, /*tp_iternext*/
|
||||
random_methods, /*tp_methods*/
|
||||
0, /*tp_members*/
|
||||
0, /*tp_getset*/
|
||||
0, /*tp_base*/
|
||||
0, /*tp_dict*/
|
||||
0, /*tp_descr_get*/
|
||||
0, /*tp_descr_set*/
|
||||
0, /*tp_dictoffset*/
|
||||
0, /*tp_init*/
|
||||
0, /*tp_alloc*/
|
||||
random_new, /*tp_new*/
|
||||
PyObject_Free, /*tp_free*/
|
||||
0, /*tp_is_gc*/
|
||||
static PyType_Slot Random_Type_slots[] = {
|
||||
{Py_tp_doc, random_doc},
|
||||
{Py_tp_methods, random_methods},
|
||||
{Py_tp_new, random_new},
|
||||
{Py_tp_free, PyObject_Free},
|
||||
{0, 0},
|
||||
};
|
||||
|
||||
static PyType_Spec Random_Type_spec = {
|
||||
"_random.Random",
|
||||
sizeof(RandomObject),
|
||||
0,
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
Random_Type_slots
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(module_doc,
|
||||
"Module implements the Mersenne Twister random number generator.");
|
||||
|
||||
static int
|
||||
_random_traverse(PyObject *module, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(_randomstate(module)->Random_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_random_clear(PyObject *module)
|
||||
{
|
||||
Py_CLEAR(_randomstate(module)->Random_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_random_free(void *module)
|
||||
{
|
||||
_random_clear((PyObject *)module);
|
||||
}
|
||||
|
||||
static struct PyModuleDef _randommodule = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_random",
|
||||
module_doc,
|
||||
-1,
|
||||
sizeof(_randomstate),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
_random_traverse,
|
||||
_random_clear,
|
||||
_random_free,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
|
@ -592,12 +598,41 @@ PyInit__random(void)
|
|||
{
|
||||
PyObject *m;
|
||||
|
||||
if (PyType_Ready(&Random_Type) < 0)
|
||||
PyObject *Random_Type = PyType_FromSpec(&Random_Type_spec);
|
||||
if (Random_Type == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m = PyModule_Create(&_randommodule);
|
||||
if (m == NULL)
|
||||
if (m == NULL) {
|
||||
Py_DECREF(Random_Type);
|
||||
return NULL;
|
||||
Py_INCREF(&Random_Type);
|
||||
PyModule_AddObject(m, "Random", (PyObject *)&Random_Type);
|
||||
}
|
||||
_randomstate(m)->Random_Type = Random_Type;
|
||||
|
||||
Py_INCREF(Random_Type);
|
||||
PyModule_AddObject(m, "Random", Random_Type);
|
||||
|
||||
/* Look up and save int.__abs__, which is needed in random_seed(). */
|
||||
PyObject *longval = NULL, *longtype = NULL;
|
||||
longval = PyLong_FromLong(0);
|
||||
if (longval == NULL) goto fail;
|
||||
|
||||
longtype = PyObject_Type(longval);
|
||||
if (longtype == NULL) goto fail;
|
||||
|
||||
PyObject *abs = PyObject_GetAttrString(longtype, "__abs__");
|
||||
if (abs == NULL) goto fail;
|
||||
|
||||
Py_DECREF(longtype);
|
||||
Py_DECREF(longval);
|
||||
_randomstate(m)->Long___abs__ = abs;
|
||||
|
||||
return m;
|
||||
|
||||
fail:
|
||||
Py_XDECREF(longtype);
|
||||
Py_XDECREF(longval);
|
||||
Py_DECREF(m);
|
||||
return NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue