Initial revision
[emacs.git] / src / intervals.c
blob5f4998789ad2fab734ebdedf8371f5177ee9644c
1 /* Code for doing intervals.
2 Copyright (C) 1993 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21 /* NOTES:
23 Have to ensure that we can't put symbol nil on a plist, or some
24 functions may work incorrectly.
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.
29 Need to call *_left_hook when buffer is killed.
31 Scan for zero-length, or 0-length to see notes about handling
32 zero length interval-markers.
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.
41 #include "config.h"
42 #include "lisp.h"
43 #include "intervals.h"
44 #include "buffer.h"
46 /* The rest of the file is within this conditional. */
47 #ifdef USE_TEXT_PROPERTIES
49 /* Factor for weight-balancing interval trees. */
50 Lisp_Object interval_balance_threshold;
52 /* Utility functions for intervals. */
55 /* Create the root interval of some object, a buffer or string. */
57 INTERVAL
58 create_root_interval (parent)
59 Lisp_Object parent;
61 INTERVAL new = make_interval ();
63 if (XTYPE (parent) == Lisp_Buffer)
65 new->total_length = BUF_Z (XBUFFER (parent)) - 1;
66 XBUFFER (parent)->intervals = new;
68 else if (XTYPE (parent) == Lisp_String)
70 new->total_length = XSTRING (parent)->size;
71 XSTRING (parent)->intervals = new;
74 new->parent = (INTERVAL) parent;
75 new->position = 1;
77 return new;
80 /* Make the interval TARGET have exactly the properties of SOURCE */
82 void
83 copy_properties (source, target)
84 register INTERVAL source, target;
86 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
87 return;
89 COPY_INTERVAL_CACHE (source, target);
90 target->plist = Fcopy_sequence (source->plist);
93 /* Merge the properties of interval SOURCE into the properties
94 of interval TARGET. That is to say, each property in SOURCE
95 is added to TARGET if TARGET has no such property as yet. */
97 static void
98 merge_properties (source, target)
99 register INTERVAL source, target;
101 register Lisp_Object o, sym, val;
103 if (DEFAULT_INTERVAL_P (source) && DEFAULT_INTERVAL_P (target))
104 return;
106 MERGE_INTERVAL_CACHE (source, target);
108 o = source->plist;
109 while (! EQ (o, Qnil))
111 sym = Fcar (o);
112 val = Fmemq (sym, target->plist);
114 if (NILP (val))
116 o = Fcdr (o);
117 val = Fcar (o);
118 target->plist = Fcons (sym, Fcons (val, target->plist));
119 o = Fcdr (o);
121 else
122 o = Fcdr (Fcdr (o));
126 /* Return 1 if the two intervals have the same properties,
127 0 otherwise. */
130 intervals_equal (i0, i1)
131 INTERVAL i0, i1;
133 register Lisp_Object i0_cdr, i0_sym, i1_val;
134 register i1_len;
136 if (DEFAULT_INTERVAL_P (i0) && DEFAULT_INTERVAL_P (i1))
137 return 1;
139 if (DEFAULT_INTERVAL_P (i0) || DEFAULT_INTERVAL_P (i1))
140 return 0;
142 i1_len = XFASTINT (Flength (i1->plist));
143 if (i1_len & 0x1) /* Paranoia -- plists are always even */
144 abort ();
145 i1_len /= 2;
146 i0_cdr = i0->plist;
147 while (!NILP (i0_cdr))
149 /* Lengths of the two plists were unequal */
150 if (i1_len == 0)
151 return 0;
153 i0_sym = Fcar (i0_cdr);
154 i1_val = Fmemq (i0_sym, i1->plist);
156 /* i0 has something i1 doesn't */
157 if (EQ (i1_val, Qnil))
158 return 0;
160 /* i0 and i1 both have sym, but it has different values in each */
161 i0_cdr = Fcdr (i0_cdr);
162 if (! Fequal (i1_val, Fcar (i0_cdr)))
163 return 0;
165 i0_cdr = Fcdr (i0_cdr);
166 i1_len--;
169 /* Lengths of the two plists were unequal */
170 if (i1_len > 0)
171 return 0;
173 return 1;
176 static int icount;
177 static int idepth;
178 static int zero_length;
180 /* Traverse an interval tree TREE, performing FUNCTION on each node.
181 Pass FUNCTION two args: an interval, and ARG. */
183 void
184 traverse_intervals (tree, position, depth, function, arg)
185 INTERVAL tree;
186 int position, depth;
187 void (* function) ();
188 Lisp_Object arg;
190 if (NULL_INTERVAL_P (tree))
191 return;
193 traverse_intervals (tree->left, position, depth + 1, function, arg);
194 position += LEFT_TOTAL_LENGTH (tree);
195 tree->position = position;
196 (*function) (tree, arg);
197 position += LENGTH (tree);
198 traverse_intervals (tree->right, position, depth + 1, function, arg);
201 #if 0
202 /* These functions are temporary, for debugging purposes only. */
204 INTERVAL search_interval, found_interval;
206 void
207 check_for_interval (i)
208 register INTERVAL i;
210 if (i == search_interval)
212 found_interval = i;
213 icount++;
217 INTERVAL
218 search_for_interval (i, tree)
219 register INTERVAL i, tree;
221 icount = 0;
222 search_interval = i;
223 found_interval = NULL_INTERVAL;
224 traverse_intervals (tree, 1, 0, &check_for_interval, Qnil);
225 return found_interval;
228 static void
229 inc_interval_count (i)
230 INTERVAL i;
232 icount++;
233 if (LENGTH (i) == 0)
234 zero_length++;
235 if (depth > idepth)
236 idepth = depth;
240 count_intervals (i)
241 register INTERVAL i;
243 icount = 0;
244 idepth = 0;
245 zero_length = 0;
246 traverse_intervals (i, 1, 0, &inc_interval_count, Qnil);
248 return icount;
251 static INTERVAL
252 root_interval (interval)
253 INTERVAL interval;
255 register INTERVAL i = interval;
257 while (! ROOT_INTERVAL_P (i))
258 i = i->parent;
260 return i;
262 #endif
264 /* Assuming that a left child exists, perform the following operation:
267 / \ / \
268 B => A
269 / \ / \
273 static INTERVAL
274 rotate_right (interval)
275 INTERVAL interval;
277 INTERVAL i;
278 INTERVAL B = interval->left;
279 int len = LENGTH (interval);
281 /* Deal with any Parent of A; make it point to B. */
282 if (! ROOT_INTERVAL_P (interval))
283 if (AM_LEFT_CHILD (interval))
284 interval->parent->left = interval->left;
285 else
286 interval->parent->right = interval->left;
287 interval->left->parent = interval->parent;
289 /* B gets the same length as A, since it get A's position in the tree. */
290 interval->left->total_length = interval->total_length;
292 /* B becomes the parent of A. */
293 i = interval->left->right;
294 interval->left->right = interval;
295 interval->parent = interval->left;
297 /* A gets c as left child. */
298 interval->left = i;
299 if (! NULL_INTERVAL_P (i))
300 i->parent = interval;
301 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
302 + RIGHT_TOTAL_LENGTH (interval));
304 return B;
307 /* Assuming that a right child exists, perform the following operation:
309 A B
310 / \ / \
311 B => A
312 / \ / \
316 static INTERVAL
317 rotate_left (interval)
318 INTERVAL interval;
320 INTERVAL i;
321 INTERVAL B = interval->right;
322 int len = LENGTH (interval);
324 /* Deal with the parent of A. */
325 if (! ROOT_INTERVAL_P (interval))
326 if (AM_LEFT_CHILD (interval))
327 interval->parent->left = interval->right;
328 else
329 interval->parent->right = interval->right;
330 interval->right->parent = interval->parent;
332 /* B must have the same total length of A. */
333 interval->right->total_length = interval->total_length;
335 /* Make B the parent of A */
336 i = interval->right->left;
337 interval->right->left = interval;
338 interval->parent = interval->right;
340 /* Make A point to c */
341 interval->right = i;
342 if (! NULL_INTERVAL_P (i))
343 i->parent = interval;
344 interval->total_length = (len + LEFT_TOTAL_LENGTH (interval)
345 + RIGHT_TOTAL_LENGTH (interval));
347 return B;
350 /* Split INTERVAL into two pieces, starting the second piece at character
351 position OFFSET (counting from 1), relative to INTERVAL. The right-hand
352 piece (second, lexicographically) is returned.
354 The size and position fields of the two intervals are set based upon
355 those of the original interval. The property list of the new interval
356 is reset, thus it is up to the caller to do the right thing with the
357 result.
359 Note that this does not change the position of INTERVAL; if it is a root,
360 it is still a root after this operation. */
362 INTERVAL
363 split_interval_right (interval, offset)
364 INTERVAL interval;
365 int offset;
367 INTERVAL new = make_interval ();
368 int position = interval->position;
369 int new_length = LENGTH (interval) - offset + 1;
371 new->position = position + offset - 1;
372 new->parent = interval;
374 if (LEAF_INTERVAL_P (interval) || NULL_RIGHT_CHILD (interval))
376 interval->right = new;
377 new->total_length = new_length;
379 return new;
382 /* Insert the new node between INTERVAL and its right child. */
383 new->right = interval->right;
384 interval->right->parent = new;
385 interval->right = new;
387 new->total_length = new_length + new->right->total_length;
389 return new;
392 /* Split INTERVAL into two pieces, starting the second piece at character
393 position OFFSET (counting from 1), relative to INTERVAL. The left-hand
394 piece (first, lexicographically) is returned.
396 The size and position fields of the two intervals are set based upon
397 those of the original interval. The property list of the new interval
398 is reset, thus it is up to the caller to do the right thing with the
399 result.
401 Note that this does not change the position of INTERVAL; if it is a root,
402 it is still a root after this operation. */
404 INTERVAL
405 split_interval_left (interval, offset)
406 INTERVAL interval;
407 int offset;
409 INTERVAL new = make_interval ();
410 int position = interval->position;
411 int new_length = offset - 1;
413 new->position = interval->position;
414 interval->position = interval->position + offset - 1;
415 new->parent = interval;
417 if (NULL_LEFT_CHILD (interval))
419 interval->left = new;
420 new->total_length = new_length;
422 return new;
425 /* Insert the new node between INTERVAL and its left child. */
426 new->left = interval->left;
427 new->left->parent = new;
428 interval->left = new;
429 new->total_length = new_length + LEFT_TOTAL_LENGTH (new);
431 return new;
434 /* Find the interval containing text position POSITION in the text
435 represented by the interval tree TREE. POSITION is relative to
436 the beginning of that text.
438 The `position' field, which is a cache of an interval's position,
439 is updated in the interval found. Other functions (e.g., next_interval)
440 will update this cache based on the result of find_interval. */
442 INLINE INTERVAL
443 find_interval (tree, position)
444 register INTERVAL tree;
445 register int position;
447 register int relative_position = position;
449 if (NULL_INTERVAL_P (tree))
450 return NULL_INTERVAL;
452 if (position > TOTAL_LENGTH (tree))
453 abort (); /* Paranoia */
454 #if 0
455 position = TOTAL_LENGTH (tree);
456 #endif
458 while (1)
460 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
462 tree = tree->left;
464 else if (relative_position > (TOTAL_LENGTH (tree)
465 - RIGHT_TOTAL_LENGTH (tree)))
467 relative_position -= (TOTAL_LENGTH (tree)
468 - RIGHT_TOTAL_LENGTH (tree));
469 tree = tree->right;
471 else
473 tree->position = LEFT_TOTAL_LENGTH (tree)
474 + position - relative_position + 1;
475 return tree;
480 /* Find the succeeding interval (lexicographically) to INTERVAL.
481 Sets the `position' field based on that of INTERVAL (see
482 find_interval). */
484 INTERVAL
485 next_interval (interval)
486 register INTERVAL interval;
488 register INTERVAL i = interval;
489 register int next_position;
491 if (NULL_INTERVAL_P (i))
492 return NULL_INTERVAL;
493 next_position = interval->position + LENGTH (interval);
495 if (! NULL_RIGHT_CHILD (i))
497 i = i->right;
498 while (! NULL_LEFT_CHILD (i))
499 i = i->left;
501 i->position = next_position;
502 return i;
505 while (! NULL_PARENT (i))
507 if (AM_LEFT_CHILD (i))
509 i = i->parent;
510 i->position = next_position;
511 return i;
514 i = i->parent;
517 return NULL_INTERVAL;
520 /* Find the preceding interval (lexicographically) to INTERVAL.
521 Sets the `position' field based on that of INTERVAL (see
522 find_interval). */
524 INTERVAL
525 previous_interval (interval)
526 register INTERVAL interval;
528 register INTERVAL i;
529 register position_of_previous;
531 if (NULL_INTERVAL_P (interval))
532 return NULL_INTERVAL;
534 if (! NULL_LEFT_CHILD (interval))
536 i = interval->left;
537 while (! NULL_RIGHT_CHILD (i))
538 i = i->right;
540 i->position = interval->position - LENGTH (i);
541 return i;
544 i = interval;
545 while (! NULL_PARENT (i))
547 if (AM_RIGHT_CHILD (i))
549 i = i->parent;
551 i->position = interval->position - LENGTH (i);
552 return i;
554 i = i->parent;
557 return NULL_INTERVAL;
560 #if 0
561 /* Traverse a path down the interval tree TREE to the interval
562 containing POSITION, adjusting all nodes on the path for
563 an addition of LENGTH characters. Insertion between two intervals
564 (i.e., point == i->position, where i is second interval) means
565 text goes into second interval.
567 Modifications are needed to handle the hungry bits -- after simply
568 finding the interval at position (don't add length going down),
569 if it's the beginning of the interval, get the previous interval
570 and check the hugry bits of both. Then add the length going back up
571 to the root. */
573 static INTERVAL
574 adjust_intervals_for_insertion (tree, position, length)
575 INTERVAL tree;
576 int position, length;
578 register int relative_position;
579 register INTERVAL this;
581 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
582 abort ();
584 /* If inserting at point-max of a buffer, that position
585 will be out of range */
586 if (position > TOTAL_LENGTH (tree))
587 position = TOTAL_LENGTH (tree);
588 relative_position = position;
589 this = tree;
591 while (1)
593 if (relative_position <= LEFT_TOTAL_LENGTH (this))
595 this->total_length += length;
596 this = this->left;
598 else if (relative_position > (TOTAL_LENGTH (this)
599 - RIGHT_TOTAL_LENGTH (this)))
601 relative_position -= (TOTAL_LENGTH (this)
602 - RIGHT_TOTAL_LENGTH (this));
603 this->total_length += length;
604 this = this->right;
606 else
608 /* If we are to use zero-length intervals as buffer pointers,
609 then this code will have to change. */
610 this->total_length += length;
611 this->position = LEFT_TOTAL_LENGTH (this)
612 + position - relative_position + 1;
613 return tree;
617 #endif
619 /* Effect an adjustment corresponding to the addition of LENGTH characters
620 of text. Do this by finding the interval containing POSITION in the
621 interval tree TREE, and then adjusting all of it's ancestors by adding
622 LENGTH to them.
624 If POSITION is the first character of an interval, meaning that point
625 is actually between the two intervals, make the new text belong to
626 the interval which is "sticky".
628 If both intervals are "sticky", then make them belong to the left-most
629 interval. Another possibility would be to create a new interval for
630 this text, and make it have the merged properties of both ends. */
632 static INTERVAL
633 adjust_intervals_for_insertion (tree, position, length)
634 INTERVAL tree;
635 int position, length;
637 register INTERVAL i;
639 if (TOTAL_LENGTH (tree) == 0) /* Paranoia */
640 abort ();
642 /* If inserting at point-max of a buffer, that position
643 will be out of range. */
644 if (position > TOTAL_LENGTH (tree))
645 position = TOTAL_LENGTH (tree);
647 i = find_interval (tree, position);
648 /* If we are positioned between intervals, check the stickiness of
649 both of them. */
650 if (position == i->position
651 && position != 1)
653 register INTERVAL prev = previous_interval (i);
655 /* If both intervals are sticky here, then default to the
656 left-most one. But perhaps we should create a new
657 interval here instead... */
658 if (END_STICKY_P (prev))
659 i = prev;
662 while (! NULL_INTERVAL_P (i))
664 i->total_length += length;
665 i = i->parent;
668 return tree;
671 /* Delete an node I from its interval tree by merging its subtrees
672 into one subtree which is then returned. Caller is responsible for
673 storing the resulting subtree into its parent. */
675 static INTERVAL
676 delete_node (i)
677 register INTERVAL i;
679 register INTERVAL migrate, this;
680 register int migrate_amt;
682 if (NULL_INTERVAL_P (i->left))
683 return i->right;
684 if (NULL_INTERVAL_P (i->right))
685 return i->left;
687 migrate = i->left;
688 migrate_amt = i->left->total_length;
689 this = i->right;
690 this->total_length += migrate_amt;
691 while (! NULL_INTERVAL_P (this->left))
693 this = this->left;
694 this->total_length += migrate_amt;
696 this->left = migrate;
697 migrate->parent = this;
699 return i->right;
702 /* Delete interval I from its tree by calling `delete_node'
703 and properly connecting the resultant subtree.
705 I is presumed to be empty; that is, no adjustments are made
706 for the length of I. */
708 void
709 delete_interval (i)
710 register INTERVAL i;
712 register INTERVAL parent;
713 int amt = LENGTH (i);
715 if (amt > 0) /* Only used on zero-length intervals now. */
716 abort ();
718 if (ROOT_INTERVAL_P (i))
720 Lisp_Object owner = (Lisp_Object) i->parent;
721 parent = delete_node (i);
722 if (! NULL_INTERVAL_P (parent))
723 parent->parent = (INTERVAL) owner;
725 if (XTYPE (owner) == Lisp_Buffer)
726 XBUFFER (owner)->intervals = parent;
727 else if (XTYPE (owner) == Lisp_String)
728 XSTRING (owner)->intervals = parent;
729 else
730 abort ();
732 return;
735 parent = i->parent;
736 if (AM_LEFT_CHILD (i))
738 parent->left = delete_node (i);
739 if (! NULL_INTERVAL_P (parent->left))
740 parent->left->parent = parent;
742 else
744 parent->right = delete_node (i);
745 if (! NULL_INTERVAL_P (parent->right))
746 parent->right->parent = parent;
750 /* Find the interval in TREE corresponding to the character position FROM
751 and delete as much as possible of AMOUNT from that interval, starting
752 after the relative position of FROM within it. Return the amount
753 actually deleted, and if the interval was zeroed-out, delete that
754 interval node from the tree.
756 Do this by recursing down TREE to the interval in question, and
757 deleting the appropriate amount of text. */
759 static int
760 interval_deletion_adjustment (tree, from, amount)
761 register INTERVAL tree;
762 register int from, amount;
764 register int relative_position = from;
766 if (NULL_INTERVAL_P (tree))
767 return 0;
769 /* Left branch */
770 if (relative_position <= LEFT_TOTAL_LENGTH (tree))
772 int subtract = interval_deletion_adjustment (tree->left,
773 relative_position,
774 amount);
775 tree->total_length -= subtract;
776 return subtract;
778 /* Right branch */
779 else if (relative_position > (TOTAL_LENGTH (tree)
780 - RIGHT_TOTAL_LENGTH (tree)))
782 int subtract;
784 relative_position -= (tree->total_length
785 - RIGHT_TOTAL_LENGTH (tree));
786 subtract = interval_deletion_adjustment (tree->right,
787 relative_position,
788 amount);
789 tree->total_length -= subtract;
790 return subtract;
792 /* Here -- this node */
793 else
795 /* If this is a zero-length, marker interval, then
796 we must skip it. */
798 if (relative_position == LEFT_TOTAL_LENGTH (tree) + 1)
800 /* This means we're deleting from the beginning of this interval. */
801 register int my_amount = LENGTH (tree);
803 if (amount < my_amount)
805 tree->total_length -= amount;
806 return amount;
808 else
810 tree->total_length -= my_amount;
811 if (LENGTH (tree) != 0)
812 abort (); /* Paranoia */
814 delete_interval (tree);
815 return my_amount;
818 else /* Deleting starting in the middle. */
820 register int my_amount = ((tree->total_length
821 - RIGHT_TOTAL_LENGTH (tree))
822 - relative_position + 1);
824 if (amount <= my_amount)
826 tree->total_length -= amount;
827 return amount;
829 else
831 tree->total_length -= my_amount;
832 return my_amount;
837 /* Never reach here */
838 abort ();
841 /* Effect the adjustments neccessary to the interval tree of BUFFER
842 to correspond to the deletion of LENGTH characters from that buffer
843 text. The deletion is effected at position START (relative to the
844 buffer). */
846 static void
847 adjust_intervals_for_deletion (buffer, start, length)
848 struct buffer *buffer;
849 int start, length;
851 register int left_to_delete = length;
852 register INTERVAL tree = buffer->intervals;
853 register int deleted;
855 if (NULL_INTERVAL_P (tree))
856 return;
858 if (length == TOTAL_LENGTH (tree))
860 buffer->intervals = NULL_INTERVAL;
861 return;
864 if (ONLY_INTERVAL_P (tree))
866 tree->total_length -= length;
867 return;
870 if (start > TOTAL_LENGTH (tree))
871 start = TOTAL_LENGTH (tree);
872 while (left_to_delete > 0)
874 left_to_delete -= interval_deletion_adjustment (tree, start,
875 left_to_delete);
876 tree = buffer->intervals;
877 if (left_to_delete == tree->total_length)
879 buffer->intervals = NULL_INTERVAL;
880 return;
885 /* Make the adjustments neccessary to the interval tree of BUFFER to
886 represent an addition or deletion of LENGTH characters starting
887 at position START. Addition or deletion is indicated by the sign
888 of LENGTH. */
890 INLINE void
891 offset_intervals (buffer, start, length)
892 struct buffer *buffer;
893 int start, length;
895 if (NULL_INTERVAL_P (buffer->intervals) || length == 0)
896 return;
898 if (length > 0)
899 adjust_intervals_for_insertion (buffer->intervals, start, length);
900 else
901 adjust_intervals_for_deletion (buffer, start, -length);
904 /* Merge interval I with its lexicographic successor. The resulting
905 interval is returned, and has the properties of the original
906 successor. The properties of I are lost. I is removed from the
907 interval tree.
909 IMPORTANT:
910 The caller must verify that this is not the last (rightmost)
911 interval. */
913 INTERVAL
914 merge_interval_right (i)
915 register INTERVAL i;
917 register int absorb = LENGTH (i);
918 register INTERVAL successor;
920 /* Zero out this interval. */
921 i->total_length -= absorb;
923 /* Find the succeeding interval. */
924 if (! NULL_RIGHT_CHILD (i)) /* It's below us. Add absorb
925 as we descend. */
927 successor = i->right;
928 while (! NULL_LEFT_CHILD (successor))
930 successor->total_length += absorb;
931 successor = successor->left;
934 successor->total_length += absorb;
935 delete_interval (i);
936 return successor;
939 successor = i;
940 while (! NULL_PARENT (successor)) /* It's above us. Subtract as
941 we ascend. */
943 if (AM_LEFT_CHILD (successor))
945 successor = successor->parent;
946 delete_interval (i);
947 return successor;
950 successor = successor->parent;
951 successor->total_length -= absorb;
954 /* This must be the rightmost or last interval and cannot
955 be merged right. The caller should have known. */
956 abort ();
959 /* Merge interval I with its lexicographic predecessor. The resulting
960 interval is returned, and has the properties of the original predecessor.
961 The properties of I are lost. Interval node I is removed from the tree.
963 IMPORTANT:
964 The caller must verify that this is not the first (leftmost) interval. */
966 INTERVAL
967 merge_interval_left (i)
968 register INTERVAL i;
970 register int absorb = LENGTH (i);
971 register INTERVAL predecessor;
973 /* Zero out this interval. */
974 i->total_length -= absorb;
976 /* Find the preceding interval. */
977 if (! NULL_LEFT_CHILD (i)) /* It's below us. Go down,
978 adding ABSORB as we go. */
980 predecessor = i->left;
981 while (! NULL_RIGHT_CHILD (predecessor))
983 predecessor->total_length += absorb;
984 predecessor = predecessor->right;
987 predecessor->total_length += absorb;
988 delete_interval (i);
989 return predecessor;
992 predecessor = i;
993 while (! NULL_PARENT (predecessor)) /* It's above us. Go up,
994 subtracting ABSORB. */
996 if (AM_RIGHT_CHILD (predecessor))
998 predecessor = predecessor->parent;
999 delete_interval (i);
1000 return predecessor;
1003 predecessor = predecessor->parent;
1004 predecessor->total_length -= absorb;
1007 /* This must be the leftmost or first interval and cannot
1008 be merged left. The caller should have known. */
1009 abort ();
1012 /* Make an exact copy of interval tree SOURCE which descends from
1013 PARENT. This is done by recursing through SOURCE, copying
1014 the current interval and its properties, and then adjusting
1015 the pointers of the copy. */
1017 static INTERVAL
1018 reproduce_tree (source, parent)
1019 INTERVAL source, parent;
1021 register INTERVAL t = make_interval ();
1023 bcopy (source, t, INTERVAL_SIZE);
1024 copy_properties (source, t);
1025 t->parent = parent;
1026 if (! NULL_LEFT_CHILD (source))
1027 t->left = reproduce_tree (source->left, t);
1028 if (! NULL_RIGHT_CHILD (source))
1029 t->right = reproduce_tree (source->right, t);
1031 return t;
1034 /* Make a new interval of length LENGTH starting at START in the
1035 group of intervals INTERVALS, which is actually an interval tree.
1036 Returns the new interval.
1038 Generate an error if the new positions would overlap an existing
1039 interval. */
1041 static INTERVAL
1042 make_new_interval (intervals, start, length)
1043 INTERVAL intervals;
1044 int start, length;
1046 INTERVAL slot;
1048 slot = find_interval (intervals, start);
1049 if (start + length > slot->position + LENGTH (slot))
1050 error ("Interval would overlap");
1052 if (start == slot->position && length == LENGTH (slot))
1053 return slot;
1055 if (slot->position == start)
1057 /* New right node. */
1058 split_interval_right (slot, length + 1);
1059 return slot;
1062 if (slot->position + LENGTH (slot) == start + length)
1064 /* New left node. */
1065 split_interval_left (slot, LENGTH (slot) - length + 1);
1066 return slot;
1069 /* Convert interval SLOT into three intervals. */
1070 split_interval_left (slot, start - slot->position + 1);
1071 split_interval_right (slot, length + 1);
1072 return slot;
1075 /* Insert the intervals of SOURCE into BUFFER at POSITION.
1077 This is used in insdel.c when inserting Lisp_Strings into
1078 the buffer. The text corresponding to SOURCE is already in
1079 the buffer when this is called. The intervals of new tree are
1080 those belonging to the string being inserted; a copy is not made.
1082 If the inserted text had no intervals associated, this function
1083 simply returns -- offset_intervals should handle placing the
1084 text in the correct interval, depending on the sticky bits.
1086 If the inserted text had properties (intervals), then there are two
1087 cases -- either insertion happened in the middle of some interval,
1088 or between two intervals.
1090 If the text goes into the middle of an interval, then new
1091 intervals are created in the middle with only the properties of
1092 the new text, *unless* the macro MERGE_INSERTIONS is true, in
1093 which case the new text has the union of its properties and those
1094 of the text into which it was inserted.
1096 If the text goes between two intervals, then if neither interval
1097 had its appropriate sticky property set (front_sticky, rear_sticky),
1098 the new text has only its properties. If one of the sticky properties
1099 is set, then the new text "sticks" to that region and its properties
1100 depend on merging as above. If both the preceding and succeding
1101 intervals to the new text are "sticky", then the new text retains
1102 only its properties, as if neither sticky property were set. Perhaps
1103 we should consider merging all three sets of properties onto the new
1104 text... */
1106 void
1107 graft_intervals_into_buffer (source, position, buffer)
1108 INTERVAL source;
1109 int position;
1110 struct buffer *buffer;
1112 register INTERVAL under, over, this, prev;
1113 register INTERVAL tree = buffer->intervals;
1114 int middle;
1116 /* If the new text has no properties, it becomes part of whatever
1117 interval it was inserted into. */
1118 if (NULL_INTERVAL_P (source))
1119 return;
1121 if (NULL_INTERVAL_P (tree))
1123 /* The inserted text constitutes the whole buffer, so
1124 simply copy over the interval structure. */
1125 if (BUF_Z (buffer) == TOTAL_LENGTH (source))
1127 buffer->intervals = reproduce_tree (source, tree->parent);
1128 /* Explicitly free the old tree here. */
1130 return;
1133 /* Create an interval tree in which to place a copy
1134 of the intervals of the inserted string. */
1136 Lisp_Object buf;
1137 XSET (buf, Lisp_Buffer, buffer);
1138 tree = create_root_interval (buf);
1141 else
1142 if (TOTAL_LENGTH (tree) == TOTAL_LENGTH (source))
1143 /* If the buffer contains only the new string, but
1144 there was already some interval tree there, then it may be
1145 some zero length intervals. Eventually, do something clever
1146 about inserting properly. For now, just waste the old intervals. */
1148 buffer->intervals = reproduce_tree (source, tree->parent);
1149 /* Explicitly free the old tree here. */
1151 return;
1153 else
1154 /* Paranoia -- the text has already been added, so this buffer
1155 should be of non-zero length. */
1156 if (TOTAL_LENGTH (tree) == 0)
1157 abort ();
1159 this = under = find_interval (tree, position);
1160 if (NULL_INTERVAL_P (under)) /* Paranoia */
1161 abort ();
1162 over = find_interval (source, 1);
1164 /* Here for insertion in the middle of an interval.
1165 Split off an equivalent interval to the right,
1166 then don't bother with it any more. */
1168 if (position > under->position)
1170 INTERVAL end_unchanged
1171 = split_interval_left (this, position - under->position + 1);
1172 copy_properties (under, end_unchanged);
1173 under->position = position;
1174 prev = 0;
1175 middle = 1;
1177 else
1179 prev = previous_interval (under);
1180 if (prev && !END_STICKY_P (prev))
1181 prev = 0;
1184 /* Insertion is now at beginning of UNDER. */
1186 /* The inserted text "sticks" to the interval `under',
1187 which means it gets those properties. */
1188 while (! NULL_INTERVAL_P (over))
1190 position = LENGTH (over) + 1;
1191 if (position < LENGTH (under))
1192 this = split_interval_left (under, position);
1193 else
1194 this = under;
1195 copy_properties (over, this);
1196 /* Insertion at the end of an interval, PREV,
1197 inherits from PREV if PREV is sticky at the end. */
1198 if (prev && ! FRONT_STICKY_P (under)
1199 && MERGE_INSERTIONS (prev))
1200 merge_properties (prev, this);
1201 /* Maybe it inherits from the following interval
1202 if that is sticky at the front. */
1203 else if ((FRONT_STICKY_P (under) || middle)
1204 && MERGE_INSERTIONS (under))
1205 merge_properties (under, this);
1206 over = next_interval (over);
1209 buffer->intervals = balance_intervals (buffer->intervals);
1210 return;
1213 /* Get the value of property PROP from PLIST,
1214 which is the plist of an interval.
1215 We check for direct properties and for categories with property PROP. */
1217 Lisp_Object
1218 textget (plist, prop)
1219 Lisp_Object plist;
1220 register Lisp_Object prop;
1222 register Lisp_Object tail, fallback;
1223 fallback = Qnil;
1225 for (tail = plist; !NILP (tail); tail = Fcdr (Fcdr (tail)))
1227 register Lisp_Object tem;
1228 tem = Fcar (tail);
1229 if (EQ (prop, tem))
1230 return Fcar (Fcdr (tail));
1231 if (EQ (tem, Qcategory))
1232 fallback = Fget (Fcar (Fcdr (tail)), prop);
1235 return fallback;
1238 /* Set point in BUFFER to POSITION. If the target position is
1239 before an invisible character which is not displayed with a special glyph,
1240 move back to an ok place to display. */
1242 void
1243 set_point (position, buffer)
1244 register int position;
1245 register struct buffer *buffer;
1247 register INTERVAL to, from, toprev, fromprev, target;
1248 register int iposition = position;
1249 int buffer_point;
1250 register Lisp_Object obj;
1251 int backwards = (position < BUF_PT (buffer)) ? 1 : 0;
1252 int old_position = buffer->text.pt;
1254 if (position == buffer->text.pt)
1255 return;
1257 if (NULL_INTERVAL_P (buffer->intervals))
1259 buffer->text.pt = position;
1260 return;
1263 /* Perhaps we should just change `position' to the limit. */
1264 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1265 abort ();
1267 /* Position Z is really one past the last char in the buffer. */
1268 if (position == BUF_ZV (buffer))
1269 iposition = position - 1;
1271 /* Set TO to the interval containing the char after POSITION,
1272 and TOPREV to the interval containing the char before POSITION.
1273 Either one may be null. They may be equal. */
1274 to = find_interval (buffer->intervals, iposition);
1275 if (position == BUF_BEGV (buffer))
1276 toprev = 0;
1277 else if (to->position == position)
1278 toprev = previous_interval (to);
1279 else if (iposition != position)
1280 toprev = to, to = 0;
1281 else
1282 toprev = to;
1284 buffer_point = (BUF_PT (buffer) == BUF_ZV (buffer)
1285 ? BUF_ZV (buffer) - 1
1286 : BUF_PT (buffer));
1288 /* Set FROM to the interval containing the char after PT,
1289 and FROMPREV to the interval containing the char before PT.
1290 Either one may be null. They may be equal. */
1291 /* We could cache this and save time. */
1292 from = find_interval (buffer->intervals, buffer_point);
1293 if (from->position == BUF_BEGV (buffer))
1294 fromprev = 0;
1295 else if (from->position == BUF_PT (buffer))
1296 fromprev = previous_interval (from);
1297 else if (buffer_point != BUF_PT (buffer))
1298 fromprev = from, from = 0;
1299 else
1300 fromprev = from;
1302 /* Moving within an interval */
1303 if (to == from && toprev == fromprev && INTERVAL_VISIBLE_P (to))
1305 buffer->text.pt = position;
1306 return;
1309 /* If the new position is before an invisible character,
1310 move forward over all such. */
1311 while (! NULL_INTERVAL_P (to)
1312 && ! INTERVAL_VISIBLE_P (to)
1313 && ! DISPLAY_INVISIBLE_GLYPH (to))
1315 toprev = to;
1316 to = next_interval (to);
1317 position = to->position;
1320 buffer->text.pt = position;
1322 /* We run point-left and point-entered hooks here, iff the
1323 two intervals are not equivalent. These hooks take
1324 (old_point, new_point) as arguments. */
1325 if (! intervals_equal (from, to)
1326 || ! intervals_equal (fromprev, toprev))
1328 Lisp_Object leave_after, leave_before, enter_after, enter_before;
1330 if (fromprev)
1331 leave_after = textget (fromprev->plist, Qpoint_left);
1332 else
1333 leave_after = Qnil;
1334 if (from)
1335 leave_before = textget (from->plist, Qpoint_left);
1336 else
1337 leave_before = Qnil;
1339 if (toprev)
1340 enter_after = textget (toprev->plist, Qpoint_entered);
1341 else
1342 enter_after = Qnil;
1343 if (to)
1344 enter_before = textget (to->plist, Qpoint_entered);
1345 else
1346 enter_before = Qnil;
1348 if (! EQ (leave_before, enter_before) && !NILP (leave_before))
1349 call2 (leave_before, old_position, position);
1350 if (! EQ (leave_after, enter_after) && !NILP (leave_after))
1351 call2 (leave_after, old_position, position);
1353 if (! EQ (enter_before, leave_before) && !NILP (enter_before))
1354 call2 (enter_before, old_position, position);
1355 if (! EQ (enter_after, leave_after) && !NILP (enter_after))
1356 call2 (enter_after, old_position, position);
1360 /* Set point temporarily, without checking any text properties. */
1362 INLINE void
1363 temp_set_point (position, buffer)
1364 int position;
1365 struct buffer *buffer;
1367 buffer->text.pt = position;
1370 /* Return the proper local map for position POSITION in BUFFER.
1371 Use the map specified by the local-map property, if any.
1372 Otherwise, use BUFFER's local map. */
1374 Lisp_Object
1375 get_local_map (position, buffer)
1376 register int position;
1377 register struct buffer *buffer;
1379 register INTERVAL interval;
1380 Lisp_Object prop, tem;
1382 if (NULL_INTERVAL_P (buffer->intervals))
1383 return current_buffer->keymap;
1385 /* Perhaps we should just change `position' to the limit. */
1386 if (position > BUF_Z (buffer) || position < BUF_BEG (buffer))
1387 abort ();
1389 /* Position Z is really one past the last char in the buffer. */
1390 if (position == BUF_ZV (buffer))
1391 return current_buffer->keymap;
1393 interval = find_interval (buffer->intervals, position);
1394 prop = textget (interval->plist, Qlocal_map);
1395 if (NILP (prop))
1396 return current_buffer->keymap;
1398 /* Use the local map only if it is valid. */
1399 tem = Fkeymapp (prop);
1400 if (!NILP (tem))
1401 return prop;
1403 return current_buffer->keymap;
1406 /* Call the modification hook functions in LIST, each with START and END. */
1408 static void
1409 call_mod_hooks (list, start, end)
1410 Lisp_Object list, start, end;
1412 struct gcpro gcpro1;
1413 GCPRO1 (list);
1414 while (!NILP (list))
1416 call2 (Fcar (list), start, end);
1417 list = Fcdr (list);
1419 UNGCPRO;
1422 /* Check for read-only intervals and signal an error if we find one.
1423 Then check for any modification hooks in the range START up to
1424 (but not including) TO. Create a list of all these hooks in
1425 lexicographic order, eliminating consecutive extra copies of the
1426 same hook. Then call those hooks in order, with START and END - 1
1427 as arguments. */
1429 void
1430 verify_interval_modification (buf, start, end)
1431 struct buffer *buf;
1432 int start, end;
1434 register INTERVAL intervals = buf->intervals;
1435 register INTERVAL i, prev;
1436 Lisp_Object hooks;
1437 register Lisp_Object prev_mod_hooks;
1438 Lisp_Object mod_hooks;
1439 struct gcpro gcpro1;
1441 hooks = Qnil;
1442 prev_mod_hooks = Qnil;
1443 mod_hooks = Qnil;
1445 if (NULL_INTERVAL_P (intervals))
1446 return;
1448 if (start > end)
1450 int temp = start;
1451 start = end;
1452 end = temp;
1455 /* For an insert operation, check the two chars around the position. */
1456 if (start == end)
1458 INTERVAL prev;
1459 Lisp_Object before, after;
1461 /* Set I to the interval containing the char after START,
1462 and PREV to the interval containing the char before START.
1463 Either one may be null. They may be equal. */
1464 i = find_interval (intervals,
1465 (start == BUF_ZV (buf) ? start - 1 : start));
1467 if (start == BUF_BEGV (buf))
1468 prev = 0;
1469 if (i->position == start)
1470 prev = previous_interval (i);
1471 else if (i->position < start)
1472 prev = i;
1473 if (start == BUF_ZV (buf))
1474 i = 0;
1476 if (NULL_INTERVAL_P (prev))
1478 after = textget (i->plist, Qread_only);
1479 if (! NILP (after))
1480 error ("Attempt to insert within read-only text");
1482 else if (NULL_INTERVAL_P (i))
1484 before = textget (prev->plist, Qread_only);
1485 if (! NILP (before))
1486 error ("Attempt to insert within read-only text");
1488 else
1490 before = textget (prev->plist, Qread_only);
1491 after = textget (i->plist, Qread_only);
1492 if (! NILP (before) && EQ (before, after))
1493 error ("Attempt to insert within read-only text");
1496 /* Run both mod hooks (just once if they're the same). */
1497 if (!NULL_INTERVAL_P (prev))
1498 prev_mod_hooks = textget (prev->plist, Qmodification_hooks);
1499 if (!NULL_INTERVAL_P (i))
1500 mod_hooks = textget (i->plist, Qmodification_hooks);
1501 GCPRO1 (mod_hooks);
1502 if (! NILP (prev_mod_hooks))
1503 call_mod_hooks (prev_mod_hooks, make_number (start),
1504 make_number (end));
1505 UNGCPRO;
1506 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1507 call_mod_hooks (mod_hooks, make_number (start), make_number (end));
1509 else
1511 /* Loop over intervals on or next to START...END,
1512 collecting their hooks. */
1514 i = find_interval (intervals, start);
1517 if (! INTERVAL_WRITABLE_P (i))
1518 error ("Attempt to modify read-only text");
1520 mod_hooks = textget (i->plist, Qmodification_hooks);
1521 if (! NILP (mod_hooks) && ! EQ (mod_hooks, prev_mod_hooks))
1523 hooks = Fcons (mod_hooks, hooks);
1524 prev_mod_hooks = mod_hooks;
1527 i = next_interval (i);
1529 /* Keep going thru the interval containing the char before END. */
1530 while (! NULL_INTERVAL_P (i) && i->position < end);
1532 GCPRO1 (hooks);
1533 hooks = Fnreverse (hooks);
1534 while (! EQ (hooks, Qnil))
1536 call_mod_hooks (Fcar (hooks), make_number (start),
1537 make_number (end));
1538 hooks = Fcdr (hooks);
1540 UNGCPRO;
1544 /* Balance an interval node if the amount of text in its left and right
1545 subtrees differs by more than the percentage specified by
1546 `interval-balance-threshold'. */
1548 static INTERVAL
1549 balance_an_interval (i)
1550 INTERVAL i;
1552 register int total_children_size = (LEFT_TOTAL_LENGTH (i)
1553 + RIGHT_TOTAL_LENGTH (i));
1554 register int threshold = (XFASTINT (interval_balance_threshold)
1555 * (total_children_size / 100));
1557 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1558 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1559 return rotate_right (i);
1561 if (LEFT_TOTAL_LENGTH (i) > RIGHT_TOTAL_LENGTH (i)
1562 && (LEFT_TOTAL_LENGTH (i) - RIGHT_TOTAL_LENGTH (i)) > threshold)
1563 return rotate_right (i);
1565 #if 0
1566 if (LEFT_TOTAL_LENGTH (i) >
1567 (RIGHT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1568 return rotate_right (i);
1570 if (RIGHT_TOTAL_LENGTH (i) >
1571 (LEFT_TOTAL_LENGTH (i) + XINT (interval_balance_threshold)))
1572 return rotate_left (i);
1573 #endif
1575 return i;
1578 /* Balance the interval tree TREE. Balancing is by weight
1579 (the amount of text). */
1581 INTERVAL
1582 balance_intervals (tree)
1583 register INTERVAL tree;
1585 register INTERVAL new_tree;
1587 if (NULL_INTERVAL_P (tree))
1588 return NULL_INTERVAL;
1590 new_tree = tree;
1593 tree = new_tree;
1594 new_tree = balance_an_interval (new_tree);
1596 while (new_tree != tree);
1598 return new_tree;
1601 /* Produce an interval tree reflecting the intervals in
1602 TREE from START to START + LENGTH. */
1604 INTERVAL
1605 copy_intervals (tree, start, length)
1606 INTERVAL tree;
1607 int start, length;
1609 register INTERVAL i, new, t;
1610 register int got;
1612 if (NULL_INTERVAL_P (tree) || length <= 0)
1613 return NULL_INTERVAL;
1615 i = find_interval (tree, start);
1616 if (NULL_INTERVAL_P (i) || LENGTH (i) == 0)
1617 abort ();
1619 /* If there is only one interval and it's the default, return nil. */
1620 if ((start - i->position + 1 + length) < LENGTH (i)
1621 && DEFAULT_INTERVAL_P (i))
1622 return NULL_INTERVAL;
1624 new = make_interval ();
1625 new->position = 1;
1626 got = (LENGTH (i) - (start - i->position));
1627 new->total_length = length;
1628 copy_properties (i, new);
1630 t = new;
1631 while (got < length)
1633 i = next_interval (i);
1634 t = split_interval_right (t, got + 1);
1635 copy_properties (i, t);
1636 got += LENGTH (i);
1639 if (got > length)
1640 t->total_length -= (got - length);
1642 return balance_intervals (new);
1645 /* Give STRING the properties of BUFFER from POSITION to LENGTH. */
1647 INLINE void
1648 copy_intervals_to_string (string, buffer, position, length)
1649 Lisp_Object string, buffer;
1650 int position, length;
1652 INTERVAL interval_copy = copy_intervals (XBUFFER (buffer)->intervals,
1653 position, length);
1654 if (NULL_INTERVAL_P (interval_copy))
1655 return;
1657 interval_copy->parent = (INTERVAL) string;
1658 XSTRING (string)->intervals = interval_copy;
1661 #endif /* USE_TEXT_PROPERTIES */