aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/marker.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/src/marker.c b/src/marker.c
index 7773c4fce0f..9933d957a57 100644
--- a/src/marker.c
+++ b/src/marker.c
@@ -90,7 +90,7 @@ clear_charpos_cache (struct buffer *b)
90#define CONSIDER(CHARPOS, BYTEPOS) \ 90#define CONSIDER(CHARPOS, BYTEPOS) \
91{ \ 91{ \
92 ptrdiff_t this_charpos = (CHARPOS); \ 92 ptrdiff_t this_charpos = (CHARPOS); \
93 bool changed = 0; \ 93 bool changed = false; \
94 \ 94 \
95 if (this_charpos == charpos) \ 95 if (this_charpos == charpos) \
96 { \ 96 { \
@@ -105,14 +105,14 @@ clear_charpos_cache (struct buffer *b)
105 { \ 105 { \
106 best_above = this_charpos; \ 106 best_above = this_charpos; \
107 best_above_byte = (BYTEPOS); \ 107 best_above_byte = (BYTEPOS); \
108 changed = 1; \ 108 changed = true; \
109 } \ 109 } \
110 } \ 110 } \
111 else if (this_charpos > best_below) \ 111 else if (this_charpos > best_below) \
112 { \ 112 { \
113 best_below = this_charpos; \ 113 best_below = this_charpos; \
114 best_below_byte = (BYTEPOS); \ 114 best_below_byte = (BYTEPOS); \
115 changed = 1; \ 115 changed = true; \
116 } \ 116 } \
117 \ 117 \
118 if (changed) \ 118 if (changed) \
@@ -133,6 +133,28 @@ CHECK_MARKER (Lisp_Object x)
133 CHECK_TYPE (MARKERP (x), Qmarkerp, x); 133 CHECK_TYPE (MARKERP (x), Qmarkerp, x);
134} 134}
135 135
136/* When converting bytes from/to chars, we look through the list of
137 markers to try and find a good starting point (since markers keep
138 track of both bytepos and charpos at the same time).
139 But if there are many markers, it can take too much time to find a "good"
140 marker from which to start. Worse yet: if it takes a long time and we end
141 up finding a nearby markers, we won't add a new marker to cache this
142 result, so next time around we'll have to go through this same long list
143 to (re)find this best marker. So the further down the list of
144 markers we go, the less demanding we are w.r.t what is a good marker.
145
146 The previous code used INITIAL=50 and INCREMENT=0 and this lead to
147 really poor performance when there are many markers.
148 I haven't tried to tweak INITIAL, but experiments on my trusty Thinkpad
149 T61 using various artificial test cases seem to suggest that INCREMENT=50
150 might be "the best compromise": it significantly improved the
151 worst case and it was rarely slower and never by much.
152
153 The asymptotic behavior is still poor, tho, so in largish buffers with many
154 overlays (e.g. 300KB and 30K overlays), it can still be a bottlneck. */
155#define BYTECHAR_DISTANCE_INITIAL 50
156#define BYTECHAR_DISTANCE_INCREMENT 50
157
136/* Return the byte position corresponding to CHARPOS in B. */ 158/* Return the byte position corresponding to CHARPOS in B. */
137 159
138ptrdiff_t 160ptrdiff_t
@@ -141,6 +163,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
141 struct Lisp_Marker *tail; 163 struct Lisp_Marker *tail;
142 ptrdiff_t best_above, best_above_byte; 164 ptrdiff_t best_above, best_above_byte;
143 ptrdiff_t best_below, best_below_byte; 165 ptrdiff_t best_below, best_below_byte;
166 ptrdiff_t distance = BYTECHAR_DISTANCE_INITIAL;
144 167
145 eassert (BUF_BEG (b) <= charpos && charpos <= BUF_Z (b)); 168 eassert (BUF_BEG (b) <= charpos && charpos <= BUF_Z (b));
146 169
@@ -180,8 +203,11 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
180 /* If we are down to a range of 50 chars, 203 /* If we are down to a range of 50 chars,
181 don't bother checking any other markers; 204 don't bother checking any other markers;
182 scan the intervening chars directly now. */ 205 scan the intervening chars directly now. */
183 if (best_above - best_below < 50) 206 if (best_above - charpos < distance
207 || charpos - best_below < distance)
184 break; 208 break;
209 else
210 distance += BYTECHAR_DISTANCE_INCREMENT;
185 } 211 }
186 212
187 /* We get here if we did not exactly hit one of the known places. 213 /* We get here if we did not exactly hit one of the known places.
@@ -248,7 +274,7 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
248#define CONSIDER(BYTEPOS, CHARPOS) \ 274#define CONSIDER(BYTEPOS, CHARPOS) \
249{ \ 275{ \
250 ptrdiff_t this_bytepos = (BYTEPOS); \ 276 ptrdiff_t this_bytepos = (BYTEPOS); \
251 int changed = 0; \ 277 int changed = false; \
252 \ 278 \
253 if (this_bytepos == bytepos) \ 279 if (this_bytepos == bytepos) \
254 { \ 280 { \
@@ -263,14 +289,14 @@ buf_charpos_to_bytepos (struct buffer *b, ptrdiff_t charpos)
263 { \ 289 { \
264 best_above = (CHARPOS); \ 290 best_above = (CHARPOS); \
265 best_above_byte = this_bytepos; \ 291 best_above_byte = this_bytepos; \
266 changed = 1; \ 292 changed = true; \
267 } \ 293 } \
268 } \ 294 } \
269 else if (this_bytepos > best_below_byte) \ 295 else if (this_bytepos > best_below_byte) \
270 { \ 296 { \
271 best_below = (CHARPOS); \ 297 best_below = (CHARPOS); \
272 best_below_byte = this_bytepos; \ 298 best_below_byte = this_bytepos; \
273 changed = 1; \ 299 changed = true; \
274 } \ 300 } \
275 \ 301 \
276 if (changed) \ 302 if (changed) \
@@ -293,6 +319,7 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
293 struct Lisp_Marker *tail; 319 struct Lisp_Marker *tail;
294 ptrdiff_t best_above, best_above_byte; 320 ptrdiff_t best_above, best_above_byte;
295 ptrdiff_t best_below, best_below_byte; 321 ptrdiff_t best_below, best_below_byte;
322 ptrdiff_t distance = BYTECHAR_DISTANCE_INITIAL;
296 323
297 eassert (BUF_BEG_BYTE (b) <= bytepos && bytepos <= BUF_Z_BYTE (b)); 324 eassert (BUF_BEG_BYTE (b) <= bytepos && bytepos <= BUF_Z_BYTE (b));
298 325
@@ -323,8 +350,11 @@ buf_bytepos_to_charpos (struct buffer *b, ptrdiff_t bytepos)
323 /* If we are down to a range of 50 chars, 350 /* If we are down to a range of 50 chars,
324 don't bother checking any other markers; 351 don't bother checking any other markers;
325 scan the intervening chars directly now. */ 352 scan the intervening chars directly now. */
326 if (best_above - best_below < 50) 353 if (best_above - bytepos < distance
354 || bytepos - best_below < distance)
327 break; 355 break;
356 else
357 distance += BYTECHAR_DISTANCE_INCREMENT;
328 } 358 }
329 359
330 /* We get here if we did not exactly hit one of the known places. 360 /* We get here if we did not exactly hit one of the known places.
@@ -744,8 +774,8 @@ count_markers (struct buffer *buf)
744ptrdiff_t 774ptrdiff_t
745verify_bytepos (ptrdiff_t charpos) 775verify_bytepos (ptrdiff_t charpos)
746{ 776{
747 ptrdiff_t below = 1; 777 ptrdiff_t below = BEG;
748 ptrdiff_t below_byte = 1; 778 ptrdiff_t below_byte = BYTE_BEG;
749 779
750 while (below != charpos) 780 while (below != charpos)
751 { 781 {