diff options
author | Dino Viehland <dinoviehland@fb.com> | 2019-09-13 10:12:27 (GMT) |
---|---|---|
committer | T. Wouters <thomas@python.org> | 2019-09-13 10:12:27 (GMT) |
commit | 04f0bbfbedf8d2bb69b012f853de6648b1a9f27f (patch) | |
tree | 2703f0f3a64730d851b9761957dcf995c9615387 /Modules | |
parent | 42671aea2db6cbc54369617da0fd3545048e0a45 (diff) | |
download | cpython-04f0bbfbedf8d2bb69b012f853de6648b1a9f27f.zip cpython-04f0bbfbedf8d2bb69b012f853de6648b1a9f27f.tar.gz cpython-04f0bbfbedf8d2bb69b012f853de6648b1a9f27f.tar.bz2 |
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.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_randommodule.c | 149 |
1 files changed, 92 insertions, 57 deletions
diff --git a/Modules/_randommodule.c b/Modules/_randommodule.c index 4e9ac40..8b0a024 100644 --- a/Modules/_randommodule.c +++ b/Modules/_randommodule.c @@ -80,14 +80,22 @@ #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, - NULL, + sizeof(_randomstate), 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; } |