@@ -496,24 +496,19 @@ pg_base_get_init(PyObject *self, PyObject *_null)
496
496
static int
497
497
pg_IntFromObj (PyObject * obj , int * val )
498
498
{
499
- int tmp_val ;
500
-
501
499
if (PyFloat_Check (obj )) {
502
500
/* Python3.8 complains with deprecation warnings if we pass
503
501
* floats to PyLong_AsLong.
504
502
*/
505
- double dv = PyFloat_AsDouble (obj );
506
- tmp_val = (int )dv ;
503
+ * val = (int )PyFloat_AS_DOUBLE (obj );
507
504
}
508
505
else {
509
- tmp_val = PyLong_AsLong (obj );
510
- }
511
-
512
- if (tmp_val == -1 && PyErr_Occurred ()) {
513
- PyErr_Clear ();
514
- return 0 ;
506
+ * val = PyLong_AsLong (obj );
507
+ if (* val == -1 && PyErr_Occurred ()) {
508
+ PyErr_Clear ();
509
+ return 0 ;
510
+ }
515
511
}
516
- * val = tmp_val ;
517
512
return 1 ;
518
513
}
519
514
@@ -535,30 +530,79 @@ pg_IntFromObjIndex(PyObject *obj, int _index, int *val)
535
530
static int
536
531
pg_TwoIntsFromObj (PyObject * obj , int * val1 , int * val2 )
537
532
{
538
- if (PyTuple_Check (obj ) && PyTuple_Size (obj ) == 1 ) {
533
+ // First, lets check the size. This returns -1 if invalid and may set an
534
+ // error.
535
+ Py_ssize_t obj_size = PySequence_Size (obj );
536
+
537
+ // If the object is a tuple of one element, try that one element.
538
+ if (obj_size == 1 && PyTuple_Check (obj )) {
539
539
return pg_TwoIntsFromObj (PyTuple_GET_ITEM (obj , 0 ), val1 , val2 );
540
540
}
541
- if (!PySequence_Check (obj ) || PySequence_Length (obj ) != 2 ) {
541
+
542
+ // Otherwise lets make sure this is a legit sequence and has two elements.
543
+ // Some objects can passing PySequence_Size but fail PySequence_Check
544
+ // (like sets)
545
+ if (obj_size != 2 || !PySequence_Check (obj )) {
546
+ PyErr_Clear (); // Clear the potential error from PySequence_Size
547
+ return 0 ;
548
+ }
549
+
550
+ // Now we can extract the items, using this macro because we know
551
+ // obj is a PySequence.
552
+ PyObject * item1 = PySequence_ITEM (obj , 0 );
553
+ PyObject * item2 = PySequence_ITEM (obj , 1 );
554
+
555
+ // If either item is NULL lets get out of here
556
+ if (item1 == NULL || item2 == NULL ) {
557
+ Py_XDECREF (item1 );
558
+ Py_XDECREF (item2 );
559
+ PyErr_Clear ();
542
560
return 0 ;
543
561
}
544
- if (!pg_IntFromObjIndex (obj , 0 , val1 ) ||
545
- !pg_IntFromObjIndex (obj , 1 , val2 )) {
562
+
563
+ // Fastest way to extract numbers I tested (in Python 3.13) is to extract
564
+ // Python floats as doubles with the below macro, and get everything else
565
+ // through PyLong_AsLong, using C casting to turn into the final type.
566
+ if (PyFloat_Check (item1 )) {
567
+ * val1 = (int )PyFloat_AS_DOUBLE (item1 );
568
+ }
569
+ else {
570
+ * val1 = PyLong_AsLong (item1 );
571
+ }
572
+
573
+ if (PyFloat_Check (item2 )) {
574
+ * val2 = (int )PyFloat_AS_DOUBLE (item2 );
575
+ }
576
+ else {
577
+ * val2 = PyLong_AsLong (item2 );
578
+ }
579
+
580
+ // This catches the case where either of the PyLong_AsLong's failed
581
+ if ((* val1 == -1 || * val2 == -1 ) && PyErr_Occurred ()) {
582
+ PyErr_Clear ();
583
+ Py_DECREF (item1 );
584
+ Py_DECREF (item2 );
546
585
return 0 ;
547
586
}
587
+
588
+ Py_DECREF (item1 );
589
+ Py_DECREF (item2 );
548
590
return 1 ;
549
591
}
550
592
551
593
static int
552
594
pg_FloatFromObj (PyObject * obj , float * val )
553
595
{
554
- float f = (float )PyFloat_AsDouble (obj );
555
-
556
- if (f == -1 && PyErr_Occurred ()) {
557
- PyErr_Clear ();
558
- return 0 ;
596
+ if (PyFloat_Check (obj )) {
597
+ * val = (float )PyFloat_AS_DOUBLE (obj );
598
+ }
599
+ else {
600
+ * val = (float )PyLong_AsLong (obj );
601
+ if (* val == -1.0f && PyErr_Occurred ()) {
602
+ PyErr_Clear ();
603
+ return 0 ;
604
+ }
559
605
}
560
-
561
- * val = f ;
562
606
return 1 ;
563
607
}
564
608
@@ -580,16 +624,63 @@ pg_FloatFromObjIndex(PyObject *obj, int _index, float *val)
580
624
static int
581
625
pg_TwoFloatsFromObj (PyObject * obj , float * val1 , float * val2 )
582
626
{
583
- if (PyTuple_Check (obj ) && PyTuple_Size (obj ) == 1 ) {
627
+ // First, lets check the size. This returns -1 if invalid and may set an
628
+ // error.
629
+ Py_ssize_t obj_size = PySequence_Size (obj );
630
+
631
+ // If the object is a tuple of one element, try that one element.
632
+ if (obj_size == 1 && PyTuple_Check (obj )) {
584
633
return pg_TwoFloatsFromObj (PyTuple_GET_ITEM (obj , 0 ), val1 , val2 );
585
634
}
586
- if (!PySequence_Check (obj ) || PySequence_Length (obj ) != 2 ) {
635
+
636
+ // Otherwise lets make sure this is a legit sequence and has two elements.
637
+ // Some objects can passing PySequence_Size but fail PySequence_Check
638
+ // (like sets)
639
+ if (obj_size != 2 || !PySequence_Check (obj )) {
640
+ PyErr_Clear (); // Clear the potential error from PySequence_Size
641
+ return 0 ;
642
+ }
643
+
644
+ // Now we can extract the items, using this macro because we know
645
+ // obj is a PySequence.
646
+ PyObject * item1 = PySequence_ITEM (obj , 0 );
647
+ PyObject * item2 = PySequence_ITEM (obj , 1 );
648
+
649
+ // If either item is NULL lets get out of here
650
+ if (item1 == NULL || item2 == NULL ) {
651
+ Py_XDECREF (item1 );
652
+ Py_XDECREF (item2 );
653
+ PyErr_Clear ();
587
654
return 0 ;
588
655
}
589
- if (!pg_FloatFromObjIndex (obj , 0 , val1 ) ||
590
- !pg_FloatFromObjIndex (obj , 1 , val2 )) {
656
+
657
+ // Fastest way to extract numbers I tested (in Python 3.13) is to extract
658
+ // Python floats as doubles with the below macro, and get everything else
659
+ // through PyLong_AsLong, using C casting to turn into the final type.
660
+ if (PyFloat_Check (item1 )) {
661
+ * val1 = (float )PyFloat_AS_DOUBLE (item1 );
662
+ }
663
+ else {
664
+ * val1 = (float )PyLong_AsLong (item1 );
665
+ }
666
+
667
+ if (PyFloat_Check (item2 )) {
668
+ * val2 = (float )PyFloat_AS_DOUBLE (item2 );
669
+ }
670
+ else {
671
+ * val2 = (float )PyLong_AsLong (item2 );
672
+ }
673
+
674
+ // This catches the case where either of the PyLong_AsLong's failed
675
+ if ((* val1 == -1.0f || * val2 == -1.0f ) && PyErr_Occurred ()) {
676
+ PyErr_Clear ();
677
+ Py_DECREF (item1 );
678
+ Py_DECREF (item2 );
591
679
return 0 ;
592
680
}
681
+
682
+ Py_DECREF (item1 );
683
+ Py_DECREF (item2 );
593
684
return 1 ;
594
685
}
595
686
0 commit comments