diff options
| author | Stefan Monnier | 2022-11-17 09:08:24 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2022-11-17 09:08:24 -0500 |
| commit | 13003105a8edf746a8e8819122bd1bcdf7f9ecdd (patch) | |
| tree | 127f1973a5c76e109c61545bfbb3b9ecf2175126 /src | |
| parent | 7781121c44736a9a5ad0422955f23bfc045f5504 (diff) | |
| download | emacs-13003105a8edf746a8e8819122bd1bcdf7f9ecdd.tar.gz emacs-13003105a8edf746a8e8819122bd1bcdf7f9ecdd.zip | |
itree.c: Add new "stateless" iterator code and post-order traversal
This still uses the old iterator code, but runs the new code
alongside to make sure they behave identically.
* src/itree.c (struct itree_iterator): New field `node`.
(itree_iterator_create): Give it a sane default value.
(itree_iterator_busy_p, itree_iterator_start, itree_iterator_finish):
Move down to the "iterator" section of the file.
(itree_iter_next_in_subtree, itree_iterator_first_node)
(itree_iter_next): New functions.
(itree_iterator_start): Initialize the new `node` field.
(itree_iterator_next): Add post-order case.
Call the new "stateless" `itree_iter_next` function and check that it
agrees.
* src/itree.h (enum itree_order): New value for post-order traversals.
Diffstat (limited to 'src')
| -rw-r--r-- | src/itree.c | 298 | ||||
| -rw-r--r-- | src/itree.h | 1 |
2 files changed, 252 insertions, 47 deletions
diff --git a/src/itree.c b/src/itree.c index da0242905c2..4f25a924b40 100644 --- a/src/itree.c +++ b/src/itree.c | |||
| @@ -242,6 +242,7 @@ itree_stack_pop (struct itree_stack *stack) | |||
| 242 | struct itree_iterator | 242 | struct itree_iterator |
| 243 | { | 243 | { |
| 244 | struct itree_stack *stack; | 244 | struct itree_stack *stack; |
| 245 | struct itree_node *node; | ||
| 245 | ptrdiff_t begin; | 246 | ptrdiff_t begin; |
| 246 | ptrdiff_t end; | 247 | ptrdiff_t end; |
| 247 | 248 | ||
| @@ -279,6 +280,7 @@ itree_iterator_create (struct itree_tree *tree) | |||
| 279 | const int size = (tree ? itree_max_height (tree) : 19) + 1; | 280 | const int size = (tree ? itree_max_height (tree) : 19) + 1; |
| 280 | 281 | ||
| 281 | g->stack = itree_stack_create (size); | 282 | g->stack = itree_stack_create (size); |
| 283 | g->node = NULL; | ||
| 282 | g->running = false; | 284 | g->running = false; |
| 283 | g->begin = 0; | 285 | g->begin = 0; |
| 284 | g->end = 0; | 286 | g->end = 0; |
| @@ -1138,52 +1140,6 @@ itree_remove (struct itree_tree *tree, struct itree_node *node) | |||
| 1138 | return node; | 1140 | return node; |
| 1139 | } | 1141 | } |
| 1140 | 1142 | ||
| 1141 | bool | ||
| 1142 | itree_iterator_busy_p (void) | ||
| 1143 | { | ||
| 1144 | return (iter && iter->running); | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /* Start a iterator enumerating all intervals in [BEGIN,END) in the | ||
| 1148 | given ORDER. Only one iterator per tree can be running at any time. */ | ||
| 1149 | |||
| 1150 | struct itree_iterator * | ||
| 1151 | itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin, | ||
| 1152 | ptrdiff_t end, enum itree_order order, | ||
| 1153 | const char *file, int line) | ||
| 1154 | { | ||
| 1155 | eassert (iter); | ||
| 1156 | if (iter->running) | ||
| 1157 | { | ||
| 1158 | fprintf (stderr, | ||
| 1159 | "Detected nested iteration!\nOuter: %s:%d\nInner: %s:%d\n", | ||
| 1160 | iter->file, iter->line, file, line); | ||
| 1161 | emacs_abort (); | ||
| 1162 | } | ||
| 1163 | iter->begin = begin; | ||
| 1164 | iter->end = end; | ||
| 1165 | iter->otick = tree->otick; | ||
| 1166 | iter->order = order; | ||
| 1167 | itree_stack_clear (iter->stack); | ||
| 1168 | if (begin <= end && tree->root != NULL) | ||
| 1169 | itree_stack_push_flagged (iter->stack, tree->root, false); | ||
| 1170 | iter->file = file; | ||
| 1171 | iter->line = line; | ||
| 1172 | iter->running = true; | ||
| 1173 | /* itree_stack_ensure_space (iter->stack, | ||
| 1174 | 2 * itree_max_height (tree)); */ | ||
| 1175 | return iter; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | /* Stop using the iterator. */ | ||
| 1179 | |||
| 1180 | void | ||
| 1181 | itree_iterator_finish (struct itree_iterator *iter) | ||
| 1182 | { | ||
| 1183 | eassert (iter && iter->running); | ||
| 1184 | iter->running = false; | ||
| 1185 | } | ||
| 1186 | |||
| 1187 | 1143 | ||
| 1188 | /* +=======================================================================+ | 1144 | /* +=======================================================================+ |
| 1189 | * | Insert/Delete Gaps | 1145 | * | Insert/Delete Gaps |
| @@ -1214,6 +1170,7 @@ itree_insert_gap (struct itree_tree *tree, | |||
| 1214 | struct itree_node *node = NULL; | 1170 | struct itree_node *node = NULL; |
| 1215 | if (!before_markers) | 1171 | if (!before_markers) |
| 1216 | { | 1172 | { |
| 1173 | /* Actually any order would do. */ | ||
| 1217 | ITREE_FOREACH (node, tree, pos, pos + 1, PRE_ORDER) | 1174 | ITREE_FOREACH (node, tree, pos, pos + 1, PRE_ORDER) |
| 1218 | { | 1175 | { |
| 1219 | if (node->begin == pos && node->front_advance | 1176 | if (node->begin == pos && node->front_advance |
| @@ -1347,6 +1304,21 @@ itree_delete_gap (struct itree_tree *tree, | |||
| 1347 | * | Iterator | 1304 | * | Iterator |
| 1348 | * +=======================================================================+ */ | 1305 | * +=======================================================================+ */ |
| 1349 | 1306 | ||
| 1307 | bool | ||
| 1308 | itree_iterator_busy_p (void) | ||
| 1309 | { | ||
| 1310 | return (iter && iter->running); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | /* Stop using the iterator. */ | ||
| 1314 | |||
| 1315 | void | ||
| 1316 | itree_iterator_finish (struct itree_iterator *iter) | ||
| 1317 | { | ||
| 1318 | eassert (iter && iter->running); | ||
| 1319 | iter->running = false; | ||
| 1320 | } | ||
| 1321 | |||
| 1350 | /* Return true, if NODE's interval intersects with [BEGIN, END). | 1322 | /* Return true, if NODE's interval intersects with [BEGIN, END). |
| 1351 | Note: We always include empty nodes at BEGIN (and not at END), | 1323 | Note: We always include empty nodes at BEGIN (and not at END), |
| 1352 | but if BEGIN==END, then we don't include non-empty nodes starting | 1324 | but if BEGIN==END, then we don't include non-empty nodes starting |
| @@ -1357,12 +1329,223 @@ itree_delete_gap (struct itree_tree *tree, | |||
| 1357 | 1329 | ||
| 1358 | static inline bool | 1330 | static inline bool |
| 1359 | itree_node_intersects (const struct itree_node *node, | 1331 | itree_node_intersects (const struct itree_node *node, |
| 1360 | ptrdiff_t begin, ptrdiff_t end) | 1332 | ptrdiff_t begin, ptrdiff_t end) |
| 1361 | { | 1333 | { |
| 1362 | return (begin < node->end && node->begin < end) | 1334 | return (begin < node->end && node->begin < end) |
| 1363 | || (node->begin == node->end && begin == node->begin); | 1335 | || (node->begin == node->end && begin == node->begin); |
| 1364 | } | 1336 | } |
| 1365 | 1337 | ||
| 1338 | /* Return the "next" node in the current traversal order. | ||
| 1339 | |||
| 1340 | Note that this should return all the nodes that we need to traverse | ||
| 1341 | in order to traverse the nodes selected by the current narrowing (i.e. | ||
| 1342 | `ITER->begin..ITER->end`) so it will also return some nodes which aren't in | ||
| 1343 | that narrowing simply because they may have children which are. | ||
| 1344 | |||
| 1345 | The code itself is very unsatifactory because the code of each one | ||
| 1346 | of the supported traversals seems completely different from the others. | ||
| 1347 | If someone knows how to make it more uniform and "obviously correct", | ||
| 1348 | please make yourself heard. */ | ||
| 1349 | |||
| 1350 | static struct itree_node * | ||
| 1351 | itree_iter_next_in_subtree (struct itree_node *node, | ||
| 1352 | struct itree_iterator *iter) | ||
| 1353 | { | ||
| 1354 | struct itree_node *next; | ||
| 1355 | switch (iter->order) | ||
| 1356 | { | ||
| 1357 | case ITREE_ASCENDING: | ||
| 1358 | next = node->right; | ||
| 1359 | if (!next) | ||
| 1360 | { | ||
| 1361 | while ((next = node->parent) | ||
| 1362 | && next->right == node) | ||
| 1363 | node = next; | ||
| 1364 | if (!next) | ||
| 1365 | return NULL; /* No more nodes to visit. */ | ||
| 1366 | node = next; | ||
| 1367 | } | ||
| 1368 | else | ||
| 1369 | { | ||
| 1370 | node = next; | ||
| 1371 | itree_inherit_offset (iter->otick, node); | ||
| 1372 | while ((next = node->left) | ||
| 1373 | && (itree_inherit_offset (iter->otick, next), | ||
| 1374 | iter->begin <= next->limit)) | ||
| 1375 | node = next; | ||
| 1376 | } | ||
| 1377 | if (node->begin > iter->end) | ||
| 1378 | return NULL; /* No more nodes within begin..end. */ | ||
| 1379 | return node; | ||
| 1380 | |||
| 1381 | case ITREE_DESCENDING: | ||
| 1382 | next = node->left; | ||
| 1383 | if (!next | ||
| 1384 | || (itree_inherit_offset (iter->otick, next), | ||
| 1385 | next->limit < iter->begin)) | ||
| 1386 | { | ||
| 1387 | while ((next = node->parent) | ||
| 1388 | && next->left == node) | ||
| 1389 | node = next; | ||
| 1390 | if (!next) | ||
| 1391 | return NULL; /* No more nodes to visit. */ | ||
| 1392 | node = next; | ||
| 1393 | } | ||
| 1394 | else | ||
| 1395 | { | ||
| 1396 | node = next; | ||
| 1397 | while (node->begin <= iter->end | ||
| 1398 | && (next = node->right)) | ||
| 1399 | { | ||
| 1400 | itree_inherit_offset (iter->otick, next), | ||
| 1401 | node = next; | ||
| 1402 | } | ||
| 1403 | } | ||
| 1404 | return node; | ||
| 1405 | |||
| 1406 | case ITREE_PRE_ORDER: | ||
| 1407 | next = node->left; | ||
| 1408 | if (next | ||
| 1409 | && (itree_inherit_offset (iter->otick, next), | ||
| 1410 | !(next->limit < iter->begin))) | ||
| 1411 | return next; | ||
| 1412 | next = node->right; | ||
| 1413 | if (node->begin <= iter->end && next) | ||
| 1414 | { | ||
| 1415 | itree_inherit_offset (iter->otick, next); | ||
| 1416 | return next; | ||
| 1417 | } | ||
| 1418 | while ((next = node->parent)) | ||
| 1419 | { | ||
| 1420 | if (next->right == node) | ||
| 1421 | node = next; | ||
| 1422 | else | ||
| 1423 | { | ||
| 1424 | eassert (next->left == node); | ||
| 1425 | node = next; | ||
| 1426 | next = node->right; | ||
| 1427 | if (node->begin <= iter->end && next) | ||
| 1428 | { | ||
| 1429 | itree_inherit_offset (iter->otick, next); | ||
| 1430 | return next; | ||
| 1431 | } | ||
| 1432 | } | ||
| 1433 | } | ||
| 1434 | return NULL; | ||
| 1435 | |||
| 1436 | case ITREE_POST_ORDER: | ||
| 1437 | next = node->parent; | ||
| 1438 | if (!next || next->right == node) | ||
| 1439 | return next; | ||
| 1440 | eassert (next->left == node); | ||
| 1441 | node = next; | ||
| 1442 | next = node->right; | ||
| 1443 | if (!(node->begin <= iter->end && next)) | ||
| 1444 | return node; | ||
| 1445 | node = next; | ||
| 1446 | itree_inherit_offset (iter->otick, node); | ||
| 1447 | while (((next = node->left) | ||
| 1448 | && (itree_inherit_offset (iter->otick, next), | ||
| 1449 | iter->begin <= next->limit)) | ||
| 1450 | || (node->begin <= iter->end | ||
| 1451 | && (next = node->right) | ||
| 1452 | && (itree_inherit_offset (iter->otick, next), true))) | ||
| 1453 | node = next; | ||
| 1454 | return node; | ||
| 1455 | |||
| 1456 | default: | ||
| 1457 | emacs_abort (); | ||
| 1458 | } | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | static struct itree_node * | ||
| 1462 | itree_iterator_first_node (struct itree_tree *tree, | ||
| 1463 | struct itree_iterator *iter) | ||
| 1464 | { | ||
| 1465 | struct itree_node *node = tree->root; | ||
| 1466 | if (node) | ||
| 1467 | { | ||
| 1468 | struct itree_node dummy; | ||
| 1469 | dummy.left = NULL; | ||
| 1470 | dummy.parent = NULL; | ||
| 1471 | dummy.right = NULL; | ||
| 1472 | itree_inherit_offset (iter->otick, node); | ||
| 1473 | switch (iter->order) | ||
| 1474 | { | ||
| 1475 | case ITREE_ASCENDING: | ||
| 1476 | dummy.right = node; | ||
| 1477 | dummy.begin = PTRDIFF_MIN; | ||
| 1478 | node = itree_iter_next_in_subtree (&dummy, iter); | ||
| 1479 | break; | ||
| 1480 | |||
| 1481 | case ITREE_DESCENDING: | ||
| 1482 | dummy.left = node; | ||
| 1483 | node = itree_iter_next_in_subtree (&dummy, iter); | ||
| 1484 | break; | ||
| 1485 | |||
| 1486 | case ITREE_PRE_ORDER: | ||
| 1487 | break; | ||
| 1488 | |||
| 1489 | case ITREE_POST_ORDER: | ||
| 1490 | dummy.parent = &dummy; | ||
| 1491 | dummy.left = &dummy; | ||
| 1492 | dummy.right = node; | ||
| 1493 | dummy.begin = PTRDIFF_MIN; | ||
| 1494 | node = itree_iter_next_in_subtree (&dummy, iter); | ||
| 1495 | break; | ||
| 1496 | default: | ||
| 1497 | emacs_abort (); | ||
| 1498 | } | ||
| 1499 | } | ||
| 1500 | return node; | ||
| 1501 | } | ||
| 1502 | |||
| 1503 | /* Start a iterator enumerating all intervals in [BEGIN,END) in the | ||
| 1504 | given ORDER. Only one iterator per tree can be running at any time. */ | ||
| 1505 | |||
| 1506 | struct itree_iterator * | ||
| 1507 | itree_iterator_start (struct itree_tree *tree, ptrdiff_t begin, | ||
| 1508 | ptrdiff_t end, enum itree_order order, | ||
| 1509 | const char *file, int line) | ||
| 1510 | { | ||
| 1511 | eassert (iter); | ||
| 1512 | if (iter->running) | ||
| 1513 | { | ||
| 1514 | fprintf (stderr, | ||
| 1515 | "Detected nested iteration!\nOuter: %s:%d\nInner: %s:%d\n", | ||
| 1516 | iter->file, iter->line, file, line); | ||
| 1517 | emacs_abort (); | ||
| 1518 | } | ||
| 1519 | uintmax_t otick= tree->otick; | ||
| 1520 | iter->begin = begin; | ||
| 1521 | iter->end = end; | ||
| 1522 | iter->otick = otick; | ||
| 1523 | iter->order = order; | ||
| 1524 | itree_stack_clear (iter->stack); | ||
| 1525 | if (begin <= end && tree->root != NULL) | ||
| 1526 | itree_stack_push_flagged (iter->stack, tree->root, false); | ||
| 1527 | iter->file = file; | ||
| 1528 | iter->line = line; | ||
| 1529 | iter->running = true; | ||
| 1530 | /* itree_stack_ensure_space (iter->stack, | ||
| 1531 | 2 * itree_max_height (tree)); */ | ||
| 1532 | iter->node = itree_iterator_first_node (tree, iter); | ||
| 1533 | return iter; | ||
| 1534 | } | ||
| 1535 | |||
| 1536 | static struct itree_node * | ||
| 1537 | itree_iter_next (struct itree_iterator *iter) | ||
| 1538 | { | ||
| 1539 | struct itree_node *node = iter->node; | ||
| 1540 | while (node | ||
| 1541 | && !itree_node_intersects (node, iter->begin, iter->end)) | ||
| 1542 | { | ||
| 1543 | node = itree_iter_next_in_subtree (node, iter); | ||
| 1544 | } | ||
| 1545 | iter->node = node ? itree_iter_next_in_subtree (node, iter) : NULL; | ||
| 1546 | return node; | ||
| 1547 | } | ||
| 1548 | |||
| 1366 | /* Return the next node of the iterator in the order given when it was | 1549 | /* Return the next node of the iterator in the order given when it was |
| 1367 | started; or NULL if there are no more nodes. */ | 1550 | started; or NULL if there are no more nodes. */ |
| 1368 | 1551 | ||
| @@ -1425,12 +1608,33 @@ itree_iterator_next (struct itree_iterator *g) | |||
| 1425 | if (itree_node_intersects (node, g->begin, g->end)) | 1608 | if (itree_node_intersects (node, g->begin, g->end)) |
| 1426 | itree_stack_push_flagged (g->stack, node, true); | 1609 | itree_stack_push_flagged (g->stack, node, true); |
| 1427 | break; | 1610 | break; |
| 1611 | case ITREE_POST_ORDER: | ||
| 1612 | if (itree_node_intersects (node, g->begin, g->end)) | ||
| 1613 | itree_stack_push_flagged (g->stack, node, true); | ||
| 1614 | if (right != null && node->begin <= g->end) | ||
| 1615 | itree_stack_push_flagged (g->stack, right, false); | ||
| 1616 | if (left != null && g->begin <= left->limit + left->offset) | ||
| 1617 | itree_stack_push_flagged (g->stack, left, false); | ||
| 1618 | break; | ||
| 1428 | } | 1619 | } |
| 1429 | } | 1620 | } |
| 1430 | /* Node may have been invalidated by itree_iterator_narrow | 1621 | /* Node may have been invalidated by itree_iterator_narrow |
| 1431 | after it was pushed: Check if it still intersects. */ | 1622 | after it was pushed: Check if it still intersects. */ |
| 1432 | } while (node && ! itree_node_intersects (node, g->begin, g->end)); | 1623 | } while (node && ! itree_node_intersects (node, g->begin, g->end)); |
| 1433 | 1624 | ||
| 1625 | struct itree_node *old_node = g->node; | ||
| 1626 | struct itree_node *other_node = itree_iter_next (g); | ||
| 1627 | if (other_node != node) | ||
| 1628 | { | ||
| 1629 | fprintf (stderr, "WOW!! %ld..%ld vs %ld..%ld\n", | ||
| 1630 | other_node ? other_node->begin : -1, | ||
| 1631 | other_node ? other_node->end : -1, | ||
| 1632 | node ? node->begin : -1, | ||
| 1633 | node ? node->end : -1); | ||
| 1634 | fprintf (stderr, "ON=%lx N=%lx OlN=%lx\n", other_node, node, | ||
| 1635 | old_node); | ||
| 1636 | emacs_abort (); | ||
| 1637 | } | ||
| 1434 | return node; | 1638 | return node; |
| 1435 | } | 1639 | } |
| 1436 | 1640 | ||
diff --git a/src/itree.h b/src/itree.h index 10ee0897c37..dc448233224 100644 --- a/src/itree.h +++ b/src/itree.h | |||
| @@ -104,6 +104,7 @@ enum itree_order | |||
| 104 | ITREE_ASCENDING, | 104 | ITREE_ASCENDING, |
| 105 | ITREE_DESCENDING, | 105 | ITREE_DESCENDING, |
| 106 | ITREE_PRE_ORDER, | 106 | ITREE_PRE_ORDER, |
| 107 | ITREE_POST_ORDER, | ||
| 107 | }; | 108 | }; |
| 108 | 109 | ||
| 109 | extern void init_itree (void); | 110 | extern void init_itree (void); |