Commit 04f0bbfb authored by Dino Viehland's avatar Dino Viehland Committed by T. Wouters

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.
parent 42671aea
The random module is now PEP-384 compatible
\ No newline at end of file
...@@ -79,15 +79,23 @@ ...@@ -79,15 +79,23 @@
#define UPPER_MASK 0x80000000U /* most significant w-r bits */ #define UPPER_MASK 0x80000000U /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffU /* least significant 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 { typedef struct {
PyObject_HEAD PyObject_HEAD
int index; int index;
uint32_t state[N]; uint32_t state[N];
} RandomObject; } RandomObject;
static PyTypeObject Random_Type;
#define RandomObject_Check(v) (Py_TYPE(v) == &Random_Type)
#include "clinic/_randommodule.c.h" #include "clinic/_randommodule.c.h"
...@@ -256,6 +264,7 @@ random_seed(RandomObject *self, PyObject *arg) ...@@ -256,6 +264,7 @@ random_seed(RandomObject *self, PyObject *arg)
uint32_t *key = NULL; uint32_t *key = NULL;
size_t bits, keyused; size_t bits, keyused;
int res; int res;
PyObject *args[1];
if (arg == NULL || arg == Py_None) { if (arg == NULL || arg == Py_None) {
if (random_seed_urandom(self) < 0) { if (random_seed_urandom(self) < 0) {
...@@ -272,10 +281,14 @@ random_seed(RandomObject *self, PyObject *arg) ...@@ -272,10 +281,14 @@ random_seed(RandomObject *self, PyObject *arg)
* So: if the arg is a PyLong, use its absolute value. * So: if the arg is a PyLong, use its absolute value.
* Otherwise use its hash value, cast to unsigned. * 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 /* Calling int.__abs__() prevents calling arg.__abs__(), which might
return an invalid value. See issue #31478. */ 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 { else {
Py_hash_t hash = PyObject_Hash(arg); Py_hash_t hash = PyObject_Hash(arg);
...@@ -500,10 +513,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -500,10 +513,12 @@ random_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
RandomObject *self; RandomObject *self;
PyObject *tmp; PyObject *tmp;
if (type == &Random_Type && !_PyArg_NoKeywords("Random", kwds)) if (type == (PyTypeObject*)_randomstate_global->Random_Type &&
!_PyArg_NoKeywords("Random()", kwds)) {
return NULL; return NULL;
}
self = (RandomObject *)type->tp_alloc(type, 0); self = (RandomObject *)PyType_GenericAlloc(type, 0);
if (self == NULL) if (self == NULL)
return NULL; return NULL;
tmp = random_seed(self, args); tmp = random_seed(self, args);
...@@ -527,64 +542,55 @@ static PyMethodDef random_methods[] = { ...@@ -527,64 +542,55 @@ static PyMethodDef random_methods[] = {
PyDoc_STRVAR(random_doc, PyDoc_STRVAR(random_doc,
"Random() -> create a random number generator with its own internal state."); "Random() -> create a random number generator with its own internal state.");
static PyTypeObject Random_Type = { static PyType_Slot Random_Type_slots[] = {
PyVarObject_HEAD_INIT(NULL, 0) {Py_tp_doc, random_doc},
"_random.Random", /*tp_name*/ {Py_tp_methods, random_methods},
sizeof(RandomObject), /*tp_basicsize*/ {Py_tp_new, random_new},
0, /*tp_itemsize*/ {Py_tp_free, PyObject_Free},
/* methods */ {0, 0},
0, /*tp_dealloc*/ };
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/ static PyType_Spec Random_Type_spec = {
0, /*tp_setattr*/ "_random.Random",
0, /*tp_as_async*/ sizeof(RandomObject),
0, /*tp_repr*/ 0,
0, /*tp_as_number*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0, /*tp_as_sequence*/ Random_Type_slots
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*/
}; };
PyDoc_STRVAR(module_doc, PyDoc_STRVAR(module_doc,
"Module implements the Mersenne Twister random number generator."); "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 = { static struct PyModuleDef _randommodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"_random", "_random",
module_doc, module_doc,
-1, sizeof(_randomstate),
NULL,
NULL, NULL,
NULL, NULL,
NULL, _random_traverse,
NULL _random_clear,
_random_free,
}; };
PyMODINIT_FUNC PyMODINIT_FUNC
...@@ -592,12 +598,41 @@ PyInit__random(void) ...@@ -592,12 +598,41 @@ PyInit__random(void)
{ {
PyObject *m; PyObject *m;
if (PyType_Ready(&Random_Type) < 0) PyObject *Random_Type = PyType_FromSpec(&Random_Type_spec);
if (Random_Type == NULL) {
return NULL; return NULL;
}
m = PyModule_Create(&_randommodule); m = PyModule_Create(&_randommodule);
if (m == NULL) if (m == NULL) {
Py_DECREF(Random_Type);
return NULL; 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; return m;
fail:
Py_XDECREF(longtype);
Py_XDECREF(longval);
Py_DECREF(m);
return NULL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment