diff options
| author | Eli Zaretskii | 2014-03-16 18:28:34 +0200 |
|---|---|---|
| committer | Eli Zaretskii | 2014-03-16 18:28:34 +0200 |
| commit | 2a3d9a06c9a1e6fd4d45eb7c89fd867ca641c563 (patch) | |
| tree | b2308944c089627351224b3eca3834971501b716 /src | |
| parent | b92631bf71bb029af7a5b4bcf3acd6b4484a4afa (diff) | |
| download | emacs-2a3d9a06c9a1e6fd4d45eb7c89fd867ca641c563.tar.gz emacs-2a3d9a06c9a1e6fd4d45eb7c89fd867ca641c563.zip | |
Fix bug #16830 with slow search for newlines in forward-line.
src/search.c (find_newline): Speed up the function when using the
newline cache, by halving the number of calls to
region_cache_forward and region_cache_backward.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 6 | ||||
| -rw-r--r-- | src/search.c | 108 |
2 files changed, 98 insertions, 16 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 424416398e8..30692059f03 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,9 @@ | |||
| 1 | 2014-03-16 Eli Zaretskii <eliz@gnu.org> | ||
| 2 | |||
| 3 | * search.c (find_newline): Speed up the function when using the | ||
| 4 | newline cache, by halving the number of call to | ||
| 5 | region_cache_forward and region_cache_backward. (Bug#16830) | ||
| 6 | |||
| 1 | 2014-03-15 Juanma Barranquero <lekktu@gmail.com> | 7 | 2014-03-15 Juanma Barranquero <lekktu@gmail.com> |
| 2 | 8 | ||
| 3 | * buffer.c (Fset_buffer): Document return value (bug#17015). | 9 | * buffer.c (Fset_buffer): Document return value (bug#17015). |
diff --git a/src/search.c b/src/search.c index 40ab5db495a..3de194c5056 100644 --- a/src/search.c +++ b/src/search.c | |||
| @@ -715,19 +715,62 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, | |||
| 715 | examine. */ | 715 | examine. */ |
| 716 | ptrdiff_t tem, ceiling_byte = end_byte - 1; | 716 | ptrdiff_t tem, ceiling_byte = end_byte - 1; |
| 717 | 717 | ||
| 718 | /* If we're looking for a newline, consult the newline cache | 718 | /* If we're using the newline cache, consult it to see whether |
| 719 | to see where we can avoid some scanning. */ | 719 | we can avoid some scanning. */ |
| 720 | if (newline_cache) | 720 | if (newline_cache) |
| 721 | { | 721 | { |
| 722 | ptrdiff_t next_change; | 722 | ptrdiff_t next_change; |
| 723 | int result = 1; | ||
| 724 | |||
| 723 | immediate_quit = 0; | 725 | immediate_quit = 0; |
| 724 | while (region_cache_forward | 726 | while (start < end && result) |
| 725 | (cache_buffer, newline_cache, start, &next_change)) | 727 | { |
| 726 | start = next_change; | 728 | ptrdiff_t lim1; |
| 729 | |||
| 730 | result = region_cache_forward (cache_buffer, newline_cache, | ||
| 731 | start, &next_change); | ||
| 732 | if (result) | ||
| 733 | { | ||
| 734 | start = next_change; | ||
| 735 | lim1 = next_change = end; | ||
| 736 | } | ||
| 737 | else | ||
| 738 | lim1 = min (next_change, end); | ||
| 739 | |||
| 740 | /* The cache returned zero for this region; see if | ||
| 741 | this is because the region is known and includes | ||
| 742 | only newlines. While at that, count any newlines | ||
| 743 | we bump into, and exit if we found enough off them. */ | ||
| 744 | start_byte = CHAR_TO_BYTE (start); | ||
| 745 | while (start < lim1 | ||
| 746 | && FETCH_BYTE (start_byte) == '\n') | ||
| 747 | { | ||
| 748 | start_byte++; | ||
| 749 | start++; | ||
| 750 | if (--count == 0) | ||
| 751 | { | ||
| 752 | if (bytepos) | ||
| 753 | *bytepos = start_byte; | ||
| 754 | return start; | ||
| 755 | } | ||
| 756 | } | ||
| 757 | /* If we found a non-newline character before hitting | ||
| 758 | position where the cache will again return non-zero | ||
| 759 | (i.e. no newlines beyond that position), it means | ||
| 760 | this region is not yet known to the cache, and we | ||
| 761 | must resort to the "dumb loop" method. */ | ||
| 762 | if (start < next_change && !result) | ||
| 763 | break; | ||
| 764 | result = 1; | ||
| 765 | } | ||
| 766 | if (start >= end) | ||
| 767 | { | ||
| 768 | start = end; | ||
| 769 | start_byte = end_byte; | ||
| 770 | break; | ||
| 771 | } | ||
| 727 | immediate_quit = allow_quit; | 772 | immediate_quit = allow_quit; |
| 728 | 773 | ||
| 729 | start_byte = CHAR_TO_BYTE (start); | ||
| 730 | |||
| 731 | /* START should never be after END. */ | 774 | /* START should never be after END. */ |
| 732 | if (start_byte > ceiling_byte) | 775 | if (start_byte > ceiling_byte) |
| 733 | start_byte = ceiling_byte; | 776 | start_byte = ceiling_byte; |
| @@ -762,9 +805,9 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, | |||
| 762 | unsigned char *nl = memchr (lim_addr + cursor, '\n', - cursor); | 805 | unsigned char *nl = memchr (lim_addr + cursor, '\n', - cursor); |
| 763 | next = nl ? nl - lim_addr : 0; | 806 | next = nl ? nl - lim_addr : 0; |
| 764 | 807 | ||
| 765 | /* If we're looking for newlines, cache the fact that | 808 | /* If we're using the newline cache, cache the fact that |
| 766 | this line's region is free of them. */ | 809 | the region we just traversed is free of newlines. */ |
| 767 | if (newline_cache) | 810 | if (newline_cache && cursor != next) |
| 768 | { | 811 | { |
| 769 | know_region_cache (cache_buffer, newline_cache, | 812 | know_region_cache (cache_buffer, newline_cache, |
| 770 | BYTE_TO_CHAR (lim_byte + cursor), | 813 | BYTE_TO_CHAR (lim_byte + cursor), |
| @@ -800,14 +843,47 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, | |||
| 800 | if (newline_cache) | 843 | if (newline_cache) |
| 801 | { | 844 | { |
| 802 | ptrdiff_t next_change; | 845 | ptrdiff_t next_change; |
| 846 | int result = 1; | ||
| 847 | |||
| 803 | immediate_quit = 0; | 848 | immediate_quit = 0; |
| 804 | while (region_cache_backward | 849 | while (start > end && result) |
| 805 | (cache_buffer, newline_cache, start, &next_change)) | 850 | { |
| 806 | start = next_change; | 851 | ptrdiff_t lim1; |
| 852 | |||
| 853 | result = region_cache_backward (cache_buffer, newline_cache, | ||
| 854 | start, &next_change); | ||
| 855 | if (result) | ||
| 856 | { | ||
| 857 | start = next_change; | ||
| 858 | lim1 = next_change = end; | ||
| 859 | } | ||
| 860 | else | ||
| 861 | lim1 = max (next_change, end); | ||
| 862 | start_byte = CHAR_TO_BYTE (start); | ||
| 863 | while (start > lim1 | ||
| 864 | && FETCH_BYTE (start_byte - 1) == '\n') | ||
| 865 | { | ||
| 866 | if (++count == 0) | ||
| 867 | { | ||
| 868 | if (bytepos) | ||
| 869 | *bytepos = start_byte; | ||
| 870 | return start; | ||
| 871 | } | ||
| 872 | start_byte--; | ||
| 873 | start--; | ||
| 874 | } | ||
| 875 | if (start > next_change && !result) | ||
| 876 | break; | ||
| 877 | result = 1; | ||
| 878 | } | ||
| 879 | if (start <= end) | ||
| 880 | { | ||
| 881 | start = end; | ||
| 882 | start_byte = end_byte; | ||
| 883 | break; | ||
| 884 | } | ||
| 807 | immediate_quit = allow_quit; | 885 | immediate_quit = allow_quit; |
| 808 | 886 | ||
| 809 | start_byte = CHAR_TO_BYTE (start); | ||
| 810 | |||
| 811 | /* Start should never be at or before end. */ | 887 | /* Start should never be at or before end. */ |
| 812 | if (start_byte <= ceiling_byte) | 888 | if (start_byte <= ceiling_byte) |
| 813 | start_byte = ceiling_byte + 1; | 889 | start_byte = ceiling_byte + 1; |
| @@ -840,7 +916,7 @@ find_newline (ptrdiff_t start, ptrdiff_t start_byte, ptrdiff_t end, | |||
| 840 | 916 | ||
| 841 | /* If we're looking for newlines, cache the fact that | 917 | /* If we're looking for newlines, cache the fact that |
| 842 | this line's region is free of them. */ | 918 | this line's region is free of them. */ |
| 843 | if (newline_cache) | 919 | if (newline_cache && cursor != prev + 1) |
| 844 | { | 920 | { |
| 845 | know_region_cache (cache_buffer, newline_cache, | 921 | know_region_cache (cache_buffer, newline_cache, |
| 846 | BYTE_TO_CHAR (ceiling_byte + prev + 1), | 922 | BYTE_TO_CHAR (ceiling_byte + prev + 1), |