11#include <Python.h>
22#include <pythread.h>
3+ #include <stdatomic.h>
34#include <stdbool.h>
45#include <stdint.h>
56#include <time.h>
@@ -294,9 +295,81 @@ static struct PyModuleDef sonyflake_module = {
294295 .m_size = -1 ,
295296};
296297
298+ inline uint16_t machine_id_lcg (uint32_t x ) {
299+ return (32309 * x + 13799 ) % 65536 ;
300+ }
301+
302+ inline uint16_t machine_id_lcg_atomic (atomic_uint * x ) {
303+ uint32_t old , new ;
304+ do {
305+ old = atomic_load_explicit (x , memory_order_relaxed );
306+ new = machine_id_lcg (old );
307+ } while (!atomic_compare_exchange_weak_explicit (x , & old , new , memory_order_relaxed , memory_order_relaxed ));
308+ return new ;
309+ }
310+
311+ struct machine_id_lcg_state {
312+ PyObject_HEAD
313+ atomic_uint machine_id ;
314+ };
315+
316+ static PyObject * machine_id_lcg_new (PyTypeObject * type , PyObject * args , PyObject * kwargs ) {
317+ unsigned int seed = 0 ;
318+
319+ if (!PyArg_ParseTuple (args , "I" , & seed )) {
320+ return NULL ;
321+ }
322+
323+ allocfunc tp_alloc = PyType_GetSlot (type , Py_tp_alloc );
324+
325+ assert (tp_alloc != NULL );
326+
327+ struct machine_id_lcg_state * self = (void * ) tp_alloc (type , 0 );
328+
329+ if (!self ) {
330+ return NULL ;
331+ }
332+
333+ atomic_init (& self -> machine_id , machine_id_lcg ((uint32_t ) seed ));
334+
335+ return (PyObject * ) self ;
336+ }
337+
338+ static void machine_id_lcg_dealloc (PyObject * self ) {
339+ PyTypeObject * tp = Py_TYPE (self );
340+ freefunc tp_free = PyType_GetSlot (tp , Py_tp_free );
341+
342+ assert (tp_free != NULL );
343+
344+ tp_free (self );
345+ Py_DECREF (tp );
346+ }
347+
348+ static PyObject * machine_id_lcg_next (struct machine_id_lcg_state * self ) {
349+ return PyLong_FromLong (machine_id_lcg_atomic (& self -> machine_id ));
350+ }
351+
352+ static PyType_Slot machine_id_lcg_slots [] = {
353+ {Py_tp_alloc , PyType_GenericAlloc },
354+ {Py_tp_dealloc , machine_id_lcg_dealloc },
355+ {Py_tp_iter , PyObject_SelfIter },
356+ {Py_tp_iternext , machine_id_lcg_next },
357+ {Py_tp_new , machine_id_lcg_new },
358+ {Py_tp_doc , "LCG with params a=32309, c=13799, m=65536" },
359+ {0 , 0 },
360+ };
361+
362+ static PyType_Spec machine_id_lcg_spec = {
363+ .name = "sonyflake_turbo.MachineIDLCG" ,
364+ .basicsize = sizeof (struct machine_id_lcg_state ),
365+ .flags = Py_TPFLAGS_DEFAULT ,
366+ .slots = machine_id_lcg_slots ,
367+ };
368+
297369PyMODINIT_FUNC
298370PyInit_sonyflake_turbo (void )
299371{
372+ PyObject * sonyflake_cls , * machine_id_lcg_cls ;
300373 PyObject * module = PyModule_Create (& sonyflake_module );
301374
302375 if (!module ) {
@@ -307,17 +380,24 @@ PyInit_sonyflake_turbo(void)
307380 PyUnstable_Module_SetGIL (module , Py_MOD_GIL_NOT_USED );
308381#endif
309382
310- PyObject * sonyflake_cls = PyType_FromSpec (& sonyflake_type_spec );
383+ sonyflake_cls = PyType_FromSpec (& sonyflake_type_spec );
311384
312385 if (!sonyflake_cls ) {
313- Py_DECREF (module );
314- return NULL ;
386+ goto err ;
315387 }
316388
317389 if (PyModule_AddObject (module , "SonyFlake" , sonyflake_cls ) < 0 ) {
318- Py_DECREF (sonyflake_cls );
319- Py_DECREF (module );
320- return NULL ;
390+ goto err_sf ;
391+ }
392+
393+ machine_id_lcg_cls = PyType_FromSpec (& machine_id_lcg_spec );
394+
395+ if (!machine_id_lcg_cls ) {
396+ goto err_lcg ;
397+ }
398+
399+ if (PyModule_AddObject (module , "MachineIDLCG" , machine_id_lcg_cls ) < 0 ) {
400+ goto err_lcg ;
321401 }
322402
323403 PyModule_AddIntMacro (module , SONYFLAKE_EPOCH );
@@ -329,4 +409,12 @@ PyInit_sonyflake_turbo(void)
329409 PyModule_AddIntMacro (module , SONYFLAKE_TIME_OFFSET );
330410
331411 return module ;
412+
413+ err_lcg :
414+ Py_DECREF (machine_id_lcg_cls );
415+ err_sf :
416+ Py_DECREF (sonyflake_cls );
417+ err :
418+ Py_DECREF (module );
419+ return NULL ;
332420}
0 commit comments