aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRichard M. Stallman1994-01-02 19:01:15 +0000
committerRichard M. Stallman1994-01-02 19:01:15 +0000
commit4314dea4b4e7a9b2f88dac84744ae5145ee07f81 (patch)
tree3fc633411e8479109483d045de73dbdb785fb8f2 /src
parent7ac78c9ad4065b5abba9915320b2a969466d55a1 (diff)
downloademacs-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')
-rw-r--r--src/intervals.c240
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
363static INTERVAL
364balance_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
399static INLINE INTERVAL
400balance_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
422static INTERVAL
423balance_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
436INTERVAL
437balance_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
1769static INTERVAL
1770balance_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
1809INTERVAL
1810balance_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. */