aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorStefan Monnier2022-11-17 09:08:24 -0500
committerStefan Monnier2022-11-17 09:08:24 -0500
commit13003105a8edf746a8e8819122bd1bcdf7f9ecdd (patch)
tree127f1973a5c76e109c61545bfbb3b9ecf2175126 /src
parent7781121c44736a9a5ad0422955f23bfc045f5504 (diff)
downloademacs-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.c298
-rw-r--r--src/itree.h1
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)
242struct itree_iterator 242struct 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
1141bool
1142itree_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
1150struct itree_iterator *
1151itree_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
1180void
1181itree_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
1307bool
1308itree_iterator_busy_p (void)
1309{
1310 return (iter && iter->running);
1311}
1312
1313/* Stop using the iterator. */
1314
1315void
1316itree_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
1358static inline bool 1330static inline bool
1359itree_node_intersects (const struct itree_node *node, 1331itree_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
1350static struct itree_node *
1351itree_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
1461static struct itree_node *
1462itree_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
1506struct itree_iterator *
1507itree_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
1536static struct itree_node *
1537itree_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
109extern void init_itree (void); 110extern void init_itree (void);