@@ -1292,17 +1292,47 @@ RectExport_colliderect(RectObject *self, PyObject *const *args,
12921292 return PyBool_FromLong (_pg_do_rects_intersect (& self -> r , argrect ));
12931293}
12941294
1295+ #ifndef OPTIMIZED_COLLIDERECT_SETUP
1296+ /* This macro is used to optimize the colliderect function. It calculates
1297+ * the left, top, right and bottom values of the calling rect only once
1298+ * and uses them in the OPTIMIZED_COLLIDERECT macro. */
1299+ #define OPTIMIZED_COLLIDERECT_SETUP \
1300+ const PrimitiveType left = MIN(srect->x, srect->x + srect->w); \
1301+ const PrimitiveType top = MIN(srect->y, srect->y + srect->h); \
1302+ const PrimitiveType right = MAX(srect->x, srect->x + srect->w); \
1303+ const PrimitiveType bottom = MAX(srect->y, srect->y + srect->h);
1304+ #endif
1305+
1306+ #ifndef OPTIMIZED_COLLIDERECT
1307+ /* This macro is used to optimize the colliderect function. Makes use of
1308+ * precalculated values to avoid unnecessary calculations. It also checks
1309+ * whether the other rect has 0 width or height, in which case we don't
1310+ * collide. */
1311+ #define OPTIMIZED_COLLIDERECT (r ) \
1312+ (r->w && r->h && left < MAX(r->x, r->x + r->w) && \
1313+ top < MAX(r->y, r->y + r->h) && right > MIN(r->x, r->x + r->w) && \
1314+ bottom > MIN(r->y, r->y + r->h))
1315+ #endif
1316+
12951317static PyObject *
12961318RectExport_collidelist (RectObject * self , PyObject * arg )
12971319{
12981320 InnerRect * argrect , * srect = & self -> r , temp ;
12991321 int loop ;
13001322
1323+ /* If the calling rect has 0 width or height, it cannot collide with
1324+ * anything, hence return -1 directly. */
1325+ if (srect -> w == 0 || srect -> h == 0 ) {
1326+ return PyLong_FromLong (-1 );
1327+ }
1328+
13011329 if (!PySequence_Check (arg )) {
13021330 return RAISE (PyExc_TypeError ,
13031331 "Argument must be a sequence of rectstyle objects." );
13041332 }
13051333
1334+ OPTIMIZED_COLLIDERECT_SETUP ;
1335+
13061336 /* If the sequence is a fast sequence, we can use the faster
13071337 * PySequence_Fast_ITEMS() function to get the items. */
13081338 if (pgSequenceFast_Check (arg )) {
@@ -1313,16 +1343,17 @@ RectExport_collidelist(RectObject *self, PyObject *arg)
13131343 PyExc_TypeError ,
13141344 "Argument must be a sequence of rectstyle objects." );
13151345 }
1316- if (_pg_do_rects_intersect (srect , argrect )) {
1346+
1347+ if (OPTIMIZED_COLLIDERECT (argrect )) {
13171348 return PyLong_FromLong (loop );
13181349 }
13191350 }
13201351 }
13211352 /* If the sequence is not a fast sequence, we have to use the slower
1322- * PySequence_GetItem () function to get the items. */
1353+ * PySequence_ITEM () function to get the items. */
13231354 else {
13241355 for (loop = 0 ; loop < PySequence_Length (arg ); loop ++ ) {
1325- PyObject * obj = PySequence_GetItem (arg , loop );
1356+ PyObject * obj = PySequence_ITEM (arg , loop );
13261357
13271358 if (!obj || !(argrect = RectFromObject (obj , & temp ))) {
13281359 Py_XDECREF (obj );
@@ -1333,7 +1364,7 @@ RectExport_collidelist(RectObject *self, PyObject *arg)
13331364
13341365 Py_DECREF (obj );
13351366
1336- if (_pg_do_rects_intersect ( srect , argrect )) {
1367+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
13371368 return PyLong_FromLong (loop );
13381369 }
13391370 }
@@ -1358,6 +1389,14 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
13581389 return NULL ;
13591390 }
13601391
1392+ /* If the calling rect has 0 width or height, it cannot collide with
1393+ * anything, hence return an empty list directly. */
1394+ if (srect -> w == 0 || srect -> h == 0 ) {
1395+ return ret ;
1396+ }
1397+
1398+ OPTIMIZED_COLLIDERECT_SETUP ;
1399+
13611400 /* If the sequence is a fast sequence, we can use the faster
13621401 * PySequence_Fast_ITEMS() function to get the items. */
13631402 if (pgSequenceFast_Check (arg )) {
@@ -1370,7 +1409,7 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
13701409 "Argument must be a sequence of rectstyle objects." );
13711410 }
13721411
1373- if (_pg_do_rects_intersect ( srect , argrect )) {
1412+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
13741413 PyObject * num = PyLong_FromLong (loop );
13751414 if (!num ) {
13761415 Py_DECREF (ret );
@@ -1400,7 +1439,7 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
14001439
14011440 Py_DECREF (obj );
14021441
1403- if (_pg_do_rects_intersect ( srect , argrect )) {
1442+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
14041443 PyObject * num = PyLong_FromLong (loop );
14051444 if (!num ) {
14061445 Py_DECREF (ret );
@@ -1452,7 +1491,7 @@ static PyObject *
14521491RectExport_collideobjectsall (RectObject * self , PyObject * args ,
14531492 PyObject * kwargs )
14541493{
1455- InnerRect * argrect ;
1494+ InnerRect * argrect , * srect = & self -> r ;
14561495 InnerRect temp ;
14571496 Py_ssize_t size ;
14581497 int loop ;
@@ -1485,14 +1524,22 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
14851524 return NULL ;
14861525 }
14871526
1527+ /* If the calling rect has 0 width or height, it cannot collide with
1528+ * anything, hence return an empty list directly. */
1529+ if (srect -> w == 0 || srect -> h == 0 ) {
1530+ return ret ;
1531+ }
1532+
1533+ OPTIMIZED_COLLIDERECT_SETUP ;
1534+
14881535 size = PySequence_Length (list );
14891536 if (size == -1 ) {
14901537 Py_DECREF (ret );
14911538 return NULL ;
14921539 }
14931540
14941541 for (loop = 0 ; loop < size ; ++ loop ) {
1495- obj = PySequence_GetItem (list , loop );
1542+ obj = PySequence_ITEM (list , loop );
14961543
14971544 if (!obj ) {
14981545 Py_DECREF (ret );
@@ -1506,7 +1553,7 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
15061553 return NULL ;
15071554 }
15081555
1509- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1556+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
15101557 if (0 != PyList_Append (ret , obj )) {
15111558 Py_DECREF (ret );
15121559 Py_DECREF (obj );
@@ -1522,7 +1569,7 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
15221569static PyObject *
15231570RectExport_collideobjects (RectObject * self , PyObject * args , PyObject * kwargs )
15241571{
1525- InnerRect * argrect ;
1572+ InnerRect * argrect , * srect = & self -> r ;
15261573 InnerRect temp ;
15271574 Py_ssize_t size ;
15281575 int loop ;
@@ -1549,13 +1596,21 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
15491596 "Key function must be callable with one argument." );
15501597 }
15511598
1599+ /* If the calling rect has 0 width or height, it cannot collide with
1600+ * anything, hence return None directly. */
1601+ if (srect -> w == 0 || srect -> h == 0 ) {
1602+ Py_RETURN_NONE ;
1603+ }
1604+
1605+ OPTIMIZED_COLLIDERECT_SETUP ;
1606+
15521607 size = PySequence_Length (list );
15531608 if (size == -1 ) {
15541609 return NULL ;
15551610 }
15561611
15571612 for (loop = 0 ; loop < size ; ++ loop ) {
1558- obj = PySequence_GetItem (list , loop );
1613+ obj = PySequence_ITEM (list , loop );
15591614
15601615 if (!obj ) {
15611616 return NULL ;
@@ -1567,7 +1622,7 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
15671622 return NULL ;
15681623 }
15691624
1570- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1625+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
15711626 return obj ;
15721627 }
15731628 Py_DECREF (obj );
@@ -1579,7 +1634,7 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
15791634static PyObject *
15801635RectExport_collidedict (RectObject * self , PyObject * args , PyObject * kwargs )
15811636{
1582- InnerRect * argrect , temp ;
1637+ InnerRect * argrect , temp , * srect = & self -> r ;
15831638 Py_ssize_t loop = 0 ;
15841639 Py_ssize_t values = 0 ; /* Defaults to expecting keys as rects. */
15851640 PyObject * dict , * key , * val ;
@@ -1596,6 +1651,14 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
15961651 return RAISE (PyExc_TypeError , "first argument must be a dict" );
15971652 }
15981653
1654+ /* If the calling rect has 0 width or height, it cannot collide with
1655+ * anything, hence return None directly. */
1656+ if (srect -> w == 0 || srect -> h == 0 ) {
1657+ Py_RETURN_NONE ;
1658+ }
1659+
1660+ OPTIMIZED_COLLIDERECT_SETUP ;
1661+
15991662 while (PyDict_Next (dict , & loop , & key , & val )) {
16001663 if (values ) {
16011664 if (!(argrect = RectFromObject (val , & temp ))) {
@@ -1609,8 +1672,8 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
16091672 }
16101673 }
16111674
1612- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1613- ret = Py_BuildValue ( "(OO)" , key , val );
1675+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1676+ ret = PyTuple_Pack ( 2 , key , val );
16141677 break ;
16151678 }
16161679 }
@@ -1624,7 +1687,7 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
16241687static PyObject *
16251688RectExport_collidedictall (RectObject * self , PyObject * args , PyObject * kwargs )
16261689{
1627- InnerRect * argrect , temp ;
1690+ InnerRect * argrect , temp , * srect = & self -> r ;
16281691 Py_ssize_t loop = 0 ;
16291692 Py_ssize_t values = 0 ; /* Defaults to expecting keys as rects. */
16301693 PyObject * dict , * key , * val ;
@@ -1645,6 +1708,14 @@ RectExport_collidedictall(RectObject *self, PyObject *args, PyObject *kwargs)
16451708 if (!ret )
16461709 return NULL ;
16471710
1711+ /* If the calling rect has 0 width or height, it cannot collide with
1712+ * anything, hence return an empty list directly. */
1713+ if (srect -> w == 0 || srect -> h == 0 ) {
1714+ return ret ;
1715+ }
1716+
1717+ OPTIMIZED_COLLIDERECT_SETUP ;
1718+
16481719 while (PyDict_Next (dict , & loop , & key , & val )) {
16491720 if (values ) {
16501721 if (!(argrect = RectFromObject (val , & temp ))) {
@@ -1660,8 +1731,8 @@ RectExport_collidedictall(RectObject *self, PyObject *args, PyObject *kwargs)
16601731 }
16611732 }
16621733
1663- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1664- PyObject * num = Py_BuildValue ( "(OO)" , key , val );
1734+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1735+ PyObject * num = PyTuple_Pack ( 2 , key , val );
16651736 if (!num ) {
16661737 Py_DECREF (ret );
16671738 return NULL ;
0 commit comments