diff options
| author | Eli Zaretskii | 2014-04-22 20:37:35 +0300 |
|---|---|---|
| committer | Eli Zaretskii | 2014-04-22 20:37:35 +0300 |
| commit | 2f999d5275f7aab04d9e1aedc35d7c33eba94e2d (patch) | |
| tree | 3fb9d81f5cc04de15d68203ee8431eb5582abf5d /src | |
| parent | 30cb51f1bc9ce5976f492b5df5d30c6298f5a2aa (diff) | |
| download | emacs-2f999d5275f7aab04d9e1aedc35d7c33eba94e2d.tar.gz emacs-2f999d5275f7aab04d9e1aedc35d7c33eba94e2d.zip | |
Add debugging facility for the newline cache.
See the discussion in
http://lists.gnu.org/archive/html/emacs-devel/2014-04/msg00295.html
for more detail.
src/search.c (find_newline1): New subroutine.
(Fnewline_cache_check): New function.
(syms_of_search): Defsubr it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/search.c | 165 |
2 files changed, 171 insertions, 0 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index e8fb5f63203..98d607046c6 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2014-04-22 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * search.c (find_newline1): New subroutine. | ||
| 4 | (Fnewline_cache_check): New function. | ||
| 5 | (syms_of_search): Defsubr it. | ||
| 6 | |||
| 1 | 2014-04-21 Jarek Czekalski <jarekczek@poczta.onet.pl> | 7 | 2014-04-21 Jarek Czekalski <jarekczek@poczta.onet.pl> |
| 2 | 8 | ||
| 3 | Fix freezing with scroll bars of GTK3 Toolkit (bug#15801). | 9 | Fix freezing with scroll bars of GTK3 Toolkit (bug#15801). |
diff --git a/src/search.c b/src/search.c index 3de194c5056..97087307be3 100644 --- a/src/search.c +++ b/src/search.c | |||
| @@ -3108,6 +3108,170 @@ DEFUN ("regexp-quote", Fregexp_quote, Sregexp_quote, 1, 1, 0, | |||
| 3108 | out - temp, | 3108 | out - temp, |
| 3109 | STRING_MULTIBYTE (string)); | 3109 | STRING_MULTIBYTE (string)); |
| 3110 | } | 3110 | } |
| 3111 | |||
| 3112 | /* Like find_newline, but doesn't use the cache, and only searches forward. */ | ||
| 3113 | static ptrdiff_t | ||
| 3114 | find_newline1 (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, | ||
| 3115 | ptrdiff_t end_byte, ptrdiff_t count, ptrdiff_t *shortage, | ||
| 3116 | ptrdiff_t *bytepos, bool allow_quit) | ||
| 3117 | { | ||
| 3118 | if (count > 0) | ||
| 3119 | { | ||
| 3120 | if (!end) | ||
| 3121 | end = ZV, end_byte = ZV_BYTE; | ||
| 3122 | } | ||
| 3123 | else | ||
| 3124 | { | ||
| 3125 | if (!end) | ||
| 3126 | end = BEGV, end_byte = BEGV_BYTE; | ||
| 3127 | } | ||
| 3128 | if (end_byte == -1) | ||
| 3129 | end_byte = CHAR_TO_BYTE (end); | ||
| 3130 | |||
| 3131 | if (shortage != 0) | ||
| 3132 | *shortage = 0; | ||
| 3133 | |||
| 3134 | immediate_quit = allow_quit; | ||
| 3135 | |||
| 3136 | if (count > 0) | ||
| 3137 | while (start != end) | ||
| 3138 | { | ||
| 3139 | /* Our innermost scanning loop is very simple; it doesn't know | ||
| 3140 | about gaps, buffer ends, or the newline cache. ceiling is | ||
| 3141 | the position of the last character before the next such | ||
| 3142 | obstacle --- the last character the dumb search loop should | ||
| 3143 | examine. */ | ||
| 3144 | ptrdiff_t tem, ceiling_byte = end_byte - 1; | ||
| 3145 | |||
| 3146 | if (start_byte == -1) | ||
| 3147 | start_byte = CHAR_TO_BYTE (start); | ||
| 3148 | |||
| 3149 | /* The dumb loop can only scan text stored in contiguous | ||
| 3150 | bytes. BUFFER_CEILING_OF returns the last character | ||
| 3151 | position that is contiguous, so the ceiling is the | ||
| 3152 | position after that. */ | ||
| 3153 | tem = BUFFER_CEILING_OF (start_byte); | ||
| 3154 | ceiling_byte = min (tem, ceiling_byte); | ||
| 3155 | |||
| 3156 | { | ||
| 3157 | /* The termination address of the dumb loop. */ | ||
| 3158 | unsigned char *lim_addr = BYTE_POS_ADDR (ceiling_byte) + 1; | ||
| 3159 | ptrdiff_t lim_byte = ceiling_byte + 1; | ||
| 3160 | |||
| 3161 | /* Nonpositive offsets (relative to LIM_ADDR and LIM_BYTE) | ||
| 3162 | of the base, the cursor, and the next line. */ | ||
| 3163 | ptrdiff_t base = start_byte - lim_byte; | ||
| 3164 | ptrdiff_t cursor, next; | ||
| 3165 | |||
| 3166 | for (cursor = base; cursor < 0; cursor = next) | ||
| 3167 | { | ||
| 3168 | /* The dumb loop. */ | ||
| 3169 | unsigned char *nl = memchr (lim_addr + cursor, '\n', - cursor); | ||
| 3170 | next = nl ? nl - lim_addr : 0; | ||
| 3171 | |||
| 3172 | if (! nl) | ||
| 3173 | break; | ||
| 3174 | next++; | ||
| 3175 | |||
| 3176 | if (--count == 0) | ||
| 3177 | { | ||
| 3178 | immediate_quit = 0; | ||
| 3179 | if (bytepos) | ||
| 3180 | *bytepos = lim_byte + next; | ||
| 3181 | return BYTE_TO_CHAR (lim_byte + next); | ||
| 3182 | } | ||
| 3183 | } | ||
| 3184 | |||
| 3185 | start_byte = lim_byte; | ||
| 3186 | start = BYTE_TO_CHAR (start_byte); | ||
| 3187 | } | ||
| 3188 | } | ||
| 3189 | |||
| 3190 | immediate_quit = 0; | ||
| 3191 | if (shortage) | ||
| 3192 | *shortage = count; | ||
| 3193 | if (bytepos) | ||
| 3194 | { | ||
| 3195 | *bytepos = start_byte == -1 ? CHAR_TO_BYTE (start) : start_byte; | ||
| 3196 | eassert (*bytepos == CHAR_TO_BYTE (start)); | ||
| 3197 | } | ||
| 3198 | return start; | ||
| 3199 | } | ||
| 3200 | |||
| 3201 | DEFUN ("newline-cache-check", Fnewline_cache_check, Snewline_cache_check, | ||
| 3202 | 0, 1, 0, | ||
| 3203 | doc: /* Check the newline cache of BUFFER against buffer contents. | ||
| 3204 | |||
| 3205 | BUFFER defaults to the current buffer. | ||
| 3206 | |||
| 3207 | Value is an array of 2 sub-arrays of buffer positions for newlines, | ||
| 3208 | the first based on the cache, the second based on actually scanning | ||
| 3209 | the buffer. If the buffer doesn't have a cache, the value is nil. */) | ||
| 3210 | (Lisp_Object buffer) | ||
| 3211 | { | ||
| 3212 | struct buffer *buf; | ||
| 3213 | struct region_cache *nlcache; | ||
| 3214 | ptrdiff_t shortage, nl_count_cache, nl_count_buf; | ||
| 3215 | Lisp_Object cache_newlines, buf_newlines, val; | ||
| 3216 | ptrdiff_t from, from_byte, found, i; | ||
| 3217 | |||
| 3218 | if (NILP (buffer)) | ||
| 3219 | buf = current_buffer; | ||
| 3220 | else | ||
| 3221 | { | ||
| 3222 | CHECK_BUFFER (buffer); | ||
| 3223 | buf = XBUFFER (buffer); | ||
| 3224 | } | ||
| 3225 | if (buf->base_buffer) | ||
| 3226 | buf = buf->base_buffer; | ||
| 3227 | |||
| 3228 | /* If the buffer doesn't have a newline cache, return nil. */ | ||
| 3229 | if (NILP (BVAR (buf, cache_long_scans)) | ||
| 3230 | || buf->newline_cache == NULL) | ||
| 3231 | return Qnil; | ||
| 3232 | |||
| 3233 | /* How many newlines are there according to the cache? */ | ||
| 3234 | find_newline (BUF_BEG (buf), BUF_BEG_BYTE (buf), | ||
| 3235 | BUF_Z (buf), BUF_Z_BYTE (buf), | ||
| 3236 | TYPE_MAXIMUM (ptrdiff_t), &shortage, NULL, true); | ||
| 3237 | nl_count_cache = TYPE_MAXIMUM (ptrdiff_t) - shortage; | ||
| 3238 | |||
| 3239 | /* Create vector and populate it. */ | ||
| 3240 | cache_newlines = make_uninit_vector (nl_count_cache); | ||
| 3241 | for (from = BUF_BEG( buf), found = from, i = 0; | ||
| 3242 | from < BUF_Z (buf); | ||
| 3243 | from = found, i++) | ||
| 3244 | { | ||
| 3245 | ptrdiff_t from_byte = CHAR_TO_BYTE (from); | ||
| 3246 | |||
| 3247 | found = find_newline (from, from_byte, 0, -1, 1, &shortage, NULL, true); | ||
| 3248 | if (shortage == 0) | ||
| 3249 | ASET (cache_newlines, i, make_number (found - 1)); | ||
| 3250 | } | ||
| 3251 | |||
| 3252 | /* Now do the same, but without using the cache. */ | ||
| 3253 | find_newline1 (BUF_BEG (buf), BUF_BEG_BYTE (buf), | ||
| 3254 | BUF_Z (buf), BUF_Z_BYTE (buf), | ||
| 3255 | TYPE_MAXIMUM (ptrdiff_t), &shortage, NULL, true); | ||
| 3256 | nl_count_buf = TYPE_MAXIMUM (ptrdiff_t) - shortage; | ||
| 3257 | buf_newlines = make_uninit_vector (nl_count_buf); | ||
| 3258 | for (from = BUF_BEG( buf), found = from, i = 0; | ||
| 3259 | from < BUF_Z (buf); | ||
| 3260 | from = found, i++) | ||
| 3261 | { | ||
| 3262 | ptrdiff_t from_byte = CHAR_TO_BYTE (from); | ||
| 3263 | |||
| 3264 | found = find_newline1 (from, from_byte, 0, -1, 1, &shortage, NULL, true); | ||
| 3265 | if (shortage == 0) | ||
| 3266 | ASET (buf_newlines, i, make_number (found - 1)); | ||
| 3267 | } | ||
| 3268 | |||
| 3269 | /* Construct the value and return it. */ | ||
| 3270 | val = make_uninit_vector (2); | ||
| 3271 | ASET (val, 0, cache_newlines); | ||
| 3272 | ASET (val, 1, buf_newlines); | ||
| 3273 | return val; | ||
| 3274 | } | ||
| 3111 | 3275 | ||
| 3112 | void | 3276 | void |
| 3113 | syms_of_search (void) | 3277 | syms_of_search (void) |
| @@ -3180,4 +3344,5 @@ is to bind it with `let' around a small expression. */); | |||
| 3180 | defsubr (&Smatch_data); | 3344 | defsubr (&Smatch_data); |
| 3181 | defsubr (&Sset_match_data); | 3345 | defsubr (&Sset_match_data); |
| 3182 | defsubr (&Sregexp_quote); | 3346 | defsubr (&Sregexp_quote); |
| 3347 | defsubr (&Snewline_cache_check); | ||
| 3183 | } | 3348 | } |