Commit e30b79c1 authored by Dmitry Antipov's avatar Dmitry Antipov

Use region cache to speedup bidi_find_paragraph_start.

* src/buffer.h (struct buffer): New member bidi_paragraph_cache.
Rename cache_long_line_scans to cache_long_scans.
* src/buffer.c (bset_cache_long_line_scans): Rename to
bset_cache_long_scans.
(Fget_buffer_create, Fmake_indirect_buffer, Fkill_buffer)
(Fbuffer_swap_text, init_buffer_once): Take bidi_paragraph_cache
into account.
(syms_of_buffer): Rename cache-long-line-scans to
cache-long-scans.  Adjust docstring.
* src/search.c (newline_cache_on_off):
* src/indent.c (width_run_cache_on_off): Adjust users.
* src/bidi.c (bidi_paragraph_cache_on_off): New function.
(bidi_find_paragraph_start): Use bidi_paragraph_cache if needed.
* src/insdel.c (prepare_to_modify_buffer): Invalidate
bidi_paragraph_cache if enabled.
* doc/lispref/positions.texi (Motion by Screen Lines):
* doc/lispref/display.texi (Truncation): Rename `cache-long-line-scans'
to `cache-long-scans'.
parent 00012b86
2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
* positions.texi (Motion by Screen Lines):
* display.texi (Truncation): Rename `cache-long-line-scans'
to `cache-long-scans'.
2013-08-05 Xue Fuqiao <xfq.free@gmail.com>
* windows.texi (Window Start and End): Add an index.
......
......@@ -217,9 +217,9 @@ over the @code{line-prefix} variable. @xref{Special Properties}.
continuation to display them, computing the continuation lines can
make redisplay slow. The column computation and indentation functions
also become slow. Then you might find it advisable to set
@code{cache-long-line-scans} to @code{t}.
@code{cache-long-scans} to @code{t}.
@defvar cache-long-line-scans
@defvar cache-long-scans
If this variable is non-@code{nil}, various indentation and motion
functions, and Emacs redisplay, cache the results of scanning the
buffer, and consult the cache to avoid rescanning regions of the buffer
......
......@@ -483,7 +483,7 @@ Display}.
These functions scan text to determine where screen lines break, and
thus take time proportional to the distance scanned. If you intend to
use them heavily, Emacs provides caches which may improve the
performance of your code. @xref{Truncation, cache-long-line-scans}.
performance of your code. @xref{Truncation, cache-long-scans}.
@defun vertical-motion count &optional window
This function moves point to the start of the screen line @var{count}
......
2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
Use region cache to speedup bidi_find_paragraph_start.
* buffer.h (struct buffer): New member bidi_paragraph_cache.
Rename cache_long_line_scans to cache_long_scans.
* buffer.c (bset_cache_long_line_scans): Rename to
bset_cache_long_scans.
(Fget_buffer_create, Fmake_indirect_buffer, Fkill_buffer)
(Fbuffer_swap_text, init_buffer_once): Take bidi_paragraph_cache
into account.
(syms_of_buffer): Rename cache-long-line-scans to
cache-long-scans. Adjust docstring.
* search.c (newline_cache_on_off):
* indent.c (width_run_cache_on_off): Adjust users.
* bidi.c (bidi_paragraph_cache_on_off): New function.
(bidi_find_paragraph_start): Use bidi_paragraph_cache if needed.
* insdel.c (prepare_to_modify_buffer): Invalidate
bidi_paragraph_cache if enabled.
2013-08-06 Dmitry Antipov <dmantipov@yandex.ru>
Invalidate region caches only if buffer text is going to be changed.
......
......@@ -61,6 +61,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "character.h"
#include "buffer.h"
#include "dispextern.h"
#include "region-cache.h"
static bool bidi_initialized = 0;
......@@ -1085,6 +1086,29 @@ bidi_at_paragraph_end (ptrdiff_t charpos, ptrdiff_t bytepos)
return val;
}
/* If the user has requested the long scans caching, make sure that
BIDI cache is enabled. Otherwise, make sure it's disabled. */
static struct region_cache *
bidi_paragraph_cache_on_off (void)
{
if (NILP (BVAR (current_buffer, cache_long_scans)))
{
if (current_buffer->bidi_paragraph_cache)
{
free_region_cache (current_buffer->bidi_paragraph_cache);
current_buffer->bidi_paragraph_cache = 0;
}
return NULL;
}
else
{
if (!current_buffer->bidi_paragraph_cache)
current_buffer->bidi_paragraph_cache = new_region_cache ();
return current_buffer->bidi_paragraph_cache;
}
}
/* On my 2005-vintage machine, searching back for paragraph start
takes ~1 ms per line. And bidi_paragraph_init is called 4 times
when user types C-p. The number below limits each call to
......@@ -1100,7 +1124,8 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte)
{
Lisp_Object re = paragraph_start_re;
ptrdiff_t limit = ZV, limit_byte = ZV_BYTE;
ptrdiff_t n = 0;
struct region_cache *bpc = bidi_paragraph_cache_on_off ();
ptrdiff_t n = 0, oldpos = pos, next;
while (pos_byte > BEGV_BYTE
&& n++ < MAX_PARAGRAPH_SEARCH
......@@ -1111,10 +1136,18 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte)
of the text over which we scan back includes
paragraph_start_re? */
DEC_BOTH (pos, pos_byte);
pos = find_newline_no_quit (pos, pos_byte, -1, &pos_byte);
if (bpc && region_cache_backward (current_buffer, bpc, pos, &next))
{
pos = next, pos_byte = CHAR_TO_BYTE (pos);
break;
}
else
pos = find_newline_no_quit (pos, pos_byte, -1, &pos_byte);
}
if (n >= MAX_PARAGRAPH_SEARCH)
pos_byte = BEGV_BYTE;
pos = BEGV, pos_byte = BEGV_BYTE;
if (bpc)
know_region_cache (current_buffer, bpc, pos, oldpos);
return pos_byte;
}
......
......@@ -203,9 +203,9 @@ bset_buffer_file_coding_system (struct buffer *b, Lisp_Object val)
b->INTERNAL_FIELD (buffer_file_coding_system) = val;
}
static void
bset_cache_long_line_scans (struct buffer *b, Lisp_Object val)
bset_cache_long_scans (struct buffer *b, Lisp_Object val)
{
b->INTERNAL_FIELD (cache_long_line_scans) = val;
b->INTERNAL_FIELD (cache_long_scans) = val;
}
static void
bset_case_fold_search (struct buffer *b, Lisp_Object val)
......@@ -583,6 +583,7 @@ even if it is dead. The return value is never nil. */)
b->newline_cache = 0;
b->width_run_cache = 0;
b->bidi_paragraph_cache = 0;
bset_width_table (b, Qnil);
b->prevent_redisplay_optimizations_p = 1;
......@@ -806,6 +807,7 @@ CLONE nil means the indirect buffer's state is reset to default values. */)
b->newline_cache = 0;
b->width_run_cache = 0;
b->bidi_paragraph_cache = 0;
bset_width_table (b, Qnil);
name = Fcopy_sequence (name);
......@@ -1945,6 +1947,11 @@ cleaning up all windows currently displaying the buffer to be killed. */)
free_region_cache (b->width_run_cache);
b->width_run_cache = 0;
}
if (b->bidi_paragraph_cache)
{
free_region_cache (b->bidi_paragraph_cache);
b->bidi_paragraph_cache = 0;
}
bset_width_table (b, Qnil);
unblock_input ();
bset_undo_list (b, Qnil);
......@@ -2355,6 +2362,7 @@ DEFUN ("buffer-swap-text", Fbuffer_swap_text, Sbuffer_swap_text,
current_buffer->clip_changed = 1; other_buffer->clip_changed = 1;
swapfield (newline_cache, struct region_cache *);
swapfield (width_run_cache, struct region_cache *);
swapfield (bidi_paragraph_cache, struct region_cache *);
current_buffer->prevent_redisplay_optimizations_p = 1;
other_buffer->prevent_redisplay_optimizations_p = 1;
swapfield (overlays_before, struct Lisp_Overlay *);
......@@ -5169,7 +5177,7 @@ init_buffer_once (void)
bset_buffer_file_coding_system (&buffer_defaults, Qnil);
XSETFASTINT (BVAR (&buffer_defaults, fill_column), 70);
XSETFASTINT (BVAR (&buffer_defaults, left_margin), 0);
bset_cache_long_line_scans (&buffer_defaults, Qnil);
bset_cache_long_scans (&buffer_defaults, Qnil);
bset_file_truename (&buffer_defaults, Qnil);
XSETFASTINT (BVAR (&buffer_defaults, display_count), 0);
XSETFASTINT (BVAR (&buffer_defaults, left_margin_cols), 0);
......@@ -5233,7 +5241,7 @@ init_buffer_once (void)
XSETFASTINT (BVAR (&buffer_local_flags, abbrev_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, display_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, syntax_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, cache_long_line_scans), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, cache_long_scans), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, category_table), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, bidi_display_reordering), idx); ++idx;
XSETFASTINT (BVAR (&buffer_local_flags, bidi_paragraph_direction), idx); ++idx;
......@@ -6120,8 +6128,8 @@ If the value of the variable is t, undo information is not recorded. */);
DEFVAR_PER_BUFFER ("mark-active", &BVAR (current_buffer, mark_active), Qnil,
doc: /* Non-nil means the mark and region are currently active in this buffer. */);
DEFVAR_PER_BUFFER ("cache-long-line-scans", &BVAR (current_buffer, cache_long_line_scans), Qnil,
doc: /* Non-nil means that Emacs should use caches to handle long lines more quickly.
DEFVAR_PER_BUFFER ("cache-long-scans", &BVAR (current_buffer, cache_long_scans), Qnil,
doc: /* Non-nil means that Emacs should use caches in attempt to speedup buffer scans.
Normally, the line-motion functions work by scanning the buffer for
newlines. Columnar operations (like `move-to-column' and
......@@ -6131,18 +6139,24 @@ buffer's lines are very long (say, more than 500 characters), these
motion functions will take longer to execute. Emacs may also take
longer to update the display.
If `cache-long-line-scans' is non-nil, these motion functions cache the
If `cache-long-scans' is non-nil, these motion functions cache the
results of their scans, and consult the cache to avoid rescanning
regions of the buffer until the text is modified. The caches are most
beneficial when they prevent the most searching---that is, when the
buffer contains long lines and large regions of characters with the
same, fixed screen width.
When `cache-long-line-scans' is non-nil, processing short lines will
When `cache-long-scans' is non-nil, processing short lines will
become slightly slower (because of the overhead of consulting the
cache), and the caches will use memory roughly proportional to the
number of newlines and characters whose screen width varies.
Bidirectional editing also requires buffer scans to find paragraph
separators. If you have large paragraphs or no paragraph separators
at all, these scans may be slow. If `cache-long-scans' is non-nil,
results of these scans are cached. This doesn't help too much if
paragraphs are of the reasonable (few thousands of characters) size.
The caches require no explicit maintenance; their accuracy is
maintained internally by the Emacs primitives. Enabling or disabling
the cache should not affect the behavior of any of the motion
......
......@@ -632,9 +632,9 @@ struct buffer
/* List of symbols naming the file format used for auto-save file. */
Lisp_Object INTERNAL_FIELD (auto_save_file_format);
/* True if the newline position cache and width run cache are
enabled. See search.c and indent.c. */
Lisp_Object INTERNAL_FIELD (cache_long_line_scans);
/* True if the newline position cache, width run cache and BIDI paragraph
cache are enabled. See search.c, indent.c and bidi.c for details. */
Lisp_Object INTERNAL_FIELD (cache_long_scans);
/* If the width run cache is enabled, this table contains the
character widths width_run_cache (see above) assumes. When we
......@@ -839,9 +839,12 @@ struct buffer
the character's width; if it maps a character to zero, we don't
know what its width is. This allows compute_motion to process
such regions very quickly, using algebra instead of inspecting
each character. See also width_table, below. */
each character. See also width_table, below.
The latter cache is used to speedup bidi_find_paragraph_start. */
struct region_cache *newline_cache;
struct region_cache *width_run_cache;
struct region_cache *bidi_paragraph_cache;
/* Non-zero means don't use redisplay optimizations for
displaying this buffer. */
......
......@@ -141,13 +141,13 @@ recompute_width_table (struct buffer *buf, struct Lisp_Char_Table *disptab)
XSETFASTINT (widthtab->contents[i], character_width (i, disptab));
}
/* Allocate or free the width run cache, as requested by the current
state of current_buffer's cache_long_line_scans variable. */
/* Allocate or free the width run cache, as requested by the
current state of current_buffer's cache_long_scans variable. */
static void
width_run_cache_on_off (void)
{
if (NILP (BVAR (current_buffer, cache_long_line_scans))
if (NILP (BVAR (current_buffer, cache_long_scans))
/* And, for the moment, this feature doesn't work on multibyte
characters. */
|| !NILP (BVAR (current_buffer, enable_multibyte_characters)))
......
......@@ -1879,6 +1879,10 @@ prepare_to_modify_buffer (ptrdiff_t start, ptrdiff_t end,
invalidate_region_cache (current_buffer,
current_buffer->width_run_cache,
start - BEG, Z - end);
if (current_buffer->bidi_paragraph_cache)
invalidate_region_cache (current_buffer,
current_buffer->bidi_paragraph_cache,
start - BEG, Z - end);
}
/* These macros work with an argument named `preserve_ptr'
......
......@@ -598,14 +598,14 @@ fast_looking_at (Lisp_Object regexp, ptrdiff_t pos, ptrdiff_t pos_byte,
/* The newline cache: remembering which sections of text have no newlines. */
/* If the user has requested newline caching, make sure it's on.
/* If the user has requested the long scans caching, make sure it's on.
Otherwise, make sure it's off.
This is our cheezy way of associating an action with the change of
state of a buffer-local variable. */
static void
newline_cache_on_off (struct buffer *buf)
{
if (NILP (BVAR (buf, cache_long_line_scans)))
if (NILP (BVAR (buf, cache_long_scans)))
{
/* It should be off. */
if (buf->newline_cache)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment