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