* alloc.c: #include "intervals.h".
[bpt/emacs.git] / src / intervals.c
CommitLineData
a50699fd
JA
1/* Code for doing intervals.
2 Copyright (C) 1991, 1992 Free Software Foundation, Inc.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 1, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20
21/* NOTES:
22
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
25
26 An idea: Have the owner of the tree keep count of splits and/or
27 insertion lengths (in intervals), and balance after every N.
28
29 Need to call *_left_hook when buffer is killed.
30
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
33
34 There are comments around about freeing intervals. It might be
35 faster to explicitly free them (put them on the free list) than
36 to GC them.
37
38*/
39
40
41#include "config.h"
42#include "lisp.h"
43#include "intervals.h"
44#include "buffer.h"
45#include "screen.h"
46
47/* Factor for weight-balancing interval trees. */
48Lisp_Object interval_balance_threshold;
49\f
50/* Utility functions for intervals. */
51
52
53/* Create the root interval of some object, a buffer or string. */
54
55INTERVAL
56create_root_interval (parent)
57 Lisp_Object parent;
58{
59 INTERVAL new = make_interval ();
60
61 if (XTYPE (parent) == Lisp_Buffer)
62 {
63 new->total_length = BUF_Z (XBUFFER (parent)) - 1;
64 XBUFFER (parent)->intervals = new;
65 }
66 else if (XTYPE (parent) == Lisp_String)
67 {
68 new->total_length = XSTRING (parent)->size;
69 XSTRING (parent)->intervals = new;
70 }
71
72 new->parent = (INTERVAL) parent;
73 new->position = 1;
74
75 return new;
76}
77
78/* Make the interval TARGET have exactly the properties of SOURCE */
79
80void
81copy_properties (source, target)
82 register INTERVAL source, target;
83{
84 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
85 return;
86
87 COPY_INTERVAL_CACHE (source, target);
88 target->plist = Fcopy_sequence (source->plist);
89}
90
91/* Merge the properties of interval SOURCE into the properties
92 of interval TARGET. */
93
94static void
95merge_properties (source, target)
96 register INTERVAL source, target;
97{
98 register Lisp_Object o, sym, val;
99
100 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
101 return;
102
103 MERGE_INTERVAL_CACHE (source, target);
104
105 o = source->plist;
106 while (! EQ (o, Qnil))
107 {
108 sym = Fcar (o);
109 val = Fmemq (sym, target->plist);
110
111 if (NILP (val))
112 {
113 o = Fcdr (o);
114 val = Fcar (o);
115 target->plist = Fcons (sym, Fcons (val, target->plist));
116 o = Fcdr (o);
117 }
118 else
119 o = Fcdr (Fcdr (o));
120 }
121}
122
123/* Return 1 if the two intervals have the same properties,
124 0 otherwise. */
125
126int
127intervals_equal (i0, i1)
128 INTERVAL i0, i1;
129{
130 register Lisp_Object i0_cdr, i0_sym, i1_val;
131 register i1_len;
132
133 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
134 return 1;
135
136 i1_len = XFASTINT (Flength (i1->plist));
137 if (i1_len & 0x1) /* Paranoia -- plists are always even */
138 abort ();
139 i1_len /= 2;
140 i0_cdr = i0->plist;
141 while (!NILP (i0_cdr))
142 {
143 /* Lengths of the two plists were unequal */
144 if (i1_len == 0)
145 return 0;
146
147 i0_sym = Fcar (i0_cdr);
148 i1_val = Fmemq (i0_sym, i1->plist);
149
150 /* i0 has something i1 doesn't */
151 if (EQ (i1_val, Qnil))
152 return 0;
153
154 /* i0 and i1 both have sym, but it has different values in each */
155 i0_cdr = Fcdr (i0_cdr);
156 if (! Fequal (i1_val, Fcar (i0_cdr)))
157 return 0;
158
159 i0_cdr = Fcdr (i0_cdr);
160 i1_len--;
161 }
162
163 /* Lengths of the two plists were unequal */
164 if (i1_len > 0)
165 return 0;
166
167 return 1;
168}
169\f
170static int icount;
171static int idepth;
172static int zero_length;
173
174static int depth;
175
176/* Traverse an interval tree TREE, performing FUNCTION on each node.
177
178 Perhaps we should pass the depth as an argument. */
179
180void
181traverse_intervals (tree, position, function)
182 INTERVAL tree;
183 int position;
184 void (* function) ();
185{
186 if (NULL_INTERVAL_P (tree))
187 return;
188
189 depth++;
190 traverse_intervals (tree->left, position, function);
191 position += LEFT_TOTAL_LENGTH (tree);
192 tree->position = position;
193 (*function) (tree);
194 position += LENGTH (tree);
195 traverse_intervals (tree->right, position, function);
196 depth--;
197}
198\f
199#if 0
200/* These functions are temporary, for debugging purposes only. */
201
202INTERVAL search_interval, found_interval;
203
204void
205check_for_interval (i)
206 register INTERVAL i;
207{
208 if (i == search_interval)
209 {
210 found_interval = i;
211 icount++;
212 }
213}
214
215INTERVAL
216search_for_interval (i, tree)
217 register INTERVAL i, tree;
218{
219 icount = 0;
220 search_interval = i;
221 found_interval = NULL_INTERVAL;
222 traverse_intervals (tree, 1, &check_for_interval);
223 return found_interval;
224}
225
226static void
227inc_interval_count (i)
228 INTERVAL i;
229{
230 icount++;
231 if (LENGTH (i) == 0)
232 zero_length++;
233 if (depth > idepth)
234 idepth = depth;
235}
236
237int
238count_intervals (i)
239 register INTERVAL i;
240{
241 icount = 0;
242 idepth = 0;
243 zero_length = 0;
244 traverse_intervals (i, 1, &inc_interval_count);
245
246 return icount;
247}
248
249static INTERVAL
250root_interval (interval)
251 INTERVAL interval;
252{
253 register INTERVAL i = interval;
254
255 while (! ROOT_INTERVAL_P (i))
256 i = i->parent;
257
258 return i;
259}
260#endif
261\f
262/* Assuming that a left child exists, perform the following operation:
263
264 A B
265 / \ / \
266 B => A
267 / \ / \
268 c c
269*/
270
271static INTERVAL
272rotate_right (interval)
273 INTERVAL interval;
274{
275 INTERVAL i;
276 INTERVAL B = interval->left;
277 int len = LENGTH (interval);
278
279 /* Deal with any Parent of A; make it point to B. */
280 if (! ROOT_INTERVAL_P (interval))
281 if (AM_LEFT_CHILD (interval))
282 interval->parent->left = interval->left;
283 else
284 interval->parent->right = interval->left;
285 interval->left->parent = interval->parent;
286
287 /* B gets the same length as A, since it get A's position in the tree. */
288 interval->left->total_length = interval->total_length;
289
290 /* B becomes the parent of A. */
291 i = interval->left->right;
292 interval->left->right = interval;
293 interval->parent = interval->left;
294
295 /* A gets c as left child. */
296 interval->left = i;
297 if (! NULL_INTERVAL_P (i))
298 i->parent = interval;
299 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
300 + RIGHT_TOTAL_LENGTH (interval));
301
302 return B;
303}
304\f
305/* Assuming that a right child exists, perform the following operation:
306
307 A B
308 / \ / \
309 B => A
310 / \ / \
311 c c
312*/
313
314static INTERVAL
315rotate_left (interval)
316 INTERVAL interval;
317{
318 INTERVAL i;
319 INTERVAL B = interval->right;
320 int len = LENGTH (interval);
321
322 /* Deal with the parent of A. */
323 if (! ROOT_INTERVAL_P (interval))
324 if (AM_LEFT_CHILD (interval))
325 interval->parent->left = interval->right;
326 else
327 interval->parent->right = interval->right;
328 interval->right->parent = interval->parent;
329
330 /* B must have the same total length of A. */
331 interval->right->total_length = interval->total_length;
332
333 /* Make B the parent of A */
334 i = interval->right->left;
335 interval->right->left = interval;
336 interval->parent = interval->right;
337
338 /* Make A point to c */
339 interval->right = i;
340 if (! NULL_INTERVAL_P (i))
341 i->parent = interval;
342 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
343 + RIGHT_TOTAL_LENGTH (interval));
344
345 return B;
346}
347\f
90ba40fc
JA
348/* Split INTERVAL into two pieces, starting the second piece at character
349 position OFFSET (counting from 1), relative to INTERVAL. The right-hand
350 piece (second, lexicographically) is returned.
351
352 The size and position fields of the two intervals are set based upon
353 those of the original interval. The property list of the new interval
354 is reset, thus it is up to the caller to do the right thing with the
355 result.
a50699fd
JA
356
357 Note that this does not change the position of INTERVAL; if it is a root,
358 it is still a root after this operation. */
359
360INTERVAL
90ba40fc 361split_interval_right (interval, offset)
a50699fd 362 INTERVAL interval;
90ba40fc 363 int offset;
a50699fd
JA
364{
365 INTERVAL new = make_interval ();
366 int position = interval->position;
90ba40fc 367 int new_length = LENGTH (interval) - offset + 1;
a50699fd 368
90ba40fc 369 new->position = position + offset - 1;
a50699fd 370 new->parent = interval;
a50699fd
JA
371
372 if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval))
373 {
374 interval->right = new;
375 new->total_length = new_length;
376
377 return new;
378 }
379
380 /* Insert the new node between INTERVAL and its right child. */
381 new->right = interval->right;
382 interval->right->parent = new;
383 interval->right = new;
384
385 new->total_length = new_length + new->right->total_length;
386
387 return new;
388}
389
90ba40fc
JA
390/* Split INTERVAL into two pieces, starting the second piece at character
391 position OFFSET (counting from 1), relative to INTERVAL. The left-hand
392 piece (first, lexicographically) is returned.
a50699fd 393
90ba40fc
JA
394 The size and position fields of the two intervals are set based upon
395 those of the original interval. The property list of the new interval
396 is reset, thus it is up to the caller to do the right thing with the
397 result.
398
399 Note that this does not change the position of INTERVAL; if it is a root,
400 it is still a root after this operation. */
a50699fd
JA
401
402INTERVAL
90ba40fc 403split_interval_left (interval, offset)
a50699fd 404 INTERVAL interval;
90ba40fc 405 int offset;
a50699fd
JA
406{
407 INTERVAL new = make_interval ();
408 int position = interval->position;
90ba40fc 409 int new_length = offset - 1;
a50699fd 410
a50699fd 411 new->position = interval->position;
90ba40fc 412 interval->position = interval->position + offset - 1;
a50699fd
JA
413 new->parent = interval;
414
415 if (NULL_LEFT_CHILD (interval))
416 {
417 interval->left = new;
418 new->total_length = new_length;
419
420 return new;
421 }
422
423 /* Insert the new node between INTERVAL and its left child. */
424 new->left = interval->left;
425 new->left->parent = new;
426 interval->left = new;
427 new->total_length = LENGTH (new) + LEFT_TOTAL_LENGTH (new);
428
429 return new;
430}
431\f
90ba40fc
JA
432/* Find the interval containing text position POSITION in the text
433 represented by the interval tree TREE. POSITION is relative to
434 the beginning of that text.
a50699fd 435
90ba40fc
JA
436 The `position' field, which is a cache of an interval's position,
437 is updated in the interval found. Other functions (e.g., next_interval)
438 will update this cache based on the result of find_interval. */
439
440INLINE INTERVAL
a50699fd
JA
441find_interval (tree, position)
442 register INTERVAL tree;
443 register int position;
444{
445 register int relative_position = position;
446
447 if (NULL_INTERVAL_P (tree))
448 return NULL_INTERVAL;
449
450 if (position > TOTAL_LENGTH (tree))
451 abort (); /* Paranoia */
452#if 0
453 position = TOTAL_LENGTH (tree);
454#endif
455
456 while (1)
457 {
458 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
459 {
460 tree = tree->left;
461 }
462 else if (relative_position > (TOTAL_LENGTH (tree)
463 - RIGHT_TOTAL_LENGTH (tree)))
464 {
465 relative_position -= (TOTAL_LENGTH (tree)
466 - RIGHT_TOTAL_LENGTH (tree));
467 tree = tree->right;
468 }
469 else
470 {
471 tree->position = LEFT_TOTAL_LENGTH (tree)
472 + position - relative_position + 1;
473 return tree;
474 }
475 }
476}
477\f
478/* Find the succeeding interval (lexicographically) to INTERVAL.
90ba40fc
JA
479 Sets the `position' field based on that of INTERVAL (see
480 find_interval). */
a50699fd
JA
481
482INTERVAL
483next_interval (interval)
484 register INTERVAL interval;
485{
486 register INTERVAL i = interval;
487 register int next_position;
488
489 if (NULL_INTERVAL_P (i))
490 return NULL_INTERVAL;
491 next_position = interval->position + LENGTH (interval);
492
493 if (! NULL_RIGHT_CHILD (i))
494 {
495 i = i->right;
496 while (! NULL_LEFT_CHILD (i))
497 i = i->left;
498
499 i->position = next_position;
500 return i;
501 }
502
503 while (! NULL_PARENT (i))
504 {
505 if (AM_LEFT_CHILD (i))
506 {
507 i = i->parent;
508 i->position = next_position;
509 return i;
510 }
511
512 i = i->parent;
513 }
514
515 return NULL_INTERVAL;
516}
517
518/* Find the preceding interval (lexicographically) to INTERVAL.
90ba40fc
JA
519 Sets the `position' field based on that of INTERVAL (see
520 find_interval). */
a50699fd
JA
521
522INTERVAL
523previous_interval (interval)
524 register INTERVAL interval;
525{
526 register INTERVAL i;
527 register position_of_previous;
528
529 if (NULL_INTERVAL_P (interval))
530 return NULL_INTERVAL;
531
532 if (! NULL_LEFT_CHILD (interval))
533 {
534 i = interval->left;
535 while (! NULL_RIGHT_CHILD (i))
536 i = i->right;
537
538 i->position = interval->position - LENGTH (i);
539 return i;
540 }
541
542 i = interval;
543 while (! NULL_PARENT (i))
544 {
545 if (AM_RIGHT_CHILD (i))
546 {
547 i = i->parent;
548
549 i->position = interval->position - LENGTH (i);
550 return i;
551 }
552 i = i->parent;
553 }
554
555 return NULL_INTERVAL;
556}
557\f
90ba40fc 558#if 0
a50699fd
JA
559/* Traverse a path down the interval tree TREE to the interval
560 containing POSITION, adjusting all nodes on the path for
561 an addition of LENGTH characters. Insertion between two intervals
562 (i.e., point == i->position, where i is second interval) means
563 text goes into second interval.
564
565 Modifications are needed to handle the hungry bits -- after simply
566 finding the interval at position (don't add length going down),
567 if it's the beginning of the interval, get the previous interval
568 and check the hugry bits of both. Then add the length going back up
569 to the root. */
570
571static INTERVAL
572adjust_intervals_for_insertion (tree, position, length)
573 INTERVAL tree;
574 int position, length;
575{
576 register int relative_position;
577 register INTERVAL this;
578
579 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
580 abort ();
581
582 /* If inserting at point-max of a buffer, that position
583 will be out of range */
584 if (position > TOTAL_LENGTH (tree))
585 position = TOTAL_LENGTH (tree);
586 relative_position = position;
587 this = tree;
588
589 while (1)
590 {
591 if (relative_position <= LEFT_TOTAL_LENGTH (this))
592 {
593 this->total_length += length;
594 this = this->left;
595 }
596 else if (relative_position > (TOTAL_LENGTH (this)
597 - RIGHT_TOTAL_LENGTH (this)))
598 {
599 relative_position -= (TOTAL_LENGTH (this)
600 - RIGHT_TOTAL_LENGTH (this));
601 this->total_length += length;
602 this = this->right;
603 }
604 else
605 {
606 /* If we are to use zero-length intervals as buffer pointers,
607 then this code will have to change. */
608 this->total_length += length;
609 this->position = LEFT_TOTAL_LENGTH (this)
610 + position - relative_position + 1;
611 return tree;
612 }
613 }
614}
90ba40fc
JA
615#endif
616
617/* Effect an adjustment corresponding to the addition of LENGTH characters
618 of text. Do this by finding the interval containing POSITION in the
619 interval tree TREE, and then adjusting all of it's ancestors by adding
620 LENGTH to them.
621
622 If POSITION is the first character of an interval, meaning that point
623 is actually between the two intervals, make the new text belong to
624 the interval which is "sticky".
625
1d1d7ba0 626 If both intervals are "sticky", then make them belong to the left-most
90ba40fc
JA
627 interval. Another possibility would be to create a new interval for
628 this text, and make it have the merged properties of both ends. */
629
630static INTERVAL
631adjust_intervals_for_insertion (tree, position, length)
632 INTERVAL tree;
633 int position, length;
634{
635 register INTERVAL i;
636
637 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
638 abort ();
639
640 /* If inserting at point-max of a buffer, that position
641 will be out of range. */
642 if (position > TOTAL_LENGTH (tree))
643 position = TOTAL_LENGTH (tree);
644
645 i = find_interval (tree, position);
646 /* If we are positioned between intervals, check the stickiness of
647 both of them. */
648 if (position == i->position
649 && position != 1)
650 {
651 register prev = previous_interval (i);
652
653 /* If both intervals are sticky here, then default to the
654 left-most one. But perhaps we should create a new
655 interval here instead... */
656 if (END_STICKY (prev))
657 i = prev;
658 }
659
660 while (! NULL_INTERVAL_P (i))
661 {
662 i->total_length += length;
663 i = i->parent
664 }
665
666 return tree;
667}
a50699fd 668\f
90ba40fc
JA
669/* Delete an node I from its interval tree by merging its subtrees
670 into one subtree which is then returned. Caller is responsible for
a50699fd
JA
671 storing the resulting subtree into its parent. */
672
673static INTERVAL
674delete_node (i)
675 register INTERVAL i;
676{
677 register INTERVAL migrate, this;
678 register int migrate_amt;
679
680 if (NULL_INTERVAL_P (i->left))
681 return i->right;
682 if (NULL_INTERVAL_P (i->right))
683 return i->left;
684
685 migrate = i->left;
686 migrate_amt = i->left->total_length;
687 this = i->right;
688 this->total_length += migrate_amt;
689 while (! NULL_INTERVAL_P (this->left))
690 {
691 this = this->left;
692 this->total_length += migrate_amt;
693 }
694 this->left = migrate;
695 migrate->parent = this;
696
697 return i->right;
698}
699
700/* Delete interval I from its tree by calling `delete_node'
701 and properly connecting the resultant subtree.
702
703 I is presumed to be empty; that is, no adjustments are made
704 for the length of I. */
705
706void
707delete_interval (i)
708 register INTERVAL i;
709{
710 register INTERVAL parent;
711 int amt = LENGTH (i);
712
713 if (amt > 0) /* Only used on zero-length intervals now. */
714 abort ();
715
716 if (ROOT_INTERVAL_P (i))
717 {
718 Lisp_Object owner = (Lisp_Object) i->parent;
719 parent = delete_node (i);
720 if (! NULL_INTERVAL_P (parent))
721 parent->parent = (INTERVAL) owner;
722
723 if (XTYPE (owner) == Lisp_Buffer)
724 XBUFFER (owner)->intervals = parent;
725 else if (XTYPE (owner) == Lisp_String)
726 XSTRING (owner)->intervals = parent;
727 else
728 abort ();
729
730 return;
731 }
732
733 parent = i->parent;
734 if (AM_LEFT_CHILD (i))
735 {
736 parent->left = delete_node (i);
737 if (! NULL_INTERVAL_P (parent->left))
738 parent->left->parent = parent;
739 }
740 else
741 {
742 parent->right = delete_node (i);
743 if (! NULL_INTERVAL_P (parent->right))
744 parent->right->parent = parent;
745 }
746}
747\f
1d1d7ba0
JA
748/* Find the interval in TREE corresponding to the character position FROM
749 and delete as much as possible of AMOUNT from that interval, starting
750 after the relative position of FROM within it. Return the amount
751 actually deleted, and if the interval was zeroed-out, delete that
752 interval node from the tree.
a50699fd 753
1d1d7ba0
JA
754 Do this by recursing down TREE to the interval in question, and
755 deleting the appropriate amount of text. */
a50699fd
JA
756
757static int
758interval_deletion_adjustment (tree, from, amount)
759 register INTERVAL tree;
760 register int from, amount;
761{
762 register int relative_position = from;
763
764 if (NULL_INTERVAL_P (tree))
765 return 0;
766
767 /* Left branch */
768 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
769 {
770 int subtract = interval_deletion_adjustment (tree->left,
771 relative_position,
772 amount);
773 tree->total_length -= subtract;
774 return subtract;
775 }
776 /* Right branch */
777 else if (relative_position > (TOTAL_LENGTH (tree)
778 - RIGHT_TOTAL_LENGTH (tree)))
779 {
780 int subtract;
781
782 relative_position -= (tree->total_length
783 - RIGHT_TOTAL_LENGTH (tree));
784 subtract = interval_deletion_adjustment (tree->right,
785 relative_position,
786 amount);
787 tree->total_length -= subtract;
788 return subtract;
789 }
790 /* Here -- this node */
791 else
792 {
793 /* If this is a zero-length, marker interval, then
794 we must skip it. */
795
796 if (relative_position == LEFT_TOTAL_LENGTH (tree) + 1)
797 {
798 /* This means we're deleting from the beginning of this interval. */
799 register int my_amount = LENGTH (tree);
800
801 if (amount < my_amount)
802 {
803 tree->total_length -= amount;
804 return amount;
805 }
806 else
807 {
808 tree->total_length -= my_amount;
809 if (LENGTH (tree) != 0)
810 abort (); /* Paranoia */
811
812 delete_interval (tree);
813 return my_amount;
814 }
815 }
816 else /* Deleting starting in the middle. */
817 {
818 register int my_amount = ((tree->total_length
819 - RIGHT_TOTAL_LENGTH (tree))
820 - relative_position + 1);
821
822 if (amount <= my_amount)
823 {
824 tree->total_length -= amount;
825 return amount;
826 }
827 else
828 {
829 tree->total_length -= my_amount;
830 return my_amount;
831 }
832 }
833 }
834
1d1d7ba0 835 /* Never reach here */
a50699fd
JA
836 abort ();
837}
838
1d1d7ba0
JA
839/* Effect the adjustments neccessary to the interval tree of BUFFER
840 to correspond to the deletion of LENGTH characters from that buffer
841 text. The deletion is effected at position START (relative to the
842 buffer). */
843
a50699fd
JA
844static void
845adjust_intervals_for_deletion (buffer, start, length)
846 struct buffer *buffer;
847 int start, length;
848{
849 register int left_to_delete = length;
850 register INTERVAL tree = buffer->intervals;
851 register int deleted;
852
853 if (NULL_INTERVAL_P (tree))
854 return;
855
856 if (length == TOTAL_LENGTH (tree))
857 {
858 buffer->intervals = NULL_INTERVAL;
859 return;
860 }
861
862 if (ONLY_INTERVAL_P (tree))
863 {
864 tree->total_length -= length;
865 return;
866 }
867
868 if (start > TOTAL_LENGTH (tree))
869 start = TOTAL_LENGTH (tree);
870 while (left_to_delete > 0)
871 {
872 left_to_delete -= interval_deletion_adjustment (tree, start,
873 left_to_delete);
874 tree = buffer->intervals;
875 if (left_to_delete == tree->total_length)
876 {
877 buffer->intervals = NULL_INTERVAL;
878 return;
879 }
880 }
881}
882\f
1d1d7ba0
JA
883/* Make the adjustments neccessary to the interval tree of BUFFER to
884 represent an addition or deletion of LENGTH characters starting
885 at position START. Addition or deletion is indicated by the sign
886 of LENGTH. */
a50699fd
JA
887
888INLINE void
889offset_intervals (buffer, start, length)
890 struct buffer *buffer;
891 int start, length;
892{
893 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
894 return;
895
896 if (length > 0)
897 adjust_intervals_for_insertion (buffer->intervals, start, length);
898 else
899 adjust_intervals_for_deletion (buffer, start, -length);
900}
9c79dd1b
JA
901\f
902/* Merge interval I with its lexicographic successor. The resulting
903 interval is returned, and has the properties of the original
904 successor. The properties of I are lost. I is removed from the
905 interval tree.
906
907 IMPORTANT:
908 The caller must verify that this is not the last (rightmost)
909 interval. */
910
911INTERVAL
912merge_interval_right (i)
913 register INTERVAL i;
914{
915 register int absorb = LENGTH (i);
916 register INTERVAL successor;
917
918 /* Zero out this interval. */
919 i->total_length -= absorb;
920
921 /* Find the succeeding interval. */
922 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
923 as we descend. */
924 {
925 successor = i->right;
926 while (! NULL_LEFT_CHILD (successor))
927 {
928 successor->total_length += absorb;
929 successor = successor->left;
930 }
931
932 successor->total_length += absorb;
933 delete_interval (i);
934 return successor;
935 }
936
937 successor = i;
938 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
939 we ascend. */
940 {
941 if (AM_LEFT_CHILD (successor))
942 {
943 successor = successor->parent;
944 delete_interval (i);
945 return successor;
946 }
947
948 successor = successor->parent;
949 successor->total_length -= absorb;
950 }
951
952 /* This must be the rightmost or last interval and cannot
953 be merged right. The caller should have known. */
954 abort ();
955}
956\f
957/* Merge interval I with its lexicographic predecessor. The resulting
958 interval is returned, and has the properties of the original predecessor.
959 The properties of I are lost. Interval node I is removed from the tree.
960
961 IMPORTANT:
962 The caller must verify that this is not the first (leftmost) interval. */
963
964INTERVAL
965merge_interval_left (i)
966 register INTERVAL i;
967{
968 register int absorb = LENGTH (i);
969 register INTERVAL predecessor;
970
971 /* Zero out this interval. */
972 i->total_length -= absorb;
973
974 /* Find the preceding interval. */
975 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
976 adding ABSORB as we go. */
977 {
978 predecessor = i->left;
979 while (! NULL_RIGHT_CHILD (predecessor))
980 {
981 predecessor->total_length += absorb;
982 predecessor = predecessor->right;
983 }
984
985 predecessor->total_length += absorb;
986 delete_interval (i);
987 return predecessor;
988 }
989
990 predecessor = i;
991 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
992 subtracting ABSORB. */
993 {
994 if (AM_RIGHT_CHILD (predecessor))
995 {
996 predecessor = predecessor->parent;
997 delete_interval (i);
998 return predecessor;
999 }
1000
1001 predecessor = predecessor->parent;
1002 predecessor->total_length -= absorb;
1003 }
a50699fd 1004
9c79dd1b
JA
1005 /* This must be the leftmost or first interval and cannot
1006 be merged left. The caller should have known. */
1007 abort ();
1008}
1009\f
1d1d7ba0
JA
1010/* Make an exact copy of interval tree SOURCE which descends from
1011 PARENT. This is done by recursing through SOURCE, copying
1012 the current interval and its properties, and then adjusting
1013 the pointers of the copy. */
1014
a50699fd
JA
1015static INTERVAL
1016reproduce_tree (source, parent)
1017 INTERVAL source, parent;
1018{
1019 register INTERVAL t = make_interval ();
1020
1021 bcopy (source, t, INTERVAL_SIZE);
1022 copy_properties (source, t);
1023 t->parent = parent;
1024 if (! NULL_LEFT_CHILD (source))
1025 t->left = reproduce_tree (source->left, t);
1026 if (! NULL_RIGHT_CHILD (source))
1027 t->right = reproduce_tree (source->right, t);
1028
1029 return t;
1030}
1031
1d1d7ba0
JA
1032/* Make a new interval of length LENGTH starting at START in the
1033 group of intervals INTERVALS, which is actually an interval tree.
1034 Returns the new interval.
1035
1036 Generate an error if the new positions would overlap an existing
1037 interval. */
1038
a50699fd
JA
1039static INTERVAL
1040make_new_interval (intervals, start, length)
1041 INTERVAL intervals;
1042 int start, length;
1043{
1044 INTERVAL slot;
1045
1046 slot = find_interval (intervals, start);
1047 if (start + length > slot->position + LENGTH (slot))
1048 error ("Interval would overlap");
1049
1050 if (start == slot->position && length == LENGTH (slot))
1051 return slot;
1052
1053 if (slot->position == start)
1054 {
1055 /* New right node. */
1056 split_interval_right (slot, length + 1);
1057 return slot;
1058 }
1059
1060 if (slot->position + LENGTH (slot) == start + length)
1061 {
1062 /* New left node. */
1063 split_interval_left (slot, LENGTH (slot) - length + 1);
1064 return slot;
1065 }
1066
1067 /* Convert interval SLOT into three intervals. */
1068 split_interval_left (slot, start - slot->position + 1);
1069 split_interval_right (slot, length + 1);
1070 return slot;
1071}
1072
9c79dd1b 1073/* Insert the intervals of SOURCE into BUFFER at POSITION.
a50699fd
JA
1074
1075 This is used in insdel.c when inserting Lisp_Strings into
9c79dd1b 1076 the buffer. The text corresponding to SOURCE is already in
a50699fd
JA
1077 the buffer when this is called. The intervals of new tree are
1078 those belonging to the string being inserted; a copy is not made.
1079
1080 If the inserted text had no intervals associated, this function
1081 simply returns -- offset_intervals should handle placing the
90ba40fc 1082 text in the correct interval, depending on the sticky bits.
a50699fd
JA
1083
1084 If the inserted text had properties (intervals), then there are two
1085 cases -- either insertion happened in the middle of some interval,
1086 or between two intervals.
1087
1088 If the text goes into the middle of an interval, then new
1089 intervals are created in the middle with only the properties of
1090 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1091 which case the new text has the union of its properties and those
1092 of the text into which it was inserted.
1093
1094 If the text goes between two intervals, then if neither interval
90ba40fc
JA
1095 had its appropriate sticky property set (front_sticky, rear_sticky),
1096 the new text has only its properties. If one of the sticky properties
a50699fd
JA
1097 is set, then the new text "sticks" to that region and its properties
1098 depend on merging as above. If both the preceding and succeding
90ba40fc
JA
1099 intervals to the new text are "sticky", then the new text retains
1100 only its properties, as if neither sticky property were set. Perhaps
a50699fd
JA
1101 we should consider merging all three sets of properties onto the new
1102 text... */
1103
1104void
9c79dd1b
JA
1105graft_intervals_into_buffer (source, position, buffer)
1106 INTERVAL source;
a50699fd 1107 int position;
9c79dd1b 1108 struct buffer *buffer;
a50699fd
JA
1109{
1110 register INTERVAL under, over, this;
9c79dd1b 1111 register INTERVAL tree = buffer->intervals;
a50699fd
JA
1112
1113 /* If the new text has no properties, it becomes part of whatever
1114 interval it was inserted into. */
9c79dd1b 1115 if (NULL_INTERVAL_P (source))
a50699fd
JA
1116 return;
1117
1118 /* Paranoia -- the text has already been added, so this buffer
1119 should be of non-zero length. */
1120 if (TOTAL_LENGTH (tree) == 0)
1121 abort ();
1122
1123 if (NULL_INTERVAL_P (tree))
1124 {
1125 /* The inserted text constitutes the whole buffer, so
1126 simply copy over the interval structure. */
9c79dd1b 1127 if (BUF_Z (b) == TOTAL_LENGTH (source))
a50699fd 1128 {
9c79dd1b 1129 buffer->intervals = reproduce_tree (source, tree->parent);
a50699fd
JA
1130 /* Explicitly free the old tree here. */
1131
1132 return;
1133 }
1134
1135 /* Create an interval tree in which to place a copy
1136 of the intervals of the inserted string. */
1137 {
1138 Lisp_Object buffer;
1139 XSET (buffer, Lisp_Buffer, b);
1140 create_root_interval (buffer);
1141 }
1142 }
1143 else
9c79dd1b 1144 if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
a50699fd
JA
1145
1146 /* If the buffer contains only the new string, but
1147 there was already some interval tree there, then it may be
1148 some zero length intervals. Eventually, do something clever
1149 about inserting properly. For now, just waste the old intervals. */
1150 {
9c79dd1b 1151 buffer->intervals = reproduce_tree (source, tree->parent);
a50699fd
JA
1152 /* Explicitly free the old tree here. */
1153
1154 return;
1155 }
1156
1157 this = under = find_interval (tree, position);
1158 if (NULL_INTERVAL_P (under)) /* Paranoia */
1159 abort ();
9c79dd1b 1160 over = find_interval (source, 1);
a50699fd
JA
1161
1162 /* Insertion between intervals */
1163 if (position == under->position)
1164 {
1165 /* First interval -- none precede it. */
1166 if (position == 1)
1167 {
90ba40fc 1168 if (! FRONT_STICKY (under))
a50699fd
JA
1169 /* The inserted string keeps its own properties. */
1170 while (! NULL_INTERVAL_P (over))
1171 {
1172 position = LENGTH (over) + 1;
1173 this = split_interval_left (this, position);
1174 copy_properties (over, this);
1175 over = next_interval (over);
1176 }
1177 else
9c79dd1b
JA
1178 /* This string "sticks" to the first interval, `under',
1179 which means it gets those properties. */
a50699fd
JA
1180 while (! NULL_INTERVAL_P (over))
1181 {
1182 position = LENGTH (over) + 1;
1183 this = split_interval_left (this, position);
1184 copy_properties (under, this);
1185 if (MERGE_INSERTIONS (under))
1186 merge_properties (over, this);
1187 over = next_interval (over);
1188 }
1189 }
1190 else
1191 {
1192 INTERVAL prev = previous_interval (under);
1193 if (NULL_INTERVAL_P (prev))
1194 abort ();
1195
90ba40fc 1196 if (END_STICKY (prev))
a50699fd 1197 {
90ba40fc
JA
1198 if (FRONT_STICKY (under))
1199 /* The intervals go inbetween as the two sticky
a50699fd
JA
1200 properties cancel each other. Should we change
1201 this policy? */
1202 while (! NULL_INTERVAL_P (over))
1203 {
1204 position = LENGTH (over) + 1;
1205 this = split_interval_left (this, position);
1206 copy_properties (over, this);
1207 over = next_interval (over);
1208 }
1209 else
1210 /* The intervals stick to prev */
1211 while (! NULL_INTERVAL_P (over))
1212 {
1213 position = LENGTH (over) + 1;
1214 this = split_interval_left (this, position);
1215 copy_properties (prev, this);
1216 if (MERGE_INSERTIONS (prev))
1217 merge_properties (over, this);
1218 over = next_interval (over);
1219 }
1220 }
1221 else
1222 {
90ba40fc 1223 if (FRONT_STICKY (under))
9c79dd1b
JA
1224 /* The inserted text "sticks" to the interval `under',
1225 which means it gets those properties. */
a50699fd
JA
1226 while (! NULL_INTERVAL_P (over))
1227 {
1228 position = LENGTH (over) + 1;
1229 this = split_interval_left (this, position);
1230 copy_properties (under, this);
1231 if (MERGE_INSERTIONS (under))
1232 merge_properties (over, this);
1233 over = next_interval (over);
1234 }
1235 else
1236 /* The intervals go inbetween */
1237 while (! NULL_INTERVAL_P (over))
1238 {
1239 position = LENGTH (over) + 1;
1240 this = split_interval_left (this, position);
1241 copy_properties (over, this);
1242 over = next_interval (over);
1243 }
1244 }
1245 }
1246
9c79dd1b 1247 buffer->intervals = balance_intervals (buffer->intervals);
a50699fd
JA
1248 return;
1249 }
1250
1251 /* Here for insertion in the middle of an interval. */
1252
9c79dd1b 1253 if (TOTAL_LENGTH (source) < LENGTH (this))
a50699fd
JA
1254 {
1255 INTERVAL end_unchanged
9c79dd1b 1256 = split_interval_right (this, TOTAL_LENGTH (source) + 1);
a50699fd
JA
1257 copy_properties (under, end_unchanged);
1258 }
1259
1260 position = position - tree->position + 1;
1261 while (! NULL_INTERVAL_P (over))
1262 {
1263 this = split_interval_right (under, position);
1264 copy_properties (over, this);
1265 if (MERGE_INSERTIONS (under))
1266 merge_properties (under, this);
1267
1268 position = LENGTH (over) + 1;
1269 over = next_interval (over);
1270 }
1271
9c79dd1b 1272 buffer->intervals = balance_intervals (buffer->intervals);
a50699fd
JA
1273 return;
1274}
1275
a50699fd
JA
1276/* Set point in BUFFER to POSITION. If the target position is in
1277 an invisible interval which is not displayed with a special glyph,
1278 skip intervals until we find one. Point may be at the first
1279 position of an invisible interval, if it is displayed with a
d7e3e52b 1280 special glyph. */
a50699fd
JA
1281
1282void
1283set_point (position, buffer)
1284 register int position;
1285 register struct buffer *buffer;
1286{
1287 register INTERVAL to, from, target;
1288 register int iposition = position;
1289 int buffer_point;
1290 register Lisp_Object obj;
1291 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
9c79dd1b 1292 int old_position = buffer->text.pt;
a50699fd
JA
1293
1294 if (position == buffer->text.pt)
1295 return;
1296
1297 if (NULL_INTERVAL_P (buffer->intervals))
1298 {
1299 buffer->text.pt = position;
1300 return;
1301 }
1302
1303 /* Perhaps we should just change `position' to the limit. */
1304 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1305 abort ();
1306
1307 /* Position Z is really one past the last char in the buffer. */
1308 if (position == BUF_Z (buffer))
1309 iposition = position - 1;
1310
1311 to = find_interval (buffer->intervals, iposition);
1312 buffer_point =(BUF_PT (buffer) == BUF_Z (buffer)
1313 ? BUF_Z (buffer) - 1
1314 : BUF_PT (buffer));
9c79dd1b
JA
1315
1316 /* We could cache this and save time. */
a50699fd 1317 from = find_interval (buffer->intervals, buffer_point);
9c79dd1b 1318
a50699fd
JA
1319 if (NULL_INTERVAL_P (to) || NULL_INTERVAL_P (from))
1320 abort (); /* Paranoia */
1321
1322 /* Moving within an interval */
1323 if (to == from && INTERVAL_VISIBLE_P (to))
1324 {
1325 buffer->text.pt = position;
1326 return;
1327 }
1328
1329 /* Here for the case of moving into another interval. */
1330
1331 target = to;
1332 while (! INTERVAL_VISIBLE_P (to) && ! DISPLAY_INVISIBLE_GLYPH (to)
1333 && ! NULL_INTERVAL_P (to))
1334 to = (backwards ? previous_interval (to) : next_interval (to));
1335 if (NULL_INTERVAL_P (to))
1336 return;
1337
1338 /* Here we know we are actually moving to another interval. */
1339 if (INTERVAL_VISIBLE_P (to))
1340 {
1341 /* If we skipped some intervals, go to the closest point
1342 in the interval we've stopped at. */
1343 if (to != target)
1344 buffer->text.pt = (backwards
1345 ? to->position + LENGTH (to) - 1
1346 : to->position);
1347 else
1348 buffer->text.pt = position;
1349 }
1350 else
1351 buffer->text.pt = to->position;
1352
d7e3e52b
JA
1353 /* We run point-left and point-entered hooks here, iff the
1354 two intervals are not equivalent. These hooks take
1355 (old_point, new_point) as arguments. */
9c79dd1b
JA
1356 if (! intervals_equal (from, to))
1357 {
1358 Lisp_Object val;
1359
1360 val = Fget (Qpoint_left, from->plist);
1361 if (! NILP (val))
1362 call2 (val, old_position, position);
1363
1364 val = Fget (Qpoint_entered, to->plist);
1365 if (! NILP (val))
1366 call2 (val, old_position, position);
1367 }
a50699fd
JA
1368}
1369
9c79dd1b 1370/* Set point temporarily, without checking any text properties. */
a50699fd 1371
9c79dd1b
JA
1372INLINE void
1373temp_set_point (position, buffer)
1374 int position;
1375 struct buffer *buffer;
1376{
1377 buffer->text.pt = position;
1378}
1379
1380/* Check for read-only intervals and signal an error if we find one.
1381 Then check for any modification hooks in the range START up to
1382 (but not including) TO. Create a list of all these hooks in
1383 lexicographic order, eliminating consecutive extra copies of the
1384 same hook. Then call those hooks in order, with START and END - 1
1385 as arguments. */
a50699fd
JA
1386
1387void
1388verify_interval_modification (buf, start, end)
1389 struct buffer *buf;
1390 int start, end;
1391{
1392 register INTERVAL intervals = buf->intervals;
1393 register INTERVAL i;
1394 register Lisp_Object hooks = Qnil;
9c79dd1b
JA
1395 register prev_mod_hook = Qnil;
1396 register Lisp_Object mod_hook;
1397 struct gcpro gcpro1;
a50699fd
JA
1398
1399 if (NULL_INTERVAL_P (intervals))
1400 return;
1401
1402 if (start > end)
1403 {
1404 int temp = start;
1405 start = end;
1406 end = temp;
1407 }
1408
1409 if (start == BUF_Z (buf))
1410 {
9c79dd1b 1411 /* This should not be getting called on empty buffers. */
a50699fd
JA
1412 if (BUF_Z (buf) == 1)
1413 abort ();
1414
1415 i = find_interval (intervals, start - 1);
90ba40fc 1416 if (! END_STICKY_P (i))
a50699fd
JA
1417 return;
1418 }
1419 else
1420 i = find_interval (intervals, start);
1421
1422 do
1423 {
a50699fd 1424 if (! INTERVAL_WRITABLE_P (i))
9c79dd1b
JA
1425 error ("Attempt to modify read-only text");
1426
a50699fd 1427 mod_hook = Fget (Qmodification, i->plist);
9c79dd1b
JA
1428 if (! NILP (mod_hook) && ! EQ (mod_hook, prev_mod_hook))
1429 {
1430 hooks = Fcons (mod_hook, hooks);
1431 prev_mod_hook = mod_hook;
1432 }
1433
a50699fd
JA
1434 i = next_interval (i);
1435 }
1436 while (! NULL_INTERVAL_P (i) && i->position <= end);
1437
9c79dd1b 1438 GCPRO1 (hooks);
a50699fd
JA
1439 hooks = Fnreverse (hooks);
1440 while (! EQ (hooks, Qnil))
9c79dd1b
JA
1441 {
1442 call2 (Fcar (hooks), start, end - 1);
1443 hooks = Fcdr (hooks);
1444 }
1445 UNGCPRO;
a50699fd
JA
1446}
1447
1448/* Balance an interval node if the amount of text in its left and right
1449 subtrees differs by more than the percentage specified by
1450 `interval-balance-threshold'. */
1451
1452static INTERVAL
1453balance_an_interval (i)
1454 INTERVAL i;
1455{
1456 register int total_children_size = (LEFT_TOTAL_LENGTH (i)
1457 + RIGHT_TOTAL_LENGTH (i));
1458 register int threshold = (XFASTINT (interval_balance_threshold)
1459 * (total_children_size / 100));
1460
1461 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1462 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1463 return rotate_right (i);
1464
1465 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1466 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1467 return rotate_right (i);
1468
1469#if 0
1470 if (LEFT_TOTAL_LENGTH (i) >
1471 (RIGHT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1472 return rotate_right (i);
1473
1474 if (RIGHT_TOTAL_LENGTH (i) >
1475 (LEFT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1476 return rotate_left (i);
1477#endif
1478
1479 return i;
1480}
1481
1482/* Balance the interval tree TREE. Balancing is by weight
1483 (the amount of text). */
1484
1485INTERVAL
1486balance_intervals (tree)
1487 register INTERVAL tree;
1488{
1489 register INTERVAL new_tree;
1490
1491 if (NULL_INTERVAL_P (tree))
1492 return NULL_INTERVAL;
1493
1494 new_tree = tree;
1495 do
1496 {
1497 tree = new_tree;
1498 new_tree = balance_an_interval (new_tree);
1499 }
1500 while (new_tree != tree);
1501
1502 return new_tree;
1503}
1504
9c79dd1b 1505/* Produce an interval tree reflecting the intervals in
a50699fd
JA
1506 TREE from START to START + LENGTH. */
1507
1508static INTERVAL
1509copy_intervals (tree, start, length)
1510 INTERVAL tree;
1511 int start, length;
1512{
1513 register INTERVAL i, new, t;
1514 register int got;
1515
1516 if (NULL_INTERVAL_P (tree) || length <= 0)
1517 return NULL_INTERVAL;
1518
1519 i = find_interval (tree, start);
1520 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1521 abort ();
1522
1523 /* If there is only one interval and it's the default, return nil. */
1524 if ((start - i->position + 1 + length) < LENGTH (i)
1525 && DEFAULT_INTERVAL_P (i))
1526 return NULL_INTERVAL;
1527
1528 new = make_interval ();
1529 new->position = 1;
1530 got = (LENGTH (i) - (start - i->position));
9c79dd1b 1531 new->total_length = length;
a50699fd
JA
1532 copy_properties (i, new);
1533
1534 t = new;
1535 while (got < length)
1536 {
1537 i = next_interval (i);
9c79dd1b 1538 t = split_interval_right (t, got + 1);
a50699fd
JA
1539 copy_properties (i, t);
1540 got += LENGTH (i);
1541 }
1542
1543 if (got > length)
1544 t->total_length -= (got - length);
1545
1546 return balance_intervals (new);
1547}
1548
a50699fd
JA
1549/* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1550
d7e3e52b 1551INLINE void
a50699fd
JA
1552copy_intervals_to_string (string, buffer, position, length)
1553 Lisp_Object string, buffer;
1554 int position, length;
1555{
1556 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
1557 position, length);
1558 if (NULL_INTERVAL_P (interval_copy))
1559 return;
1560
1561 interval_copy->parent = (INTERVAL) string;
1562 XSTRING (string)->intervals = interval_copy;
1563}