@@ -51,7 +51,7 @@ inline void sub_diff(struct timespec *a, const struct timespec *b) {
5151 }
5252}
5353
54- inline useconds_t get_time_to_usleep (const struct timespec * diff ) {
54+ inline uint64_t get_time_to_usleep (const struct timespec * diff ) {
5555 return diff -> tv_sec * 1000000 + diff -> tv_nsec / 1000 ;
5656}
5757
@@ -72,6 +72,11 @@ bool incr_combined_sequence(struct sonyflake_state *self) {
7272 return self -> combined_sequence == 0 ;
7373}
7474
75+ static inline void get_relative_current_time (struct sonyflake_state * self , struct timespec * now ) {
76+ clock_gettime (CLOCK_REALTIME , now );
77+ sub_diff (now , & self -> start_time );
78+ }
79+
7580void sort_machine_ids (uint16_t * machine_ids , size_t machine_ids_len ) {
7681 if (machine_ids_len <= 1 ) {
7782 return ;
@@ -234,15 +239,13 @@ static void sonyflake_dealloc(struct sonyflake_state *self) {
234239
235240static PyObject * sonyflake_next (struct sonyflake_state * self ) {
236241 struct timespec now , future ;
237- useconds_t to_sleep = 0 ;
242+ uint64_t to_sleep = 0 ;
238243 sonyflake_time current ;
239244 uint64_t sonyflake_id ;
240245
241- clock_gettime (CLOCK_REALTIME , & now );
242-
243246 PyThread_acquire_lock (self -> lock , 1 );
244247
245- sub_diff ( & now , & self -> start_time );
248+ get_relative_current_time ( self , & now );
246249
247250 current = to_sonyflake_time (& now );
248251
@@ -271,6 +274,67 @@ static PyObject *sonyflake_next(struct sonyflake_state *self) {
271274 return PyLong_FromUnsignedLongLong (sonyflake_id );
272275}
273276
277+ static PyObject * sonyflake_next_n (struct sonyflake_state * self , Py_ssize_t n ) {
278+ assert (n > 0 );
279+
280+ PyObject * out = PyList_New (n );
281+
282+ if (!out ) {
283+ return NULL ;
284+ }
285+
286+ struct timespec now , future ;
287+ uint64_t to_sleep = 0 ;
288+ sonyflake_time current , diff ;
289+
290+ PyThread_acquire_lock (self -> lock , 1 );
291+
292+ get_relative_current_time (self , & now );
293+
294+ current = to_sonyflake_time (& now );
295+
296+ if (self -> elapsed_time < current ) {
297+ self -> elapsed_time = current ;
298+ self -> combined_sequence = 0 ;
299+ } else if (incr_combined_sequence (self )) {
300+ self -> elapsed_time ++ ;
301+ }
302+
303+ PyList_SetItem (out , 0 , PyLong_FromUnsignedLongLong (compose (self )));
304+
305+ for (Py_ssize_t i = 1 ; i < n ; i ++ ) {
306+ if (incr_combined_sequence (self )) {
307+ self -> elapsed_time ++ ;
308+ }
309+
310+ PyList_SetItem (out , i , PyLong_FromUnsignedLongLong (compose (self )));
311+ }
312+
313+ diff = self -> elapsed_time - current ;
314+
315+ if (diff <= 0 ) {
316+ PyThread_release_lock (self -> lock );
317+ return out ;
318+ } else if (diff > 1 ) {
319+ get_relative_current_time (self , & now );
320+ }
321+
322+ from_sonyflake_time (self -> elapsed_time , & future );
323+ sub_diff (& future , & now );
324+
325+ to_sleep = get_time_to_usleep (& future );
326+
327+ PyThread_release_lock (self -> lock );
328+
329+ if (to_sleep > 0 ) {
330+ Py_BEGIN_ALLOW_THREADS ;
331+ usleep (to_sleep );
332+ Py_END_ALLOW_THREADS ;
333+ }
334+
335+ return out ;
336+ }
337+
274338static PyObject * sonyflake_repr (struct sonyflake_state * self ) {
275339 PyObject * s , * args_list = PyList_New (self -> machine_ids_len + 1 );
276340
@@ -287,15 +351,15 @@ static PyObject *sonyflake_repr(struct sonyflake_state *self) {
287351
288352 PyList_SetItem (args_list , self -> machine_ids_len , s );
289353
290- for (Py_ssize_t i = 0 ; i < self -> machine_ids_len ; i ++ ) {
354+ for (size_t i = 0 ; i < self -> machine_ids_len ; i ++ ) {
291355 s = PyUnicode_FromFormat ("%u" , (unsigned ) self -> machine_ids [i ]);
292356
293357 if (!s ) {
294358 Py_DECREF (args_list );
295359 return NULL ;
296360 }
297361
298- PyList_SetItem (args_list , i , s );
362+ PyList_SetItem (args_list , ( Py_ssize_t ) i , s );
299363 }
300364
301365 s = PyUnicode_FromString (", " );
@@ -321,6 +385,21 @@ static PyObject *sonyflake_repr(struct sonyflake_state *self) {
321385 return s ;
322386}
323387
388+ static PyObject * sonyflake_call (struct sonyflake_state * self , PyObject * args ) {
389+ Py_ssize_t n ;
390+
391+ if (!PyArg_ParseTuple (args , "n" , & n )) {
392+ return NULL ;
393+ }
394+
395+ if (n <= 0 ) {
396+ PyErr_SetString (PyExc_ValueError , "n must be positive" );
397+ return NULL ;
398+ }
399+
400+ return sonyflake_next_n (self , n );
401+ }
402+
324403PyDoc_STRVAR (sonyflake_doc ,
325404"SonyFlake(*machine_id, start_time=None)\n--\n\n"
326405"SonyFlake ID generator implementation that combines multiple ID generators into one to improve throughput.\n"
@@ -338,6 +417,7 @@ static PyType_Slot sonyflake_type_slots[] = {
338417 {Py_tp_iternext , sonyflake_next },
339418 {Py_tp_new , sonyflake_new },
340419 {Py_tp_init , sonyflake_init },
420+ {Py_tp_call , sonyflake_call },
341421 {Py_tp_doc , sonyflake_doc },
342422 {Py_tp_repr , sonyflake_repr },
343423 {0 , 0 },
0 commit comments