diff options
| author | Richard M. Stallman | 1994-01-02 19:01:15 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1994-01-02 19:01:15 +0000 |
| commit | 4314dea4b4e7a9b2f88dac84744ae5145ee07f81 (patch) | |
| tree | 3fc633411e8479109483d045de73dbdb785fb8f2 /src/intervals.c | |
| parent | 7ac78c9ad4065b5abba9915320b2a969466d55a1 (diff) | |
| download | emacs-4314dea4b4e7a9b2f88dac84744ae5145ee07f81.tar.gz emacs-4314dea4b4e7a9b2f88dac84744ae5145ee07f81.zip | |
(rotate_right, rotate_left): Simplify
total_length calculation. Minimize pointer dereferencing.
(balance_an_interval): Remove recursive rebalancing.
Rebalance precisely when imbalanced. If a rotation is done,
rebalance only the node which may have become unbalanced.
Iterate until the current node is balanced.
(balance_possible_root_interval): New function.
(balance_intervals): Move the interation into rebalance_an_interval.
(balance_intervals_internal): New subroutine of balance_intervals.
(split_interval_right, split_interval_left): Speed up by
not checking LEAF_INTERVAL_P.
(split_interval_right, split_interval_left, find_interval,
adjust_intervals_for_insertion, graft_intervals_into_buffer):
Add dynamic rebalancing anywhere a node may become unbalanced.
(graft_intervals_into_buffer, copy_intervals): No longer
any need to do a full rebalance as the tree stays balanced.
Diffstat (limited to 'src/intervals.c')
| -rw-r--r-- | src/intervals.c | 240 |
1 files changed, 140 insertions, 100 deletions
diff --git a/src/intervals.c b/src/intervals.c index 46b1f9f31fd..51f988d4637 100644 --- a/src/intervals.c +++ b/src/intervals.c | |||
| @@ -284,34 +284,35 @@ rotate_right (interval) | |||
| 284 | { | 284 | { |
| 285 | INTERVAL i; | 285 | INTERVAL i; |
| 286 | INTERVAL B = interval->left; | 286 | INTERVAL B = interval->left; |
| 287 | int len = LENGTH (interval); | 287 | int old_total = interval->total_length; |
| 288 | 288 | ||
| 289 | /* Deal with any Parent of A; make it point to B. */ | 289 | /* Deal with any Parent of A; make it point to B. */ |
| 290 | if (! ROOT_INTERVAL_P (interval)) | 290 | if (! ROOT_INTERVAL_P (interval)) |
| 291 | if (AM_LEFT_CHILD (interval)) | 291 | if (AM_LEFT_CHILD (interval)) |
| 292 | interval->parent->left = interval->left; | 292 | interval->parent->left = B; |
| 293 | else | 293 | else |
| 294 | interval->parent->right = interval->left; | 294 | interval->parent->right = B; |
| 295 | interval->left->parent = interval->parent; | 295 | B->parent = interval->parent; |
| 296 | 296 | ||
| 297 | /* B gets the same length as A, since it get A's position in the tree. */ | 297 | /* Make B the parent of A */ |
| 298 | interval->left->total_length = interval->total_length; | 298 | i = B->right; |
| 299 | 299 | B->right = interval; | |
| 300 | /* B becomes the parent of A. */ | 300 | interval->parent = B; |
| 301 | i = interval->left->right; | ||
| 302 | interval->left->right = interval; | ||
| 303 | interval->parent = interval->left; | ||
| 304 | 301 | ||
| 305 | /* A gets c as left child. */ | 302 | /* Make A point to c */ |
| 306 | interval->left = i; | 303 | interval->left = i; |
| 307 | if (! NULL_INTERVAL_P (i)) | 304 | if (! NULL_INTERVAL_P (i)) |
| 308 | i->parent = interval; | 305 | i->parent = interval; |
| 309 | interval->total_length = (len + LEFT_TOTAL_LENGTH (interval) | 306 | |
| 310 | + RIGHT_TOTAL_LENGTH (interval)); | 307 | /* A's total length is decreased by the length of B and it's left child. */ |
| 308 | interval->total_length -= B->total_length - LEFT_TOTAL_LENGTH (interval); | ||
| 309 | |||
| 310 | /* B must have the same total length of A. */ | ||
| 311 | B->total_length = old_total; | ||
| 311 | 312 | ||
| 312 | return B; | 313 | return B; |
| 313 | } | 314 | } |
| 314 | 315 | ||
| 315 | /* Assuming that a right child exists, perform the following operation: | 316 | /* Assuming that a right child exists, perform the following operation: |
| 316 | 317 | ||
| 317 | A B | 318 | A B |
| @@ -327,34 +328,121 @@ rotate_left (interval) | |||
| 327 | { | 328 | { |
| 328 | INTERVAL i; | 329 | INTERVAL i; |
| 329 | INTERVAL B = interval->right; | 330 | INTERVAL B = interval->right; |
| 330 | int len = LENGTH (interval); | 331 | int old_total = interval->total_length; |
| 331 | 332 | ||
| 332 | /* Deal with the parent of A. */ | 333 | /* Deal with any parent of A; make it point to B. */ |
| 333 | if (! ROOT_INTERVAL_P (interval)) | 334 | if (! ROOT_INTERVAL_P (interval)) |
| 334 | if (AM_LEFT_CHILD (interval)) | 335 | if (AM_LEFT_CHILD (interval)) |
| 335 | interval->parent->left = interval->right; | 336 | interval->parent->left = B; |
| 336 | else | 337 | else |
| 337 | interval->parent->right = interval->right; | 338 | interval->parent->right = B; |
| 338 | interval->right->parent = interval->parent; | 339 | B->parent = interval->parent; |
| 339 | |||
| 340 | /* B must have the same total length of A. */ | ||
| 341 | interval->right->total_length = interval->total_length; | ||
| 342 | 340 | ||
| 343 | /* Make B the parent of A */ | 341 | /* Make B the parent of A */ |
| 344 | i = interval->right->left; | 342 | i = B->left; |
| 345 | interval->right->left = interval; | 343 | B->left = interval; |
| 346 | interval->parent = interval->right; | 344 | interval->parent = B; |
| 347 | 345 | ||
| 348 | /* Make A point to c */ | 346 | /* Make A point to c */ |
| 349 | interval->right = i; | 347 | interval->right = i; |
| 350 | if (! NULL_INTERVAL_P (i)) | 348 | if (! NULL_INTERVAL_P (i)) |
| 351 | i->parent = interval; | 349 | i->parent = interval; |
| 352 | interval->total_length = (len + LEFT_TOTAL_LENGTH (interval) | 350 | |
| 353 | + RIGHT_TOTAL_LENGTH (interval)); | 351 | /* A's total length is decreased by the length of B and it's right child. */ |
| 352 | interval->total_length -= B->total_length - RIGHT_TOTAL_LENGTH (interval); | ||
| 353 | |||
| 354 | /* B must have the same total length of A. */ | ||
| 355 | B->total_length = old_total; | ||
| 354 | 356 | ||
| 355 | return B; | 357 | return B; |
| 356 | } | 358 | } |
| 357 | 359 | ||
| 360 | /* Balance an interval tree with the assumption that the subtrees | ||
| 361 | themselves are already balanced. */ | ||
| 362 | |||
| 363 | static INTERVAL | ||
| 364 | balance_an_interval (i) | ||
| 365 | INTERVAL i; | ||
| 366 | { | ||
| 367 | register int old_diff, new_diff; | ||
| 368 | |||
| 369 | while (1) | ||
| 370 | { | ||
| 371 | old_diff = LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i); | ||
| 372 | if (old_diff > 0) | ||
| 373 | { | ||
| 374 | new_diff = i->total_length - i->left->total_length | ||
| 375 | + RIGHT_TOTAL_LENGTH (i->left) - LEFT_TOTAL_LENGTH (i->left); | ||
| 376 | if (abs (new_diff) >= old_diff) | ||
| 377 | break; | ||
| 378 | i = rotate_right (i); | ||
| 379 | balance_an_interval (i->right); | ||
| 380 | } | ||
| 381 | else if (old_diff < 0) | ||
| 382 | { | ||
| 383 | new_diff = i->total_length - i->right->total_length | ||
| 384 | + LEFT_TOTAL_LENGTH (i->right) - RIGHT_TOTAL_LENGTH (i->right); | ||
| 385 | if (abs (new_diff) >= -old_diff) | ||
| 386 | break; | ||
| 387 | i = rotate_left (i); | ||
| 388 | balance_an_interval (i->left); | ||
| 389 | } | ||
| 390 | else | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | return i; | ||
| 394 | } | ||
| 395 | |||
| 396 | /* Balance INTERVAL, potentially stuffing it back into its parent | ||
| 397 | Lisp Object. */ | ||
| 398 | |||
| 399 | static INLINE INTERVAL | ||
| 400 | balance_possible_root_interval (interval) | ||
| 401 | register INTERVAL interval; | ||
| 402 | { | ||
| 403 | Lisp_Object parent; | ||
| 404 | |||
| 405 | if (interval->parent == NULL_INTERVAL) | ||
| 406 | return interval; | ||
| 407 | |||
| 408 | parent = (Lisp_Object) (interval->parent); | ||
| 409 | interval = balance_an_interval (interval); | ||
| 410 | |||
| 411 | if (XTYPE (parent) == Lisp_Buffer) | ||
| 412 | XBUFFER (parent)->intervals = interval; | ||
| 413 | else if (XTYPE (parent) == Lisp_String) | ||
| 414 | XSTRING (parent)->intervals = interval; | ||
| 415 | |||
| 416 | return interval; | ||
| 417 | } | ||
| 418 | |||
| 419 | /* Balance the interval tree TREE. Balancing is by weight | ||
| 420 | (the amount of text). */ | ||
| 421 | |||
| 422 | static INTERVAL | ||
| 423 | balance_intervals_internal (tree) | ||
| 424 | register INTERVAL tree; | ||
| 425 | { | ||
| 426 | /* Balance within each side. */ | ||
| 427 | if (tree->left) | ||
| 428 | balance_intervals (tree->left); | ||
| 429 | if (tree->right) | ||
| 430 | balance_intervals (tree->right); | ||
| 431 | return balance_an_interval (tree); | ||
| 432 | } | ||
| 433 | |||
| 434 | /* Advertised interface to balance intervals. */ | ||
| 435 | |||
| 436 | INTERVAL | ||
| 437 | balance_intervals (tree) | ||
| 438 | INTERVAL tree; | ||
| 439 | { | ||
| 440 | if (tree == NULL_INTERVAL) | ||
| 441 | return NULL_INTERVAL; | ||
| 442 | |||
| 443 | return balance_intervals_internal (tree); | ||
| 444 | } | ||
| 445 | |||
| 358 | /* Split INTERVAL into two pieces, starting the second piece at | 446 | /* Split INTERVAL into two pieces, starting the second piece at |
| 359 | character position OFFSET (counting from 0), relative to INTERVAL. | 447 | character position OFFSET (counting from 0), relative to INTERVAL. |
| 360 | INTERVAL becomes the left-hand piece, and the right-hand piece | 448 | INTERVAL becomes the left-hand piece, and the right-hand piece |
| @@ -380,7 +468,7 @@ split_interval_right (interval, offset) | |||
| 380 | new->position = position + offset; | 468 | new->position = position + offset; |
| 381 | new->parent = interval; | 469 | new->parent = interval; |
| 382 | 470 | ||
| 383 | if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval)) | 471 | if (NULL_RIGHT_CHILD (interval)) |
| 384 | { | 472 | { |
| 385 | interval->right = new; | 473 | interval->right = new; |
| 386 | new->total_length = new_length; | 474 | new->total_length = new_length; |
| @@ -392,9 +480,11 @@ split_interval_right (interval, offset) | |||
| 392 | new->right = interval->right; | 480 | new->right = interval->right; |
| 393 | interval->right->parent = new; | 481 | interval->right->parent = new; |
| 394 | interval->right = new; | 482 | interval->right = new; |
| 395 | |||
| 396 | new->total_length = new_length + new->right->total_length; | 483 | new->total_length = new_length + new->right->total_length; |
| 397 | 484 | ||
| 485 | balance_an_interval (new); | ||
| 486 | balance_possible_root_interval (interval); | ||
| 487 | |||
| 398 | return new; | 488 | return new; |
| 399 | } | 489 | } |
| 400 | 490 | ||
| @@ -436,7 +526,10 @@ split_interval_left (interval, offset) | |||
| 436 | new->left = interval->left; | 526 | new->left = interval->left; |
| 437 | new->left->parent = new; | 527 | new->left->parent = new; |
| 438 | interval->left = new; | 528 | interval->left = new; |
| 439 | new->total_length = new_length + LEFT_TOTAL_LENGTH (new); | 529 | new->total_length = new_length + new->left->total_length; |
| 530 | |||
| 531 | balance_an_interval (new); | ||
| 532 | balance_possible_root_interval (interval); | ||
| 440 | 533 | ||
| 441 | return new; | 534 | return new; |
| 442 | } | 535 | } |
| @@ -465,6 +558,8 @@ find_interval (tree, position) | |||
| 465 | if (relative_position > TOTAL_LENGTH (tree)) | 558 | if (relative_position > TOTAL_LENGTH (tree)) |
| 466 | abort (); /* Paranoia */ | 559 | abort (); /* Paranoia */ |
| 467 | 560 | ||
| 561 | tree = balance_possible_root_interval (tree); | ||
| 562 | |||
| 468 | while (1) | 563 | while (1) |
| 469 | { | 564 | { |
| 470 | if (relative_position < LEFT_TOTAL_LENGTH (tree)) | 565 | if (relative_position < LEFT_TOTAL_LENGTH (tree)) |
| @@ -694,8 +789,11 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 694 | /* Even if we are positioned between intervals, we default | 789 | /* Even if we are positioned between intervals, we default |
| 695 | to the left one if it exists. We extend it now and split | 790 | to the left one if it exists. We extend it now and split |
| 696 | off a part later, if stickyness demands it. */ | 791 | off a part later, if stickyness demands it. */ |
| 697 | for (temp = prev ? prev : i; ! NULL_INTERVAL_P (temp); temp = temp->parent) | 792 | for (temp = prev ? prev : i;! NULL_INTERVAL_P (temp); temp = temp->parent) |
| 698 | temp->total_length += length; | 793 | { |
| 794 | temp->total_length += length; | ||
| 795 | temp = balance_possible_root_interval (temp); | ||
| 796 | } | ||
| 699 | 797 | ||
| 700 | /* If at least one interval has sticky properties, | 798 | /* If at least one interval has sticky properties, |
| 701 | we check the stickyness property by property. */ | 799 | we check the stickyness property by property. */ |
| @@ -739,7 +837,10 @@ adjust_intervals_for_insertion (tree, position, length) | |||
| 739 | else | 837 | else |
| 740 | { | 838 | { |
| 741 | for (temp = i; ! NULL_INTERVAL_P (temp); temp = temp->parent) | 839 | for (temp = i; ! NULL_INTERVAL_P (temp); temp = temp->parent) |
| 742 | temp->total_length += length; | 840 | { |
| 841 | temp->total_length += length; | ||
| 842 | temp = balance_possible_root_interval (temp); | ||
| 843 | } | ||
| 743 | } | 844 | } |
| 744 | 845 | ||
| 745 | return tree; | 846 | return tree; |
| @@ -1279,6 +1380,8 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) | |||
| 1279 | make_number (position + length), | 1380 | make_number (position + length), |
| 1280 | Qnil, buf); | 1381 | Qnil, buf); |
| 1281 | } | 1382 | } |
| 1383 | if (! NULL_INTERVAL_P (buffer->intervals)) | ||
| 1384 | buffer->intervals = balance_an_interval (buffer->intervals); | ||
| 1282 | return; | 1385 | return; |
| 1283 | } | 1386 | } |
| 1284 | 1387 | ||
| @@ -1370,7 +1473,8 @@ graft_intervals_into_buffer (source, position, length, buffer, inherit) | |||
| 1370 | over = next_interval (over); | 1473 | over = next_interval (over); |
| 1371 | } | 1474 | } |
| 1372 | 1475 | ||
| 1373 | buffer->intervals = balance_intervals (buffer->intervals); | 1476 | if (! NULL_INTERVAL_P (buffer->intervals)) |
| 1477 | buffer->intervals = balance_an_interval (buffer->intervals); | ||
| 1374 | return; | 1478 | return; |
| 1375 | } | 1479 | } |
| 1376 | 1480 | ||
| @@ -1762,70 +1866,6 @@ verify_interval_modification (buf, start, end) | |||
| 1762 | } | 1866 | } |
| 1763 | } | 1867 | } |
| 1764 | 1868 | ||
| 1765 | /* Balance an interval node if the amount of text in its left and right | ||
| 1766 | subtrees differs by more than the percentage specified by | ||
| 1767 | `interval-balance-threshold'. */ | ||
| 1768 | |||
| 1769 | static INTERVAL | ||
| 1770 | balance_an_interval (i) | ||
| 1771 | INTERVAL i; | ||
| 1772 | { | ||
| 1773 | register int total_children_size = (LEFT_TOTAL_LENGTH (i) | ||
| 1774 | + RIGHT_TOTAL_LENGTH (i)); | ||
| 1775 | register int threshold = (XFASTINT (interval_balance_threshold) | ||
| 1776 | * (total_children_size / 100)); | ||
| 1777 | |||
| 1778 | /* Balance within each side. */ | ||
| 1779 | balance_intervals (i->left); | ||
| 1780 | balance_intervals (i->right); | ||
| 1781 | |||
| 1782 | if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i) | ||
| 1783 | && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold) | ||
| 1784 | { | ||
| 1785 | i = rotate_right (i); | ||
| 1786 | /* If that made it unbalanced the other way, take it back. */ | ||
| 1787 | if (RIGHT_TOTAL_LENGTH (i) > LEFT_TOTAL_LENGTH (i) | ||
| 1788 | && (RIGHT_TOTAL_LENGTH (i) - LEFT_TOTAL_LENGTH (i)) > threshold) | ||
| 1789 | return rotate_left (i); | ||
| 1790 | return i; | ||
| 1791 | } | ||
| 1792 | |||
| 1793 | if (RIGHT_TOTAL_LENGTH (i) > LEFT_TOTAL_LENGTH (i) | ||
| 1794 | && (RIGHT_TOTAL_LENGTH (i) - LEFT_TOTAL_LENGTH (i)) > threshold) | ||
| 1795 | { | ||
| 1796 | i = rotate_left (i); | ||
| 1797 | if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i) | ||
| 1798 | && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold) | ||
| 1799 | return rotate_right (i); | ||
| 1800 | return i; | ||
| 1801 | } | ||
| 1802 | |||
| 1803 | return i; | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | /* Balance the interval tree TREE. Balancing is by weight | ||
| 1807 | (the amount of text). */ | ||
| 1808 | |||
| 1809 | INTERVAL | ||
| 1810 | balance_intervals (tree) | ||
| 1811 | register INTERVAL tree; | ||
| 1812 | { | ||
| 1813 | register INTERVAL new_tree; | ||
| 1814 | |||
| 1815 | if (NULL_INTERVAL_P (tree)) | ||
| 1816 | return NULL_INTERVAL; | ||
| 1817 | |||
| 1818 | new_tree = tree; | ||
| 1819 | do | ||
| 1820 | { | ||
| 1821 | tree = new_tree; | ||
| 1822 | new_tree = balance_an_interval (new_tree); | ||
| 1823 | } | ||
| 1824 | while (new_tree != tree); | ||
| 1825 | |||
| 1826 | return new_tree; | ||
| 1827 | } | ||
| 1828 | |||
| 1829 | /* Produce an interval tree reflecting the intervals in | 1869 | /* Produce an interval tree reflecting the intervals in |
| 1830 | TREE from START to START + LENGTH. */ | 1870 | TREE from START to START + LENGTH. */ |
| 1831 | 1871 | ||
| @@ -1866,7 +1906,7 @@ copy_intervals (tree, start, length) | |||
| 1866 | got += prevlen; | 1906 | got += prevlen; |
| 1867 | } | 1907 | } |
| 1868 | 1908 | ||
| 1869 | return balance_intervals (new); | 1909 | return balance_an_interval (new); |
| 1870 | } | 1910 | } |
| 1871 | 1911 | ||
| 1872 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ | 1912 | /* Give STRING the properties of BUFFER from POSITION to LENGTH. */ |