@@ -85,11 +85,11 @@ encoder_dealloc(PyObject *self);
85
85
static int
86
86
encoder_clear (PyEncoderObject * self );
87
87
static int
88
- encoder_listencode_list (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * seq , PyObject * newline_indent );
88
+ encoder_listencode_list (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * seq , Py_ssize_t indent_level , PyObject * indent_cache );
89
89
static int
90
- encoder_listencode_obj (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * obj , PyObject * newline_indent );
90
+ encoder_listencode_obj (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * obj , Py_ssize_t indent_level , PyObject * indent_cache );
91
91
static int
92
- encoder_listencode_dict (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * dct , PyObject * newline_indent );
92
+ encoder_listencode_dict (PyEncoderObject * s , _PyUnicodeWriter * writer , PyObject * dct , Py_ssize_t indent_level , PyObject * indent_cache );
93
93
static PyObject *
94
94
_encoded_const (PyObject * obj );
95
95
static void
@@ -1252,14 +1252,81 @@ encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
1252
1252
}
1253
1253
1254
1254
static PyObject *
1255
- _create_newline_indent ( PyObject * indent , Py_ssize_t indent_level )
1255
+ _create_indent_cache ( PyEncoderObject * s , Py_ssize_t indent_level )
1256
1256
{
1257
1257
PyObject * newline_indent = PyUnicode_FromOrdinal ('\n' );
1258
1258
if (newline_indent != NULL && indent_level ) {
1259
1259
PyUnicode_AppendAndDel (& newline_indent ,
1260
- PySequence_Repeat (indent , indent_level ));
1260
+ PySequence_Repeat (s -> indent , indent_level ));
1261
1261
}
1262
- return newline_indent ;
1262
+ if (newline_indent == NULL ) {
1263
+ return NULL ;
1264
+ }
1265
+ PyObject * indent_cache = PyList_New (2 );
1266
+ if (indent_cache == NULL ) {
1267
+ Py_XDECREF (newline_indent );
1268
+ return NULL ;
1269
+ }
1270
+ PyList_SET_ITEM (indent_cache , 0 , newline_indent );
1271
+ PyList_SET_ITEM (indent_cache , 1 , Py_NewRef (Py_None )); // not used
1272
+ return indent_cache ;
1273
+ }
1274
+
1275
+ static int
1276
+ update_newline_indent (PyEncoderObject * s ,
1277
+ Py_ssize_t indent_level , PyObject * indent_cache )
1278
+ {
1279
+ assert (indent_level * 2 == PyList_GET_SIZE (indent_cache ));
1280
+ assert (indent_level > 0 );
1281
+ PyObject * newline_indent = PyList_GET_ITEM (indent_cache , (indent_level - 1 )* 2 );
1282
+ newline_indent = PyUnicode_Concat (newline_indent , s -> indent );
1283
+ if (newline_indent == NULL ) {
1284
+ return -1 ;
1285
+ }
1286
+ if (PyList_Append (indent_cache , newline_indent ) < 0 ) {
1287
+ Py_DECREF (newline_indent );
1288
+ return -1 ;
1289
+ }
1290
+ PyObject * separator_indent = PyUnicode_Concat (s -> item_separator , newline_indent );
1291
+ Py_DECREF (newline_indent );
1292
+ if (PyList_Append (indent_cache , separator_indent ) < 0 ) {
1293
+ Py_DECREF (separator_indent );
1294
+ return -1 ;
1295
+ }
1296
+ Py_DECREF (separator_indent );
1297
+ return 0 ;
1298
+ }
1299
+
1300
+ static PyObject *
1301
+ do_indent (PyEncoderObject * s , _PyUnicodeWriter * writer ,
1302
+ Py_ssize_t indent_level , PyObject * indent_cache )
1303
+ {
1304
+ assert (indent_level > 0 );
1305
+ assert (s -> indent != Py_None );
1306
+ PyObject * newline_indent ;
1307
+ if (indent_level * 2 == PyList_GET_SIZE (indent_cache )) {
1308
+ if (update_newline_indent (s , indent_level , indent_cache ) < 0 ) {
1309
+ return NULL ;
1310
+ }
1311
+ }
1312
+ assert (indent_level * 2 <= PyList_GET_SIZE (indent_cache ) - 2 );
1313
+
1314
+ newline_indent = PyList_GET_ITEM (indent_cache , indent_level * 2 );
1315
+ if (_PyUnicodeWriter_WriteStr (writer , newline_indent ) < 0 ) {
1316
+ return NULL ;
1317
+ }
1318
+ return PyList_GET_ITEM (indent_cache , indent_level * 2 + 1 );
1319
+ }
1320
+
1321
+ static int
1322
+ do_dedent (PyEncoderObject * s , _PyUnicodeWriter * writer ,
1323
+ Py_ssize_t indent_level , PyObject * indent_cache )
1324
+ {
1325
+ assert (indent_level >= 0 );
1326
+ assert (indent_level * 2 <= PyList_GET_SIZE (indent_cache ) - 4 );
1327
+ assert (s -> indent != Py_None );
1328
+ PyObject * newline_indent = PyList_GET_ITEM (indent_cache , indent_level * 2 );
1329
+ return _PyUnicodeWriter_WriteStr (writer , newline_indent );
1263
1330
}
1264
1331
1265
1332
static PyObject *
@@ -1278,20 +1345,20 @@ encoder_call(PyEncoderObject *self, PyObject *args, PyObject *kwds)
1278
1345
_PyUnicodeWriter_Init (& writer );
1279
1346
writer .overallocate = 1 ;
1280
1347
1281
- PyObject * newline_indent = NULL ;
1348
+ PyObject * indent_cache = NULL ;
1282
1349
if (self -> indent != Py_None ) {
1283
- newline_indent = _create_newline_indent (self -> indent , indent_level );
1284
- if (newline_indent == NULL ) {
1350
+ indent_cache = _create_indent_cache (self , indent_level );
1351
+ if (indent_cache == NULL ) {
1285
1352
_PyUnicodeWriter_Dealloc (& writer );
1286
1353
return NULL ;
1287
1354
}
1288
1355
}
1289
- if (encoder_listencode_obj (self , & writer , obj , newline_indent )) {
1356
+ if (encoder_listencode_obj (self , & writer , obj , 0 , indent_cache )) {
1290
1357
_PyUnicodeWriter_Dealloc (& writer );
1291
- Py_XDECREF (newline_indent );
1358
+ Py_XDECREF (indent_cache );
1292
1359
return NULL ;
1293
1360
}
1294
- Py_XDECREF (newline_indent );
1361
+ Py_XDECREF (indent_cache );
1295
1362
1296
1363
result = PyTuple_New (1 );
1297
1364
if (result == NULL ||
@@ -1379,7 +1446,8 @@ _steal_accumulate(_PyUnicodeWriter *writer, PyObject *stolen)
1379
1446
1380
1447
static int
1381
1448
encoder_listencode_obj (PyEncoderObject * s , _PyUnicodeWriter * writer ,
1382
- PyObject * obj , PyObject * newline_indent )
1449
+ PyObject * obj ,
1450
+ Py_ssize_t indent_level , PyObject * indent_cache )
1383
1451
{
1384
1452
/* Encode Python object obj to a JSON term */
1385
1453
PyObject * newobj ;
@@ -1415,14 +1483,14 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer,
1415
1483
else if (PyList_Check (obj ) || PyTuple_Check (obj )) {
1416
1484
if (_Py_EnterRecursiveCall (" while encoding a JSON object" ))
1417
1485
return -1 ;
1418
- rv = encoder_listencode_list (s , writer , obj , newline_indent );
1486
+ rv = encoder_listencode_list (s , writer , obj , indent_level , indent_cache );
1419
1487
_Py_LeaveRecursiveCall ();
1420
1488
return rv ;
1421
1489
}
1422
1490
else if (PyDict_Check (obj )) {
1423
1491
if (_Py_EnterRecursiveCall (" while encoding a JSON object" ))
1424
1492
return -1 ;
1425
- rv = encoder_listencode_dict (s , writer , obj , newline_indent );
1493
+ rv = encoder_listencode_dict (s , writer , obj , indent_level , indent_cache );
1426
1494
_Py_LeaveRecursiveCall ();
1427
1495
return rv ;
1428
1496
}
@@ -1456,7 +1524,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer,
1456
1524
Py_XDECREF (ident );
1457
1525
return -1 ;
1458
1526
}
1459
- rv = encoder_listencode_obj (s , writer , newobj , newline_indent );
1527
+ rv = encoder_listencode_obj (s , writer , newobj , indent_level , indent_cache );
1460
1528
_Py_LeaveRecursiveCall ();
1461
1529
1462
1530
Py_DECREF (newobj );
@@ -1478,7 +1546,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyUnicodeWriter *writer,
1478
1546
static int
1479
1547
encoder_encode_key_value (PyEncoderObject * s , _PyUnicodeWriter * writer , bool * first ,
1480
1548
PyObject * key , PyObject * value ,
1481
- PyObject * newline_indent ,
1549
+ Py_ssize_t indent_level , PyObject * indent_cache ,
1482
1550
PyObject * item_separator )
1483
1551
{
1484
1552
PyObject * keystr = NULL ;
@@ -1534,23 +1602,22 @@ encoder_encode_key_value(PyEncoderObject *s, _PyUnicodeWriter *writer, bool *fir
1534
1602
if (_PyUnicodeWriter_WriteStr (writer , s -> key_separator ) < 0 ) {
1535
1603
return -1 ;
1536
1604
}
1537
- if (encoder_listencode_obj (s , writer , value , newline_indent ) < 0 ) {
1605
+ if (encoder_listencode_obj (s , writer , value , indent_level , indent_cache ) < 0 ) {
1538
1606
return -1 ;
1539
1607
}
1540
1608
return 0 ;
1541
1609
}
1542
1610
1543
1611
static int
1544
1612
encoder_listencode_dict (PyEncoderObject * s , _PyUnicodeWriter * writer ,
1545
- PyObject * dct , PyObject * newline_indent )
1613
+ PyObject * dct ,
1614
+ Py_ssize_t indent_level , PyObject * indent_cache )
1546
1615
{
1547
1616
/* Encode Python dict dct a JSON term */
1548
1617
PyObject * ident = NULL ;
1549
1618
PyObject * items = NULL ;
1550
1619
PyObject * key , * value ;
1551
1620
bool first = true;
1552
- PyObject * new_newline_indent = NULL ;
1553
- PyObject * separator_indent = NULL ;
1554
1621
1555
1622
if (PyDict_GET_SIZE (dct ) == 0 ) /* Fast path */
1556
1623
return _PyUnicodeWriter_WriteASCIIString (writer , "{}" , 2 );
@@ -1574,19 +1641,11 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer,
1574
1641
if (_PyUnicodeWriter_WriteChar (writer , '{' ))
1575
1642
goto bail ;
1576
1643
1577
- PyObject * current_item_separator = s -> item_separator ; // borrowed reference
1644
+ PyObject * separator = s -> item_separator ; // borrowed reference
1578
1645
if (s -> indent != Py_None ) {
1579
- new_newline_indent = PyUnicode_Concat (newline_indent , s -> indent );
1580
- if (new_newline_indent == NULL ) {
1581
- goto bail ;
1582
- }
1583
- separator_indent = PyUnicode_Concat (current_item_separator , new_newline_indent );
1584
- if (separator_indent == NULL ) {
1585
- goto bail ;
1586
- }
1587
- // update item separator with a borrowed reference
1588
- current_item_separator = separator_indent ;
1589
- if (_PyUnicodeWriter_WriteStr (writer , new_newline_indent ) < 0 ) {
1646
+ indent_level ++ ;
1647
+ separator = do_indent (s , writer , indent_level , indent_cache );
1648
+ if (separator == NULL ) {
1590
1649
goto bail ;
1591
1650
}
1592
1651
}
@@ -1607,8 +1666,8 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer,
1607
1666
key = PyTuple_GET_ITEM (item , 0 );
1608
1667
value = PyTuple_GET_ITEM (item , 1 );
1609
1668
if (encoder_encode_key_value (s , writer , & first , key , value ,
1610
- new_newline_indent ,
1611
- current_item_separator ) < 0 )
1669
+ indent_level , indent_cache ,
1670
+ separator ) < 0 )
1612
1671
goto bail ;
1613
1672
}
1614
1673
Py_CLEAR (items );
@@ -1617,8 +1676,8 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer,
1617
1676
Py_ssize_t pos = 0 ;
1618
1677
while (PyDict_Next (dct , & pos , & key , & value )) {
1619
1678
if (encoder_encode_key_value (s , writer , & first , key , value ,
1620
- new_newline_indent ,
1621
- current_item_separator ) < 0 )
1679
+ indent_level , indent_cache ,
1680
+ separator ) < 0 )
1622
1681
goto bail ;
1623
1682
}
1624
1683
}
@@ -1629,12 +1688,8 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer,
1629
1688
Py_CLEAR (ident );
1630
1689
}
1631
1690
if (s -> indent != Py_None ) {
1632
- Py_CLEAR (new_newline_indent );
1633
- Py_CLEAR (separator_indent );
1634
-
1635
- if (_PyUnicodeWriter_WriteStr (writer , newline_indent ) < 0 ) {
1636
- goto bail ;
1637
- }
1691
+ indent_level -- ;
1692
+ do_dedent (s , writer , indent_level , indent_cache );
1638
1693
}
1639
1694
1640
1695
if (_PyUnicodeWriter_WriteChar (writer , '}' ))
@@ -1644,20 +1699,17 @@ encoder_listencode_dict(PyEncoderObject *s, _PyUnicodeWriter *writer,
1644
1699
bail :
1645
1700
Py_XDECREF (items );
1646
1701
Py_XDECREF (ident );
1647
- Py_XDECREF (separator_indent );
1648
- Py_XDECREF (new_newline_indent );
1649
1702
return -1 ;
1650
1703
}
1651
1704
1652
1705
static int
1653
1706
encoder_listencode_list (PyEncoderObject * s , _PyUnicodeWriter * writer ,
1654
- PyObject * seq , PyObject * newline_indent )
1707
+ PyObject * seq ,
1708
+ Py_ssize_t indent_level , PyObject * indent_cache )
1655
1709
{
1656
1710
PyObject * ident = NULL ;
1657
1711
PyObject * s_fast = NULL ;
1658
1712
Py_ssize_t i ;
1659
- PyObject * new_newline_indent = NULL ;
1660
- PyObject * separator_indent = NULL ;
1661
1713
1662
1714
ident = NULL ;
1663
1715
s_fast = PySequence_Fast (seq , "_iterencode_list needs a sequence" );
@@ -1689,28 +1741,19 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer,
1689
1741
1690
1742
PyObject * separator = s -> item_separator ; // borrowed reference
1691
1743
if (s -> indent != Py_None ) {
1692
- new_newline_indent = PyUnicode_Concat (newline_indent , s -> indent );
1693
- if (new_newline_indent == NULL ) {
1694
- goto bail ;
1695
- }
1696
-
1697
- if (_PyUnicodeWriter_WriteStr (writer , new_newline_indent ) < 0 ) {
1744
+ indent_level ++ ;
1745
+ separator = do_indent (s , writer , indent_level , indent_cache );
1746
+ if (separator == NULL ) {
1698
1747
goto bail ;
1699
1748
}
1700
-
1701
- separator_indent = PyUnicode_Concat (separator , new_newline_indent );
1702
- if (separator_indent == NULL ) {
1703
- goto bail ;
1704
- }
1705
- separator = separator_indent ; // assign separator with borrowed reference
1706
1749
}
1707
1750
for (i = 0 ; i < PySequence_Fast_GET_SIZE (s_fast ); i ++ ) {
1708
1751
PyObject * obj = PySequence_Fast_GET_ITEM (s_fast , i );
1709
1752
if (i ) {
1710
1753
if (_PyUnicodeWriter_WriteStr (writer , separator ) < 0 )
1711
1754
goto bail ;
1712
1755
}
1713
- if (encoder_listencode_obj (s , writer , obj , new_newline_indent ))
1756
+ if (encoder_listencode_obj (s , writer , obj , indent_level , indent_cache ))
1714
1757
goto bail ;
1715
1758
}
1716
1759
if (ident != NULL ) {
@@ -1720,11 +1763,8 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer,
1720
1763
}
1721
1764
1722
1765
if (s -> indent != Py_None ) {
1723
- Py_CLEAR (new_newline_indent );
1724
- Py_CLEAR (separator_indent );
1725
- if (_PyUnicodeWriter_WriteStr (writer , newline_indent ) < 0 ) {
1726
- goto bail ;
1727
- }
1766
+ indent_level -- ;
1767
+ do_dedent (s , writer , indent_level , indent_cache );
1728
1768
}
1729
1769
1730
1770
if (_PyUnicodeWriter_WriteChar (writer , ']' ))
@@ -1735,8 +1775,6 @@ encoder_listencode_list(PyEncoderObject *s, _PyUnicodeWriter *writer,
1735
1775
bail :
1736
1776
Py_XDECREF (ident );
1737
1777
Py_DECREF (s_fast );
1738
- Py_XDECREF (separator_indent );
1739
- Py_XDECREF (new_newline_indent );
1740
1778
return -1 ;
1741
1779
}
1742
1780
0 commit comments