@@ -1292,17 +1292,47 @@ RectExport_colliderect(RectObject *self, PyObject *const *args,
1292
1292
return PyBool_FromLong (_pg_do_rects_intersect (& self -> r , argrect ));
1293
1293
}
1294
1294
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
+
1295
1317
static PyObject *
1296
1318
RectExport_collidelist (RectObject * self , PyObject * arg )
1297
1319
{
1298
1320
InnerRect * argrect , * srect = & self -> r , temp ;
1299
1321
int loop ;
1300
1322
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
+
1301
1329
if (!PySequence_Check (arg )) {
1302
1330
return RAISE (PyExc_TypeError ,
1303
1331
"Argument must be a sequence of rectstyle objects." );
1304
1332
}
1305
1333
1334
+ OPTIMIZED_COLLIDERECT_SETUP ;
1335
+
1306
1336
/* If the sequence is a fast sequence, we can use the faster
1307
1337
* PySequence_Fast_ITEMS() function to get the items. */
1308
1338
if (pgSequenceFast_Check (arg )) {
@@ -1313,16 +1343,17 @@ RectExport_collidelist(RectObject *self, PyObject *arg)
1313
1343
PyExc_TypeError ,
1314
1344
"Argument must be a sequence of rectstyle objects." );
1315
1345
}
1316
- if (_pg_do_rects_intersect (srect , argrect )) {
1346
+
1347
+ if (OPTIMIZED_COLLIDERECT (argrect )) {
1317
1348
return PyLong_FromLong (loop );
1318
1349
}
1319
1350
}
1320
1351
}
1321
1352
/* 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. */
1323
1354
else {
1324
1355
for (loop = 0 ; loop < PySequence_Length (arg ); loop ++ ) {
1325
- PyObject * obj = PySequence_GetItem (arg , loop );
1356
+ PyObject * obj = PySequence_ITEM (arg , loop );
1326
1357
1327
1358
if (!obj || !(argrect = RectFromObject (obj , & temp ))) {
1328
1359
Py_XDECREF (obj );
@@ -1333,7 +1364,7 @@ RectExport_collidelist(RectObject *self, PyObject *arg)
1333
1364
1334
1365
Py_DECREF (obj );
1335
1366
1336
- if (_pg_do_rects_intersect ( srect , argrect )) {
1367
+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1337
1368
return PyLong_FromLong (loop );
1338
1369
}
1339
1370
}
@@ -1358,6 +1389,14 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
1358
1389
return NULL ;
1359
1390
}
1360
1391
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
+
1361
1400
/* If the sequence is a fast sequence, we can use the faster
1362
1401
* PySequence_Fast_ITEMS() function to get the items. */
1363
1402
if (pgSequenceFast_Check (arg )) {
@@ -1370,7 +1409,7 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
1370
1409
"Argument must be a sequence of rectstyle objects." );
1371
1410
}
1372
1411
1373
- if (_pg_do_rects_intersect ( srect , argrect )) {
1412
+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1374
1413
PyObject * num = PyLong_FromLong (loop );
1375
1414
if (!num ) {
1376
1415
Py_DECREF (ret );
@@ -1400,7 +1439,7 @@ RectExport_collidelistall(RectObject *self, PyObject *arg)
1400
1439
1401
1440
Py_DECREF (obj );
1402
1441
1403
- if (_pg_do_rects_intersect ( srect , argrect )) {
1442
+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1404
1443
PyObject * num = PyLong_FromLong (loop );
1405
1444
if (!num ) {
1406
1445
Py_DECREF (ret );
@@ -1452,7 +1491,7 @@ static PyObject *
1452
1491
RectExport_collideobjectsall (RectObject * self , PyObject * args ,
1453
1492
PyObject * kwargs )
1454
1493
{
1455
- InnerRect * argrect ;
1494
+ InnerRect * argrect , * srect = & self -> r ;
1456
1495
InnerRect temp ;
1457
1496
Py_ssize_t size ;
1458
1497
int loop ;
@@ -1485,14 +1524,22 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
1485
1524
return NULL ;
1486
1525
}
1487
1526
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
+
1488
1535
size = PySequence_Length (list );
1489
1536
if (size == -1 ) {
1490
1537
Py_DECREF (ret );
1491
1538
return NULL ;
1492
1539
}
1493
1540
1494
1541
for (loop = 0 ; loop < size ; ++ loop ) {
1495
- obj = PySequence_GetItem (list , loop );
1542
+ obj = PySequence_ITEM (list , loop );
1496
1543
1497
1544
if (!obj ) {
1498
1545
Py_DECREF (ret );
@@ -1506,7 +1553,7 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
1506
1553
return NULL ;
1507
1554
}
1508
1555
1509
- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1556
+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1510
1557
if (0 != PyList_Append (ret , obj )) {
1511
1558
Py_DECREF (ret );
1512
1559
Py_DECREF (obj );
@@ -1522,7 +1569,7 @@ RectExport_collideobjectsall(RectObject *self, PyObject *args,
1522
1569
static PyObject *
1523
1570
RectExport_collideobjects (RectObject * self , PyObject * args , PyObject * kwargs )
1524
1571
{
1525
- InnerRect * argrect ;
1572
+ InnerRect * argrect , * srect = & self -> r ;
1526
1573
InnerRect temp ;
1527
1574
Py_ssize_t size ;
1528
1575
int loop ;
@@ -1549,13 +1596,21 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
1549
1596
"Key function must be callable with one argument." );
1550
1597
}
1551
1598
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
+
1552
1607
size = PySequence_Length (list );
1553
1608
if (size == -1 ) {
1554
1609
return NULL ;
1555
1610
}
1556
1611
1557
1612
for (loop = 0 ; loop < size ; ++ loop ) {
1558
- obj = PySequence_GetItem (list , loop );
1613
+ obj = PySequence_ITEM (list , loop );
1559
1614
1560
1615
if (!obj ) {
1561
1616
return NULL ;
@@ -1567,7 +1622,7 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
1567
1622
return NULL ;
1568
1623
}
1569
1624
1570
- if (_pg_do_rects_intersect ( & self -> r , argrect )) {
1625
+ if (OPTIMIZED_COLLIDERECT ( argrect )) {
1571
1626
return obj ;
1572
1627
}
1573
1628
Py_DECREF (obj );
@@ -1579,7 +1634,7 @@ RectExport_collideobjects(RectObject *self, PyObject *args, PyObject *kwargs)
1579
1634
static PyObject *
1580
1635
RectExport_collidedict (RectObject * self , PyObject * args , PyObject * kwargs )
1581
1636
{
1582
- InnerRect * argrect , temp ;
1637
+ InnerRect * argrect , temp , * srect = & self -> r ;
1583
1638
Py_ssize_t loop = 0 ;
1584
1639
Py_ssize_t values = 0 ; /* Defaults to expecting keys as rects. */
1585
1640
PyObject * dict , * key , * val ;
@@ -1596,6 +1651,14 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
1596
1651
return RAISE (PyExc_TypeError , "first argument must be a dict" );
1597
1652
}
1598
1653
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
+
1599
1662
while (PyDict_Next (dict , & loop , & key , & val )) {
1600
1663
if (values ) {
1601
1664
if (!(argrect = RectFromObject (val , & temp ))) {
@@ -1609,8 +1672,8 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
1609
1672
}
1610
1673
}
1611
1674
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 );
1614
1677
break ;
1615
1678
}
1616
1679
}
@@ -1624,7 +1687,7 @@ RectExport_collidedict(RectObject *self, PyObject *args, PyObject *kwargs)
1624
1687
static PyObject *
1625
1688
RectExport_collidedictall (RectObject * self , PyObject * args , PyObject * kwargs )
1626
1689
{
1627
- InnerRect * argrect , temp ;
1690
+ InnerRect * argrect , temp , * srect = & self -> r ;
1628
1691
Py_ssize_t loop = 0 ;
1629
1692
Py_ssize_t values = 0 ; /* Defaults to expecting keys as rects. */
1630
1693
PyObject * dict , * key , * val ;
@@ -1645,6 +1708,14 @@ RectExport_collidedictall(RectObject *self, PyObject *args, PyObject *kwargs)
1645
1708
if (!ret )
1646
1709
return NULL ;
1647
1710
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
+
1648
1719
while (PyDict_Next (dict , & loop , & key , & val )) {
1649
1720
if (values ) {
1650
1721
if (!(argrect = RectFromObject (val , & temp ))) {
@@ -1660,8 +1731,8 @@ RectExport_collidedictall(RectObject *self, PyObject *args, PyObject *kwargs)
1660
1731
}
1661
1732
}
1662
1733
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 );
1665
1736
if (!num ) {
1666
1737
Py_DECREF (ret );
1667
1738
return NULL ;
0 commit comments