diff options
| author | Dmitry Antipov | 2012-07-20 20:05:47 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2012-07-20 20:05:47 +0400 |
| commit | 9928463dcdb0164477785e83406602065de79ef8 (patch) | |
| tree | 14d6b28885b7e333733ff4eb62275e6e425f81b3 /src/buffer.c | |
| parent | f8643a6b9e35af22b69a84f83df5d9410de82f16 (diff) | |
| download | emacs-9928463dcdb0164477785e83406602065de79ef8.tar.gz emacs-9928463dcdb0164477785e83406602065de79ef8.zip | |
Add indirection counting to speed up Fkill_buffer.
* buffer.h (struct buffer): New member.
* buffer.c (Fget_buffer_create): Set indirection counter to 0.
(Fmake_indirect_buffer): Set indirection counter to -1, increment
base buffer indirection counter.
(compact_buffer): If ENABLE_CHECKING, verify indirection counters.
(Fkill_buffer): Adjust indirection counters as needed, don't walk
through buffer list if indirection counter is 0.
Diffstat (limited to 'src/buffer.c')
| -rw-r--r-- | src/buffer.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/src/buffer.c b/src/buffer.c index b722ff135dd..5f9f6a79b67 100644 --- a/src/buffer.c +++ b/src/buffer.c | |||
| @@ -329,7 +329,9 @@ even if it is dead. The return value is never nil. */) | |||
| 329 | 329 | ||
| 330 | /* An ordinary buffer uses its own struct buffer_text. */ | 330 | /* An ordinary buffer uses its own struct buffer_text. */ |
| 331 | b->text = &b->own_text; | 331 | b->text = &b->own_text; |
| 332 | b->base_buffer = 0; | 332 | b->base_buffer = NULL; |
| 333 | /* No one shares the text with us now. */ | ||
| 334 | b->indirections = 0; | ||
| 333 | 335 | ||
| 334 | BUF_GAP_SIZE (b) = 20; | 336 | BUF_GAP_SIZE (b) = 20; |
| 335 | BLOCK_INPUT; | 337 | BLOCK_INPUT; |
| @@ -568,12 +570,18 @@ CLONE nil means the indirect buffer's state is reset to default values. */) | |||
| 568 | 570 | ||
| 569 | b = allocate_buffer (); | 571 | b = allocate_buffer (); |
| 570 | 572 | ||
| 573 | /* No double indirection - if base buffer is indirect, | ||
| 574 | new buffer becomes an indirect to base's base. */ | ||
| 571 | b->base_buffer = (XBUFFER (base_buffer)->base_buffer | 575 | b->base_buffer = (XBUFFER (base_buffer)->base_buffer |
| 572 | ? XBUFFER (base_buffer)->base_buffer | 576 | ? XBUFFER (base_buffer)->base_buffer |
| 573 | : XBUFFER (base_buffer)); | 577 | : XBUFFER (base_buffer)); |
| 574 | 578 | ||
| 575 | /* Use the base buffer's text object. */ | 579 | /* Use the base buffer's text object. */ |
| 576 | b->text = b->base_buffer->text; | 580 | b->text = b->base_buffer->text; |
| 581 | /* We have no own text. */ | ||
| 582 | b->indirections = -1; | ||
| 583 | /* Notify base buffer that we share the text now. */ | ||
| 584 | b->base_buffer->indirections++; | ||
| 577 | 585 | ||
| 578 | b->pt = b->base_buffer->pt; | 586 | b->pt = b->base_buffer->pt; |
| 579 | b->begv = b->base_buffer->begv; | 587 | b->begv = b->base_buffer->begv; |
| @@ -1439,6 +1447,15 @@ No argument or nil as argument means do this for the current buffer. */) | |||
| 1439 | int | 1447 | int |
| 1440 | compact_buffer (struct buffer *buffer) | 1448 | compact_buffer (struct buffer *buffer) |
| 1441 | { | 1449 | { |
| 1450 | /* Verify indirection counters. */ | ||
| 1451 | if (buffer->base_buffer) | ||
| 1452 | { | ||
| 1453 | eassert (buffer->indirections == -1); | ||
| 1454 | eassert (buffer->base_buffer->indirections > 0); | ||
| 1455 | } | ||
| 1456 | else | ||
| 1457 | eassert (buffer->indirections >= 0); | ||
| 1458 | |||
| 1442 | /* Skip dead buffers, indirect buffers and buffers | 1459 | /* Skip dead buffers, indirect buffers and buffers |
| 1443 | which aren't changed since last compaction. */ | 1460 | which aren't changed since last compaction. */ |
| 1444 | if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name)) | 1461 | if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name)) |
| @@ -1555,10 +1572,19 @@ cleaning up all windows currently displaying the buffer to be killed. */) | |||
| 1555 | if (EQ (buffer, XWINDOW (minibuf_window)->buffer)) | 1572 | if (EQ (buffer, XWINDOW (minibuf_window)->buffer)) |
| 1556 | return Qnil; | 1573 | return Qnil; |
| 1557 | 1574 | ||
| 1558 | /* When we kill a base buffer, kill all its indirect buffers. | 1575 | /* Notify our base buffer that we don't share the text anymore. */ |
| 1576 | if (b->base_buffer) | ||
| 1577 | { | ||
| 1578 | eassert (b->indirections == -1); | ||
| 1579 | b->base_buffer->indirections--; | ||
| 1580 | eassert (b->base_buffer->indirections >= 0); | ||
| 1581 | } | ||
| 1582 | |||
| 1583 | /* When we kill an ordinary buffer which shares it's buffer text | ||
| 1584 | with indirect buffer(s), we must kill indirect buffer(s) too. | ||
| 1559 | We do it at this stage so nothing terrible happens if they | 1585 | We do it at this stage so nothing terrible happens if they |
| 1560 | ask questions or their hooks get errors. */ | 1586 | ask questions or their hooks get errors. */ |
| 1561 | if (! b->base_buffer) | 1587 | if (!b->base_buffer && b->indirections > 0) |
| 1562 | { | 1588 | { |
| 1563 | struct buffer *other; | 1589 | struct buffer *other; |
| 1564 | 1590 | ||