Mercurial > emacs
comparison src/print.c @ 112012:75a194479697
* src/print.c (print, print_preprocess, print_object): Use a hash table
rather than a linear table for Vprint_number_table.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Wed, 22 Dec 2010 16:25:46 -0500 |
parents | 7153f8068e69 |
children | f11676feb984 |
comparison
equal
deleted
inserted
replaced
112011:0258e50dbf90 | 112012:75a194479697 |
---|---|
143 /* Non-nil means keep continuous number for #n= and #n# syntax | 143 /* Non-nil means keep continuous number for #n= and #n# syntax |
144 between several print functions. */ | 144 between several print functions. */ |
145 | 145 |
146 Lisp_Object Vprint_continuous_numbering; | 146 Lisp_Object Vprint_continuous_numbering; |
147 | 147 |
148 /* Vprint_number_table is a vector like [OBJ1 STAT1 OBJ2 STAT2 ...], | 148 /* Vprint_number_table is a table, that keeps objects that are going to |
149 where OBJn are objects going to be printed, and STATn are their status, | 149 be printed, to allow use of #n= and #n# to express sharing. |
150 which may be different meanings during process. See the comments of | 150 For any given object, the table can give the following values: |
151 the functions print and print_preprocess for details. | 151 t the object will be printed only once. |
152 print_number_index keeps the last position the next object should be added, | 152 -N the object will be printed several times and will take number N. |
153 twice of which is the actual vector position in Vprint_number_table. */ | 153 N the object has been printed so we can refer to it as #N#. |
154 print_number_index holds the largest N already used. | |
155 N has to be striclty larger than 0 since we need to distinguish -N. */ | |
154 int print_number_index; | 156 int print_number_index; |
155 Lisp_Object Vprint_number_table; | 157 Lisp_Object Vprint_number_table; |
156 | 158 |
157 /* PRINT_NUMBER_OBJECT returns the I'th object in Vprint_number_table TABLE. | 159 /* PRINT_NUMBER_OBJECT returns the I'th object in Vprint_number_table TABLE. |
158 PRINT_NUMBER_STATUS returns the status of the I'th object in TABLE. | 160 PRINT_NUMBER_STATUS returns the status of the I'th object in TABLE. |
1224 } | 1226 } |
1225 | 1227 |
1226 /* Construct Vprint_number_table for print-gensym and print-circle. */ | 1228 /* Construct Vprint_number_table for print-gensym and print-circle. */ |
1227 if (!NILP (Vprint_gensym) || !NILP (Vprint_circle)) | 1229 if (!NILP (Vprint_gensym) || !NILP (Vprint_circle)) |
1228 { | 1230 { |
1229 int i, start, index; | |
1230 start = index = print_number_index; | |
1231 /* Construct Vprint_number_table. | 1231 /* Construct Vprint_number_table. |
1232 This increments print_number_index for the objects added. */ | 1232 This increments print_number_index for the objects added. */ |
1233 print_depth = 0; | 1233 print_depth = 0; |
1234 print_preprocess (obj); | 1234 print_preprocess (obj); |
1235 | 1235 |
1236 /* Remove unnecessary objects, which appear only once in OBJ; | 1236 if (HASH_TABLE_P (Vprint_number_table)) |
1237 that is, whose status is Qnil. Compactify the necessary objects. */ | 1237 { /* Remove unnecessary objects, which appear only once in OBJ; |
1238 for (i = start; i < print_number_index; i++) | 1238 that is, whose status is Qt. |
1239 if (!NILP (PRINT_NUMBER_STATUS (Vprint_number_table, i))) | 1239 Maybe a better way to do that is to copy elements to |
1240 { | 1240 a new hash table. */ |
1241 PRINT_NUMBER_OBJECT (Vprint_number_table, index) | 1241 struct Lisp_Hash_Table *h = XHASH_TABLE (Vprint_number_table); |
1242 = PRINT_NUMBER_OBJECT (Vprint_number_table, i); | 1242 int i; |
1243 index++; | 1243 |
1244 } | 1244 for (i = 0; i < HASH_TABLE_SIZE (h); ++i) |
1245 | 1245 if (!NILP (HASH_HASH (h, i)) |
1246 /* Clear out objects outside the active part of the table. */ | 1246 && EQ (HASH_VALUE (h, i), Qt)) |
1247 for (i = index; i < print_number_index; i++) | 1247 Fremhash (HASH_KEY (h, i), Vprint_number_table); |
1248 PRINT_NUMBER_OBJECT (Vprint_number_table, i) = Qnil; | 1248 } |
1249 | |
1250 /* Reset the status field for the next print step. Now this | |
1251 field means whether the object has already been printed. */ | |
1252 for (i = start; i < print_number_index; i++) | |
1253 PRINT_NUMBER_STATUS (Vprint_number_table, i) = Qnil; | |
1254 | |
1255 print_number_index = index; | |
1256 } | 1249 } |
1257 | 1250 |
1258 print_depth = 0; | 1251 print_depth = 0; |
1259 print_object (obj, printcharfun, escapeflag); | 1252 print_object (obj, printcharfun, escapeflag); |
1260 } | 1253 } |
1298 || HASH_TABLE_P (obj) | 1291 || HASH_TABLE_P (obj) |
1299 || (! NILP (Vprint_gensym) | 1292 || (! NILP (Vprint_gensym) |
1300 && SYMBOLP (obj) | 1293 && SYMBOLP (obj) |
1301 && !SYMBOL_INTERNED_P (obj))) | 1294 && !SYMBOL_INTERNED_P (obj))) |
1302 { | 1295 { |
1296 if (!HASH_TABLE_P (Vprint_number_table)) | |
1297 { | |
1298 Lisp_Object args[2]; | |
1299 args[0] = QCtest; | |
1300 args[1] = Qeq; | |
1301 Vprint_number_table = Fmake_hash_table (2, args); | |
1302 } | |
1303 | |
1303 /* In case print-circle is nil and print-gensym is t, | 1304 /* In case print-circle is nil and print-gensym is t, |
1304 add OBJ to Vprint_number_table only when OBJ is a symbol. */ | 1305 add OBJ to Vprint_number_table only when OBJ is a symbol. */ |
1305 if (! NILP (Vprint_circle) || SYMBOLP (obj)) | 1306 if (! NILP (Vprint_circle) || SYMBOLP (obj)) |
1306 { | 1307 { |
1307 for (i = 0; i < print_number_index; i++) | 1308 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil); |
1308 if (EQ (PRINT_NUMBER_OBJECT (Vprint_number_table, i), obj)) | 1309 if (!NILP (num) |
1309 { | 1310 /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym, |
1310 /* OBJ appears more than once. Let's remember that. */ | 1311 always print the gensym with a number. This is a special for |
1311 PRINT_NUMBER_STATUS (Vprint_number_table, i) = Qt; | 1312 the lisp function byte-compile-output-docform. */ |
1312 print_depth--; | 1313 || (!NILP (Vprint_continuous_numbering) |
1313 return; | 1314 && SYMBOLP (obj) |
1314 } | 1315 && !SYMBOL_INTERNED_P (obj))) |
1315 | 1316 { /* OBJ appears more than once. Let's remember that. */ |
1316 /* OBJ is not yet recorded. Let's add to the table. */ | 1317 if (EQ (Qt, num)) |
1317 if (print_number_index == 0) | |
1318 { | |
1319 /* Initialize the table. */ | |
1320 Vprint_number_table = Fmake_vector (make_number (40), Qnil); | |
1321 } | |
1322 else if (XVECTOR (Vprint_number_table)->size == print_number_index * 2) | |
1323 { | |
1324 /* Reallocate the table. */ | |
1325 int i = print_number_index * 4; | |
1326 Lisp_Object old_table = Vprint_number_table; | |
1327 Vprint_number_table = Fmake_vector (make_number (i), Qnil); | |
1328 for (i = 0; i < print_number_index; i++) | |
1329 { | 1318 { |
1330 PRINT_NUMBER_OBJECT (Vprint_number_table, i) | 1319 print_number_index++; |
1331 = PRINT_NUMBER_OBJECT (old_table, i); | 1320 /* Negative number indicates it hasn't been printed yet. */ |
1332 PRINT_NUMBER_STATUS (Vprint_number_table, i) | 1321 Fputhash (obj, make_number (- print_number_index), |
1333 = PRINT_NUMBER_STATUS (old_table, i); | 1322 Vprint_number_table); |
1334 } | 1323 } |
1335 } | 1324 print_depth--; |
1336 PRINT_NUMBER_OBJECT (Vprint_number_table, print_number_index) = obj; | 1325 return; |
1337 /* If Vprint_continuous_numbering is non-nil and OBJ is a gensym, | 1326 } |
1338 always print the gensym with a number. This is a special for | 1327 else |
1339 the lisp function byte-compile-output-docform. */ | 1328 /* OBJ is not yet recorded. Let's add to the table. */ |
1340 if (!NILP (Vprint_continuous_numbering) | 1329 Fputhash (obj, Qt, Vprint_number_table); |
1341 && SYMBOLP (obj) | |
1342 && !SYMBOL_INTERNED_P (obj)) | |
1343 PRINT_NUMBER_STATUS (Vprint_number_table, print_number_index) = Qt; | |
1344 print_number_index++; | |
1345 } | 1330 } |
1346 | 1331 |
1347 switch (XTYPE (obj)) | 1332 switch (XTYPE (obj)) |
1348 { | 1333 { |
1349 case Lisp_String: | 1334 case Lisp_String: |
1370 size &= PSEUDOVECTOR_SIZE_MASK; | 1355 size &= PSEUDOVECTOR_SIZE_MASK; |
1371 for (i = 0; i < size; i++) | 1356 for (i = 0; i < size; i++) |
1372 print_preprocess (XVECTOR (obj)->contents[i]); | 1357 print_preprocess (XVECTOR (obj)->contents[i]); |
1373 if (HASH_TABLE_P (obj)) | 1358 if (HASH_TABLE_P (obj)) |
1374 { /* For hash tables, the key_and_value slot is past | 1359 { /* For hash tables, the key_and_value slot is past |
1375 `size' because it needs to be marked specially in case | 1360 `size' because it needs to be marked specially in case |
1376 the table is weak. */ | 1361 the table is weak. */ |
1377 struct Lisp_Hash_Table *h = XHASH_TABLE (obj); | 1362 struct Lisp_Hash_Table *h = XHASH_TABLE (obj); |
1378 print_preprocess (h->key_and_value); | 1363 print_preprocess (h->key_and_value); |
1379 } | 1364 } |
1380 break; | 1365 break; |
1381 | 1366 |
1508 being_printed[print_depth] = obj; | 1493 being_printed[print_depth] = obj; |
1509 } | 1494 } |
1510 else | 1495 else |
1511 { | 1496 { |
1512 /* With the print-circle feature. */ | 1497 /* With the print-circle feature. */ |
1513 int i; | 1498 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil); |
1514 for (i = 0; i < print_number_index; i++) | 1499 if (INTEGERP (num)) |
1515 if (EQ (PRINT_NUMBER_OBJECT (Vprint_number_table, i), obj)) | 1500 { |
1516 { | 1501 int n = XINT (num); |
1517 if (NILP (PRINT_NUMBER_STATUS (Vprint_number_table, i))) | 1502 if (n < 0) |
1518 { | 1503 { /* Add a prefix #n= if OBJ has not yet been printed; |
1519 /* Add a prefix #n= if OBJ has not yet been printed; | 1504 that is, its status field is nil. */ |
1520 that is, its status field is nil. */ | 1505 sprintf (buf, "#%d=", -n); |
1521 sprintf (buf, "#%d=", i + 1); | 1506 strout (buf, -1, -1, printcharfun, 0); |
1522 strout (buf, -1, -1, printcharfun, 0); | 1507 /* OBJ is going to be printed. Remember that fact. */ |
1523 /* OBJ is going to be printed. Set the status to t. */ | 1508 Fputhash (obj, make_number (- n), Vprint_number_table); |
1524 PRINT_NUMBER_STATUS (Vprint_number_table, i) = Qt; | 1509 } |
1525 break; | 1510 else |
1526 } | 1511 { |
1527 else | 1512 /* Just print #n# if OBJ has already been printed. */ |
1528 { | 1513 sprintf (buf, "#%d#", n); |
1529 /* Just print #n# if OBJ has already been printed. */ | 1514 strout (buf, -1, -1, printcharfun, 0); |
1530 sprintf (buf, "#%d#", i + 1); | 1515 return; |
1531 strout (buf, -1, -1, printcharfun, 0); | 1516 } |
1532 return; | 1517 } |
1533 } | |
1534 } | |
1535 } | 1518 } |
1536 } | 1519 } |
1537 | 1520 |
1538 print_depth++; | 1521 print_depth++; |
1539 | 1522 |
1832 else | 1815 else |
1833 { | 1816 { |
1834 /* With the print-circle feature. */ | 1817 /* With the print-circle feature. */ |
1835 if (i != 0) | 1818 if (i != 0) |
1836 { | 1819 { |
1837 int i; | 1820 Lisp_Object num = Fgethash (obj, Vprint_number_table, Qnil); |
1838 for (i = 0; i < print_number_index; i++) | 1821 if (INTEGERP (num)) |
1839 if (EQ (PRINT_NUMBER_OBJECT (Vprint_number_table, i), | |
1840 obj)) | |
1841 { | |
1842 if (NILP (PRINT_NUMBER_STATUS (Vprint_number_table, i))) | |
1843 { | 1822 { |
1844 strout (" . ", 3, 3, printcharfun, 0); | 1823 strout (" . ", 3, 3, printcharfun, 0); |
1845 print_object (obj, printcharfun, escapeflag); | 1824 print_object (obj, printcharfun, escapeflag); |
1846 } | |
1847 else | |
1848 { | |
1849 sprintf (buf, " . #%d#", i + 1); | |
1850 strout (buf, -1, -1, printcharfun, 0); | |
1851 } | |
1852 goto end_of_list; | 1825 goto end_of_list; |
1853 } | 1826 } |
1854 } | 1827 } |
1855 } | 1828 } |
1856 | 1829 |