Mercurial > hg > xemacs-beta
comparison src/line-number.c @ 284:558f606b08ae r21-0b40
Import from CVS: tag r21-0b40
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:34:13 +0200 |
parents | f955c73f5258 |
children | 57709be46d1b |
comparison
equal
deleted
inserted
replaced
283:fa3d41851a08 | 284:558f606b08ae |
---|---|
20 | 20 |
21 /* Synched up with: Not in FSF. */ | 21 /* Synched up with: Not in FSF. */ |
22 | 22 |
23 /* To calculate the line numbers, redisplay must count the newlines | 23 /* To calculate the line numbers, redisplay must count the newlines |
24 from a known position. This used to be BUF_BEGV, but this made the | 24 from a known position. This used to be BUF_BEGV, but this made the |
25 redisplay extremely slow for large buffers, because Emacs must | 25 line numbering extremely slow for large buffers, because Emacs had |
26 rescan the whole buffer at each redisplay, just to count the | 26 to rescan the whole buffer at each redisplay. |
27 newlines. | 27 |
28 | 28 To make line numbering efficient, we maintain a buffer-local cache |
29 To make line numbering efficient, we maintain a simple-minded | 29 of recently used positions and their line numbers. The cache is |
30 cache. Each buffer contains a small ring of known positions, each | 30 implemented as a small ring of cache positions. A cache position |
31 element of the ring being a Lisp_Object -- either nil or a cons of | 31 is either nil or a cons of a buffer position (marker) and the |
32 a buffer position and the line number (beginning with 0). | 32 corresponding line number. |
33 | 33 |
34 When calculating the line numbers, this cache is consulted if it | 34 When calculating the line numbers, this cache is consulted if it |
35 would otherwise take too much time to count the newlines in the | 35 would otherwise take too much time to count the newlines in the |
36 buffer (see the comment to window_line_number.) | 36 buffer (see the comment to buffer_line_number().) |
37 | 37 |
38 Insertion and deletions that contain/delete newlines invalidate the | 38 Insertion and deletions that contain/delete newlines invalidate the |
39 cached positions after the insertion point. This guarantees | 39 cached positions after the insertion point. This guarantees |
40 relatively fast line numbers caching (even in buffers where point | 40 relatively fast line numbers caching (even in buffers where point |
41 moves a lot), and low memory usage. All of this is done only in | 41 moves a lot), and low memory usage. All of this is done only in |
42 the buffers where the cache is actually initialized -- i.e. where | 42 the buffers where the cache is actually initialized -- i.e. where |
43 line-numbering is on, and you move the point farther than | 43 line-numbering is on, and you move the point farther than |
44 LINE_NUMBER_FAR from the beginning of buffer. In this sense, the | 44 LINE_NUMBER_FAR from the beginning of buffer. In this sense, the |
45 cache is lazy. If you don't use it, you don't pay for it. | 45 cache is lazy -- if you don't use it, you don't pay for it. |
46 | 46 |
47 NOTE: line-number cache should not be confused with line-start | 47 NOTE: line-number cache should not be confused with line-start |
48 cache. Line-start cache (a part of redisplay) works with the | 48 cache. Line-start cache (a part of redisplay) works with the |
49 display lines, whereas this works with the buffer lines (literally | 49 display lines, whereas this works with the buffer lines (literally |
50 counting the newlines). */ | 50 counting the newlines). */ |
54 #include "buffer.h" | 54 #include "buffer.h" |
55 #include "insdel.h" | 55 #include "insdel.h" |
56 | 56 |
57 #include "line-number.h" | 57 #include "line-number.h" |
58 | 58 |
59 | 59 /* #### The following three values could stand more exploration for |
60 /* #### The following three values could use some tweaking, to get the | 60 best performance. */ |
61 best performance. I suspect LINE_NUMBER_FAR and | |
62 LINE_NUMBER_LARGE_STRING could be made bigger. */ | |
63 | 61 |
64 /* Size of the ring. The current code expects this to be a small | 62 /* Size of the ring. The current code expects this to be a small |
65 number. If you make it much bigger, you should probably tr yto | 63 number. If you make it larger, you should probably optimize the |
66 optimize the various routines to keep it sorted. */ | 64 code below to keep it sorted. */ |
67 #define LINE_NUMBER_RING_SIZE 8 | 65 #define LINE_NUMBER_RING_SIZE 8 |
68 | 66 |
69 /* How much traversal has to be exceeded for two points to be | 67 /* How much traversal has to be exceeded for two points to be |
70 considered "far" from each other. When two points are far, cache | 68 considered "far" from each other. When two points are far, cache |
71 will be used. You can set this to a small value for debugging | 69 will be used. */ |
72 purposes. */ | 70 #define LINE_NUMBER_FAR 32768 |
73 #define LINE_NUMBER_FAR 16384 | |
74 | 71 |
75 /* How large a string has to be to give up searching it for newlines, | 72 /* How large a string has to be to give up searching it for newlines, |
76 before change. */ | 73 before change. */ |
77 #define LINE_NUMBER_LARGE_STRING 256 | 74 #define LINE_NUMBER_LARGE_STRING 256 |
78 | 75 |
99 b->line_number_cache = Fcons (make_vector (LINE_NUMBER_RING_SIZE, Qnil), | 96 b->line_number_cache = Fcons (make_vector (LINE_NUMBER_RING_SIZE, Qnil), |
100 Qzero); | 97 Qzero); |
101 narrow_line_number_cache (b); | 98 narrow_line_number_cache (b); |
102 } | 99 } |
103 | 100 |
104 /* Update line_number_begv, or flag it as dirty. Do it only if the | 101 /* Flag LINE_NUMBER_BEGV (b) as dirty. Do it only if the line number |
105 line number cache is already initialized. */ | 102 cache is already initialized. */ |
106 void | 103 void |
107 narrow_line_number_cache (struct buffer *b) | 104 narrow_line_number_cache (struct buffer *b) |
108 { | 105 { |
109 if (NILP (b->line_number_cache)) | 106 if (NILP (b->line_number_cache)) |
110 return; | 107 return; |
111 /* Optimization: if BUF_BEG == BUF_BEGV (as is the case after Fwiden | 108 |
112 and save_restriction_restore), don't bother calling scan_buffer. */ | |
113 if (BUF_BEG (b) == BUF_BEGV (b)) | 109 if (BUF_BEG (b) == BUF_BEGV (b)) |
114 { | 110 /* The is the case Fwiden and save_restriction_restore. Since we |
115 LINE_NUMBER_BEGV (b) = Qzero; | 111 know the correct value, we can update it now. */ |
116 return; | 112 LINE_NUMBER_BEGV (b) = Qzero; |
117 } | 113 else |
118 /* Calculating the line number of BUF_BEGV here is a bad idea, | 114 /* Calculating the line number of BUF_BEGV here is a bad idea, |
119 because there is absolutely no reason to do it before the next | 115 because there is absolutely no reason to do it before the next |
120 redisplay. We simply mark it as dirty instead. */ | 116 redisplay. We simply mark it as dirty instead. */ |
121 LINE_NUMBER_BEGV (b) = make_int (-1); | 117 LINE_NUMBER_BEGV (b) = make_int (-1); |
122 } | 118 } |
123 | 119 |
124 /* Invalidate the line number cache positions that lie after POS. */ | 120 /* Invalidate the line number cache positions that lie after POS. */ |
125 static void | 121 static void |
126 invalidate_line_number_cache (struct buffer *b, Bufpos pos) | 122 invalidate_line_number_cache (struct buffer *b, Bufpos pos) |
127 { | 123 { |
128 EMACS_INT i, j; | 124 EMACS_INT i, j; |
129 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); | 125 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); |
130 Lisp_Object lisp_buffer = make_buffer (b); | |
131 | 126 |
132 for (i = 0; i < LINE_NUMBER_RING_SIZE; i++) | 127 for (i = 0; i < LINE_NUMBER_RING_SIZE; i++) |
133 { | 128 { |
134 if (!CONSP (ring[i])) | 129 if (!CONSP (ring[i])) |
135 break; | 130 break; |
136 /* As the marker stays behind the insertions, this check might | 131 /* As the marker stays behind the insertions, this check might |
137 as well be `>'. However, Finsert_before_markers can move the | 132 as well be `>'. However, Finsert_before_markers can advance |
138 marker anyway, which bites in shell buffers. | 133 the marker anyway, which bites in shell buffers. |
139 | 134 |
140 #### This is wrong; it works right, but forces recreation of | 135 #### This forces recreation of the cached marker (and |
141 the cached marker (and recalculation of newlines) every time | 136 recalculation of newlines) every time a newline is inserted |
142 a newline is inserted at point, which is way losing. Isn't | 137 at point, which is way losing. Isn't there a way to make a |
143 there a way to make a marker impervious to | 138 marker impervious to Finsert_before_markers()?? Maybe I |
144 Finsert_before_markers()?? Maybe I should convert to using | 139 should convert the code to use extents. */ |
145 extents. */ | |
146 if (marker_position (XCAR (ring[i])) >= pos) | 140 if (marker_position (XCAR (ring[i])) >= pos) |
147 { | 141 { |
148 /* Get the marker out of the way. */ | 142 /* Get the marker out of the way. */ |
149 Fset_marker (XCAR (ring[i]), Qnil, lisp_buffer); | 143 Fset_marker (XCAR (ring[i]), Qnil, Qnil); |
150 /* ...and shift the ring elements, up to the first nil. */ | 144 /* ...and shift the ring elements, up to the first nil. */ |
151 for (j = i; !NILP (ring[j]) && j < LINE_NUMBER_RING_SIZE - 1; j++) | 145 for (j = i; !NILP (ring[j]) && j < LINE_NUMBER_RING_SIZE - 1; j++) |
152 ring[j] = ring[j + 1]; | 146 ring[j] = ring[j + 1]; |
153 ring[j] = Qnil; | 147 ring[j] = Qnil; |
154 /* Must recheck position i. */ | 148 /* Must recheck position i. */ |
160 /* Invalidate the cache positions after POS, if the string to be | 154 /* Invalidate the cache positions after POS, if the string to be |
161 inserted contains a newline. If the string is too large (larger | 155 inserted contains a newline. If the string is too large (larger |
162 than LINE_NUMBER_LARGE_STRING), invalidate the cache positions | 156 than LINE_NUMBER_LARGE_STRING), invalidate the cache positions |
163 after POS without prior search. | 157 after POS without prior search. |
164 | 158 |
165 This will do nothing, if cache is uninitialized. */ | 159 This will do nothing if the cache is uninitialized. */ |
166 void | 160 void |
167 insert_invalidate_line_number_cache (struct buffer *b, Bufpos pos, | 161 insert_invalidate_line_number_cache (struct buffer *b, Bufpos pos, |
168 CONST Bufbyte *nonreloc, Bytecount length) | 162 CONST Bufbyte *nonreloc, Bytecount length) |
169 { | 163 { |
170 if (NILP (b->line_number_cache)) | 164 if (NILP (b->line_number_cache)) |
171 return; | 165 return; |
172 | 166 |
173 if (length > LINE_NUMBER_LARGE_STRING | 167 if (length > LINE_NUMBER_LARGE_STRING |
174 || | 168 || |
175 /* We could also count how many newlines are in the string, and | 169 /* We could also count how many newlines there are in the string |
176 update the cache accordingly, but it would be too much work | 170 and update the cache accordingly, but it would be too much |
177 for too little gain. */ | 171 work for too little gain. */ |
178 memchr ((void *)nonreloc, '\n', (size_t) length)) | 172 memchr ((void *)nonreloc, '\n', (size_t) length)) |
179 invalidate_line_number_cache (b, pos); | 173 invalidate_line_number_cache (b, pos); |
180 } | 174 } |
181 | 175 |
182 /* Invalidate the cache positions after FROM, if the region to be | 176 /* Invalidate the cache positions after FROM, if the region to be |
183 deleted contains a newline. If the region is too large (larger | 177 deleted contains a newline. If the region-to-be-deleted is larger |
184 than LINE_NUMBER_LARGE_STRING), invalidate the cache positions | 178 than LINE_NUMBER_LARGE_STRING, invalidate the cache positions after |
185 after FROM without prior search. | 179 FROM without unconditionally. |
186 | 180 |
187 This will do nothing, if cache is uninitialized. */ | 181 This will do nothing if the cache is uninitialized. */ |
188 void | 182 void |
189 delete_invalidate_line_number_cache (struct buffer *b, Bufpos from, Bufpos to) | 183 delete_invalidate_line_number_cache (struct buffer *b, Bufpos from, Bufpos to) |
190 { | 184 { |
191 if (NILP (b->line_number_cache)) | 185 if (NILP (b->line_number_cache)) |
192 return; | 186 return; |
213 This will initialize the cache, if necessary. */ | 207 This will initialize the cache, if necessary. */ |
214 static void | 208 static void |
215 get_nearest_line_number (struct buffer *b, Bufpos *beg, Bufpos pos, | 209 get_nearest_line_number (struct buffer *b, Bufpos *beg, Bufpos pos, |
216 EMACS_INT *line) | 210 EMACS_INT *line) |
217 { | 211 { |
212 EMACS_INT i; | |
218 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); | 213 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); |
219 EMACS_INT i; | 214 Charcount length = pos - *beg; |
220 Charcount length, howfar; | 215 |
221 Bufpos newpos; | |
222 | |
223 length = pos - *beg; | |
224 if (length < 0) | 216 if (length < 0) |
225 length = -length; | 217 length = -length; |
226 | 218 |
227 /* Look for the nearest match. */ | 219 /* Find the ring entry closest to POS, if it is closer than BEG. */ |
228 for (i = 0; i < LINE_NUMBER_RING_SIZE; i++) | 220 for (i = 0; i < LINE_NUMBER_RING_SIZE && CONSP (ring[i]); i++) |
229 { | 221 { |
230 if (!CONSP (ring[i])) | 222 Bufpos newpos = marker_position (XCAR (ring[i])); |
231 break; | 223 Charcount howfar = newpos - pos; |
232 newpos = marker_position (XCAR (ring[i])); | |
233 howfar = newpos - pos; | |
234 if (howfar < 0) | 224 if (howfar < 0) |
235 howfar = -howfar; | 225 howfar = -howfar; |
236 if (howfar < length) | 226 if (howfar < length) |
237 { | 227 { |
238 length = howfar; | 228 length = howfar; |
240 *line = XINT (XCDR (ring[i])); | 230 *line = XINT (XCDR (ring[i])); |
241 } | 231 } |
242 } | 232 } |
243 } | 233 } |
244 | 234 |
245 /* Add a (pos, line) pair to the ring, and rotate it. */ | 235 /* Add a (POS . LINE) pair to the ring, and rotate it. */ |
246 static void | 236 static void |
247 add_line_number (struct buffer *b, Bufpos pos, int line) | 237 add_position_to_cache (struct buffer *b, Bufpos pos, int line) |
248 { | 238 { |
249 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); | 239 Lisp_Object *ring = XVECTOR_DATA (LINE_NUMBER_RING (b)); |
250 Lisp_Object marker; | 240 int i = LINE_NUMBER_RING_SIZE - 1; |
251 int i; | 241 |
252 | 242 /* Set the last marker in the ring to point nowhere. */ |
253 for (i = LINE_NUMBER_RING_SIZE - 1; i > 0; i--) | 243 if (CONSP (ring[i])) |
244 Fset_marker (XCAR (ring[i]), Qnil, Qnil); | |
245 | |
246 /* Rotate the ring... */ | |
247 for (; i > 0; i--) | |
254 ring[i] = ring[i - 1]; | 248 ring[i] = ring[i - 1]; |
255 marker = Fmake_marker (); | 249 |
256 Fset_marker (marker, make_int (pos), make_buffer (b)); | 250 /* ...and update it. */ |
257 ring[0] = Fcons (marker, make_int (line)); | 251 ring[0] = Fcons (Fset_marker (Fmake_marker (), make_int (pos), |
252 make_buffer (b)), | |
253 make_int (line)); | |
258 } | 254 } |
259 | 255 |
260 /* Calculate the line number in buffer B at position POS. If CACHEP | 256 /* Calculate the line number in buffer B at position POS. If CACHEP |
261 is non-zero, initialize and facilitate the line-number cache. The | 257 is non-zero, initialize and facilitate the line-number cache. The |
262 line number of the first line is 0. If narrowing is in effect, | 258 line number of the first line is 0. If narrowing is in effect, |
270 LINE_NUMBER_FAR), try to find a closer position in the ring. If it | 266 LINE_NUMBER_FAR), try to find a closer position in the ring. If it |
271 is found, use that position for BEG, and increment the line number | 267 is found, use that position for BEG, and increment the line number |
272 appropriately. | 268 appropriately. |
273 | 269 |
274 If the calculation (with or without the cache lookup) required more | 270 If the calculation (with or without the cache lookup) required more |
275 than LINE_NUMBER_FAR bytes of traversal, update the cache. */ | 271 than LINE_NUMBER_FAR characters of traversal, update the cache. */ |
276 EMACS_INT | 272 EMACS_INT |
277 buffer_line_number (struct buffer *b, Bufpos pos, int cachep) | 273 buffer_line_number (struct buffer *b, Bufpos pos, int cachep) |
278 { | 274 { |
279 Bufpos beg = BUF_BEGV (b); | 275 Bufpos beg = BUF_BEGV (b); |
280 EMACS_INT cached_lines = 0; | 276 EMACS_INT cached_lines = 0; |
312 | 308 |
313 if (cachep) | 309 if (cachep) |
314 { | 310 { |
315 /* If too far, update the cache. */ | 311 /* If too far, update the cache. */ |
316 if ((pos > beg ? pos - beg : beg - pos) > LINE_NUMBER_FAR) | 312 if ((pos > beg ? pos - beg : beg - pos) > LINE_NUMBER_FAR) |
317 add_line_number (b, pos, line); | 313 add_position_to_cache (b, pos, line); |
318 /* Account for narrowing. If CACHEP is nil, this is | 314 /* Account for narrowing. If cache is not used, this is |
319 unnecessary, because we counted from BUF_BEGV anyway. */ | 315 unnecessary, because we counted from BUF_BEGV anyway. */ |
320 line -= XINT (LINE_NUMBER_BEGV (b)); | 316 line -= XINT (LINE_NUMBER_BEGV (b)); |
321 } | 317 } |
322 | 318 |
323 return line; | 319 return line; |
324 } | 320 } |
325 |