Mercurial > emacs
comparison src/intervals.c @ 5415:95882472f2da
(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.
author | Richard M. Stallman <rms@gnu.org> |
---|---|
date | Sun, 02 Jan 1994 19:01:15 +0000 |
parents | 63a865489a1e |
children | ceed2e32b303 |
comparison
equal
deleted
inserted
replaced
5414:39f0a30bb163 | 5415:95882472f2da |
---|---|
282 rotate_right (interval) | 282 rotate_right (interval) |
283 INTERVAL interval; | 283 INTERVAL 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; | 301 |
302 interval->left->right = interval; | 302 /* Make A point to c */ |
303 interval->parent = interval->left; | |
304 | |
305 /* A gets c as left child. */ | |
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 |
318 / \ / \ | 319 / \ / \ |
319 B => A | 320 B => A |
325 rotate_left (interval) | 326 rotate_left (interval) |
326 INTERVAL interval; | 327 INTERVAL 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; |
358 } | |
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); | |
356 } | 444 } |
357 | 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 |
378 int new_length = LENGTH (interval) - offset; | 466 int new_length = LENGTH (interval) - offset; |
379 | 467 |
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; |
387 | 475 |
388 return new; | 476 return new; |
390 | 478 |
391 /* Insert the new node between INTERVAL and its right child. */ | 479 /* Insert the new node between INTERVAL and its right child. */ |
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; |
484 | |
485 balance_an_interval (new); | |
486 balance_possible_root_interval (interval); | |
397 | 487 |
398 return new; | 488 return new; |
399 } | 489 } |
400 | 490 |
401 /* Split INTERVAL into two pieces, starting the second piece at | 491 /* Split INTERVAL into two pieces, starting the second piece at |
434 | 524 |
435 /* Insert the new node between INTERVAL and its left child. */ | 525 /* Insert the new node between INTERVAL and its left child. */ |
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 } |
443 | 536 |
444 /* Find the interval containing text position POSITION in the text | 537 /* Find the interval containing text position POSITION in the text |
462 if (NULL_INTERVAL_P (tree)) | 555 if (NULL_INTERVAL_P (tree)) |
463 return NULL_INTERVAL; | 556 return NULL_INTERVAL; |
464 | 557 |
465 if (relative_position > TOTAL_LENGTH (tree)) | 558 if (relative_position > TOTAL_LENGTH (tree)) |
466 abort (); /* Paranoia */ | 559 abort (); /* Paranoia */ |
560 | |
561 tree = balance_possible_root_interval (tree); | |
467 | 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)) |
471 { | 566 { |
692 prev = previous_interval (i); | 787 prev = previous_interval (i); |
693 | 788 |
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. */ |
702 if (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i)) | 800 if (END_NONSTICKY_P (prev) || FRONT_STICKY_P (i)) |
703 { | 801 { |
737 | 835 |
738 /* Otherwise just extend the interval. */ | 836 /* Otherwise just extend the interval. */ |
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; |
746 } | 847 } |
747 | 848 |
1277 XSET (buf, Lisp_Buffer, buffer); | 1378 XSET (buf, Lisp_Buffer, buffer); |
1278 Fset_text_properties (make_number (position), | 1379 Fset_text_properties (make_number (position), |
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 |
1285 if (NULL_INTERVAL_P (tree)) | 1388 if (NULL_INTERVAL_P (tree)) |
1286 { | 1389 { |
1368 else | 1471 else |
1369 copy_properties (over, this); | 1472 copy_properties (over, this); |
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 |
1377 /* Get the value of property PROP from PLIST, | 1481 /* Get the value of property PROP from PLIST, |
1378 which is the plist of an interval. | 1482 which is the plist of an interval. |
1760 } | 1864 } |
1761 UNGCPRO; | 1865 UNGCPRO; |
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 |
1832 INTERVAL | 1872 INTERVAL |
1833 copy_intervals (tree, start, length) | 1873 copy_intervals (tree, start, length) |
1864 copy_properties (i, t); | 1904 copy_properties (i, t); |
1865 prevlen = LENGTH (i); | 1905 prevlen = LENGTH (i); |
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. */ |
1873 | 1913 |
1874 INLINE void | 1914 INLINE void |