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