Mercurial > vim
comparison src/undo.c @ 2230:290ee42cae85 vim73
Remove old and unused method to allocate memory for undo.
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Sat, 29 May 2010 15:40:47 +0200 |
parents | d45902a5c61c |
children | aa6412cab544 |
comparison
equal
deleted
inserted
replaced
2229:d45902a5c61c | 2230:290ee42cae85 |
---|---|
70 * +-----|---------+ +-----|---------+ | 70 * +-----|---------+ +-----|---------+ |
71 * | | | 71 * | | |
72 * etc. etc. | 72 * etc. etc. |
73 * | 73 * |
74 * | 74 * |
75 * All data is allocated with U_ALLOC_LINE(), it will be freed as soon as the | 75 * All data is allocated and will all be freed when the buffer is unloaded. |
76 * buffer is unloaded. | |
77 */ | 76 */ |
78 | 77 |
79 /* Uncomment the next line for including the u_check() function. This warns | 78 /* Uncomment the next line for including the u_check() function. This warns |
80 * for errors in the debug information. */ | 79 * for errors in the debug information. */ |
81 /* #define U_DEBUG 1 */ | 80 /* #define U_DEBUG 1 */ |
85 #if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) | 84 #if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) |
86 # include "vimio.h" /* for vim_read(), must be before vim.h */ | 85 # include "vimio.h" /* for vim_read(), must be before vim.h */ |
87 #endif | 86 #endif |
88 | 87 |
89 #include "vim.h" | 88 #include "vim.h" |
90 | |
91 /* See below: use malloc()/free() for memory management. */ | |
92 #define U_USE_MALLOC 1 | |
93 | 89 |
94 static void u_unch_branch __ARGS((u_header_T *uhp)); | 90 static void u_unch_branch __ARGS((u_header_T *uhp)); |
95 static u_entry_T *u_get_headentry __ARGS((void)); | 91 static u_entry_T *u_get_headentry __ARGS((void)); |
96 static void u_getbot __ARGS((void)); | 92 static void u_getbot __ARGS((void)); |
97 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); | 93 static int u_savecommon __ARGS((linenr_T, linenr_T, linenr_T)); |
111 static int serialize_uep __ARGS((u_entry_T *uep, FILE *fp)); | 107 static int serialize_uep __ARGS((u_entry_T *uep, FILE *fp)); |
112 static void serialize_pos __ARGS((pos_T pos, FILE *fp)); | 108 static void serialize_pos __ARGS((pos_T pos, FILE *fp)); |
113 static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); | 109 static void serialize_visualinfo __ARGS((visualinfo_T *info, FILE *fp)); |
114 #endif | 110 #endif |
115 | 111 |
116 #ifdef U_USE_MALLOC | 112 #define U_ALLOC_LINE(size) lalloc((long_u)(size), FALSE) |
117 # define U_FREE_LINE(ptr) vim_free(ptr) | |
118 # define U_ALLOC_LINE(size) lalloc((long_u)((size) + 1), FALSE) | |
119 #else | |
120 static void u_free_line __ARGS((char_u *ptr, int keep)); | |
121 static char_u *u_alloc_line __ARGS((unsigned size)); | |
122 # define U_FREE_LINE(ptr) u_free_line((ptr), FALSE) | |
123 # define U_ALLOC_LINE(size) u_alloc_line(size) | |
124 #endif | |
125 static char_u *u_save_line __ARGS((linenr_T)); | 113 static char_u *u_save_line __ARGS((linenr_T)); |
126 | 114 |
127 static long u_newcount, u_oldcount; | 115 static long u_newcount, u_oldcount; |
128 | 116 |
129 /* | 117 /* |
402 { | 390 { |
403 /* | 391 /* |
404 * Make a new header entry. Do this first so that we don't mess | 392 * Make a new header entry. Do this first so that we don't mess |
405 * up the undo info when out of memory. | 393 * up the undo info when out of memory. |
406 */ | 394 */ |
407 uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T)); | 395 uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T)); |
408 if (uhp == NULL) | 396 if (uhp == NULL) |
409 goto nomem; | 397 goto nomem; |
410 #ifdef U_DEBUG | 398 #ifdef U_DEBUG |
411 uhp->uh_magic = UH_MAGIC; | 399 uhp->uh_magic = UH_MAGIC; |
412 #endif | 400 #endif |
595 #endif | 583 #endif |
596 | 584 |
597 /* | 585 /* |
598 * add lines in front of entry list | 586 * add lines in front of entry list |
599 */ | 587 */ |
600 uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); | 588 uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T)); |
601 if (uep == NULL) | 589 if (uep == NULL) |
602 goto nomem; | 590 goto nomem; |
603 vim_memset(uep, 0, sizeof(u_entry_T)); | 591 vim_memset(uep, 0, sizeof(u_entry_T)); |
604 #ifdef U_DEBUG | 592 #ifdef U_DEBUG |
605 uep->ue_magic = UE_MAGIC; | 593 uep->ue_magic = UE_MAGIC; |
622 } | 610 } |
623 | 611 |
624 if (size > 0) | 612 if (size > 0) |
625 { | 613 { |
626 if ((uep->ue_array = (char_u **)U_ALLOC_LINE( | 614 if ((uep->ue_array = (char_u **)U_ALLOC_LINE( |
627 (unsigned)(sizeof(char_u *) * size))) == NULL) | 615 sizeof(char_u *) * size)) == NULL) |
628 { | 616 { |
629 u_freeentry(uep, 0L); | 617 u_freeentry(uep, 0L); |
630 goto nomem; | 618 goto nomem; |
631 } | 619 } |
632 for (i = 0, lnum = top + 1; i < size; ++i) | 620 for (i = 0, lnum = top + 1; i < size; ++i) |
901 str_len = get4c(fp); | 889 str_len = get4c(fp); |
902 if (str_len < 0) | 890 if (str_len < 0) |
903 goto error; | 891 goto error; |
904 else if (str_len > 0) | 892 else if (str_len > 0) |
905 { | 893 { |
906 if ((line_ptr = U_ALLOC_LINE(str_len)) == NULL) | 894 if ((line_ptr = U_ALLOC_LINE(str_len + 1)) == NULL) |
907 goto error; | 895 goto error; |
908 for (i = 0; i < str_len; i++) | 896 for (i = 0; i < str_len; i++) |
909 line_ptr[i] = (char_u)getc(fp); | 897 line_ptr[i] = (char_u)getc(fp); |
910 line_ptr[i] = NUL; | 898 line_ptr[i] = NUL; |
911 } | 899 } |
919 num_head = get4c(fp); | 907 num_head = get4c(fp); |
920 seq_last = get4c(fp); | 908 seq_last = get4c(fp); |
921 seq_cur = get4c(fp); | 909 seq_cur = get4c(fp); |
922 seq_time = get8ctime(fp); | 910 seq_time = get8ctime(fp); |
923 | 911 |
924 if (num_head < 0) | |
925 num_head = 0; | |
926 | |
927 /* uhp_table will store the freshly created undo headers we allocate | 912 /* uhp_table will store the freshly created undo headers we allocate |
928 * until we insert them into curbuf. The table remains sorted by the | 913 * until we insert them into curbuf. The table remains sorted by the |
929 * sequence numbers of the headers. */ | 914 * sequence numbers of the headers. |
930 uhp_table = (u_header_T **)U_ALLOC_LINE(num_head * sizeof(u_header_T *)); | 915 * When there are no headers uhp_table is NULL. */ |
931 if (uhp_table == NULL) | 916 if (num_head > 0) |
932 goto error; | 917 { |
933 vim_memset(uhp_table, 0, num_head * sizeof(u_header_T *)); | 918 uhp_table = (u_header_T **)U_ALLOC_LINE( |
919 num_head * sizeof(u_header_T *)); | |
920 if (uhp_table == NULL) | |
921 goto error; | |
922 vim_memset(uhp_table, 0, num_head * sizeof(u_header_T *)); | |
923 } | |
934 | 924 |
935 c = get2c(fp); | 925 c = get2c(fp); |
936 while (c == UF_HEADER_MAGIC) | 926 while (c == UF_HEADER_MAGIC) |
937 { | 927 { |
938 if (num_read_uhps >= num_head) | 928 if (num_read_uhps >= num_head) |
940 EMSG2(_("E831 Undo file corruption: num_head: %s"), file_name); | 930 EMSG2(_("E831 Undo file corruption: num_head: %s"), file_name); |
941 u_free_uhp(uhp); | 931 u_free_uhp(uhp); |
942 goto error; | 932 goto error; |
943 } | 933 } |
944 | 934 |
945 uhp = (u_header_T *)U_ALLOC_LINE((unsigned)sizeof(u_header_T)); | 935 uhp = (u_header_T *)U_ALLOC_LINE(sizeof(u_header_T)); |
946 if (uhp == NULL) | 936 if (uhp == NULL) |
947 goto error; | 937 goto error; |
948 vim_memset(uhp, 0, sizeof(u_header_T)); | 938 vim_memset(uhp, 0, sizeof(u_header_T)); |
949 /* We're not actually trying to store pointers here. We're just storing | 939 /* We're not actually trying to store pointers here. We're just storing |
950 * IDs so we can swizzle them into pointers later - hence the type | 940 * IDs so we can swizzle them into pointers later - hence the type |
956 uhp->uh_seq = get4c(fp); | 946 uhp->uh_seq = get4c(fp); |
957 if (uhp->uh_seq <= 0) | 947 if (uhp->uh_seq <= 0) |
958 { | 948 { |
959 EMSG2(_("E825: Undo file corruption: invalid uh_seq.: %s"), | 949 EMSG2(_("E825: Undo file corruption: invalid uh_seq.: %s"), |
960 file_name); | 950 file_name); |
961 U_FREE_LINE(uhp); | 951 vim_free(uhp); |
962 goto error; | 952 goto error; |
963 } | 953 } |
964 uhp->uh_walk = 0; | 954 uhp->uh_walk = 0; |
965 unserialize_pos(&uhp->uh_cursor, fp); | 955 unserialize_pos(&uhp->uh_cursor, fp); |
966 #ifdef FEAT_VIRTUALEDIT | 956 #ifdef FEAT_VIRTUALEDIT |
985 * entire uep in bytes minus the length of the strings within. | 975 * entire uep in bytes minus the length of the strings within. |
986 * -1 is a sentinel value meaning no more ueps.*/ | 976 * -1 is a sentinel value meaning no more ueps.*/ |
987 last_uep = NULL; | 977 last_uep = NULL; |
988 while ((uep_len = get4c(fp)) != -1) | 978 while ((uep_len = get4c(fp)) != -1) |
989 { | 979 { |
990 uep = (u_entry_T *)U_ALLOC_LINE((unsigned)sizeof(u_entry_T)); | 980 uep = (u_entry_T *)U_ALLOC_LINE(sizeof(u_entry_T)); |
991 if (uep == NULL) | 981 if (uep == NULL) |
992 { | 982 { |
993 u_free_uhp(uhp); | 983 u_free_uhp(uhp); |
994 goto error; | 984 goto error; |
995 } | 985 } |
1003 uep->ue_top = get4c(fp); | 993 uep->ue_top = get4c(fp); |
1004 uep->ue_bot = get4c(fp); | 994 uep->ue_bot = get4c(fp); |
1005 uep->ue_lcount = get4c(fp); | 995 uep->ue_lcount = get4c(fp); |
1006 uep->ue_size = get4c(fp); | 996 uep->ue_size = get4c(fp); |
1007 uep->ue_next = NULL; | 997 uep->ue_next = NULL; |
1008 array = (char_u **)U_ALLOC_LINE( | 998 if (uep->ue_size > 0) |
1009 (unsigned)(sizeof(char_u *) * uep->ue_size)); | |
1010 if (array == NULL) | |
1011 { | 999 { |
1012 u_free_uhp(uhp); | 1000 array = (char_u **)U_ALLOC_LINE( |
1013 goto error; | 1001 sizeof(char_u *) * uep->ue_size); |
1002 if (array == NULL) | |
1003 { | |
1004 u_free_uhp(uhp); | |
1005 goto error; | |
1006 } | |
1007 vim_memset(array, 0, sizeof(char_u *) * uep->ue_size); | |
1014 } | 1008 } |
1015 vim_memset(array, 0, sizeof(char_u *) * uep->ue_size); | |
1016 uep->ue_array = array; | 1009 uep->ue_array = array; |
1017 | 1010 |
1018 for (i = 0; i < uep->ue_size; i++) | 1011 for (i = 0; i < uep->ue_size; i++) |
1019 { | 1012 { |
1020 line_len = get4c(fp); | 1013 line_len = get4c(fp); |
1021 /* U_ALLOC_LINE provides an extra byte for the NUL terminator.*/ | 1014 if (line_len >= 0) |
1022 line = (char_u *)U_ALLOC_LINE( | 1015 line = (char_u *)U_ALLOC_LINE(line_len + 1); |
1023 (unsigned)(sizeof(char_u) * line_len)); | 1016 else |
1017 line = NULL; | |
1024 if (line == NULL) | 1018 if (line == NULL) |
1025 { | 1019 { |
1026 u_free_uhp(uhp); | 1020 u_free_uhp(uhp); |
1027 goto error; | 1021 goto error; |
1028 } | 1022 } |
1113 curbuf->b_u_line_colnr = line_colnr; | 1107 curbuf->b_u_line_colnr = line_colnr; |
1114 curbuf->b_u_numhead = num_head; | 1108 curbuf->b_u_numhead = num_head; |
1115 curbuf->b_u_seq_last = seq_last; | 1109 curbuf->b_u_seq_last = seq_last; |
1116 curbuf->b_u_seq_cur = seq_cur; | 1110 curbuf->b_u_seq_cur = seq_cur; |
1117 curbuf->b_u_seq_time = seq_time; | 1111 curbuf->b_u_seq_time = seq_time; |
1118 U_FREE_LINE(uhp_table); | 1112 vim_free(uhp_table); |
1119 #ifdef U_DEBUG | 1113 #ifdef U_DEBUG |
1120 u_check(TRUE); | 1114 u_check(TRUE); |
1121 #endif | 1115 #endif |
1122 if (name != NULL) | 1116 if (name != NULL) |
1123 smsg((char_u *)_("Finished reading undo file %s"), file_name); | 1117 smsg((char_u *)_("Finished reading undo file %s"), file_name); |
1124 goto theend; | 1118 goto theend; |
1125 | 1119 |
1126 error: | 1120 error: |
1127 if (line_ptr != NULL) | 1121 vim_free(line_ptr); |
1128 U_FREE_LINE(line_ptr); | |
1129 if (uhp_table != NULL) | 1122 if (uhp_table != NULL) |
1130 { | 1123 { |
1131 for (i = 0; i < num_head; i++) | 1124 for (i = 0; i < num_head; i++) |
1132 if (uhp_table[i] != NULL) | 1125 if (uhp_table[i] != NULL) |
1133 u_free_uhp(uhp_table[i]); | 1126 u_free_uhp(uhp_table[i]); |
1134 U_FREE_LINE(uhp_table); | 1127 vim_free(uhp_table); |
1135 } | 1128 } |
1136 | 1129 |
1137 theend: | 1130 theend: |
1138 if (fp != NULL) | 1131 if (fp != NULL) |
1139 fclose(fp); | 1132 fclose(fp); |
1154 { | 1147 { |
1155 nuep = uep->ue_next; | 1148 nuep = uep->ue_next; |
1156 u_freeentry(uep, uep->ue_size); | 1149 u_freeentry(uep, uep->ue_size); |
1157 uep = nuep; | 1150 uep = nuep; |
1158 } | 1151 } |
1159 U_FREE_LINE(uhp); | 1152 vim_free(uhp); |
1160 } | 1153 } |
1161 | 1154 |
1162 /* | 1155 /* |
1163 * Serialize "uep" to "fp". | 1156 * Serialize "uep" to "fp". |
1164 */ | 1157 */ |
1992 | 1985 |
1993 /* delete the lines between top and bot and save them in newarray */ | 1986 /* delete the lines between top and bot and save them in newarray */ |
1994 if (oldsize > 0) | 1987 if (oldsize > 0) |
1995 { | 1988 { |
1996 if ((newarray = (char_u **)U_ALLOC_LINE( | 1989 if ((newarray = (char_u **)U_ALLOC_LINE( |
1997 (unsigned)(sizeof(char_u *) * oldsize))) == NULL) | 1990 sizeof(char_u *) * oldsize)) == NULL) |
1998 { | 1991 { |
1999 do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize)); | 1992 do_outofmem_msg((long_u)(sizeof(char_u *) * oldsize)); |
2000 /* | 1993 /* |
2001 * We have messed up the entry list, repair is impossible. | 1994 * We have messed up the entry list, repair is impossible. |
2002 * we have to free the rest of the list. | 1995 * we have to free the rest of the list. |
2036 */ | 2029 */ |
2037 if (empty_buffer && lnum == 0) | 2030 if (empty_buffer && lnum == 0) |
2038 ml_replace((linenr_T)1, uep->ue_array[i], TRUE); | 2031 ml_replace((linenr_T)1, uep->ue_array[i], TRUE); |
2039 else | 2032 else |
2040 ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE); | 2033 ml_append(lnum, uep->ue_array[i], (colnr_T)0, FALSE); |
2041 U_FREE_LINE(uep->ue_array[i]); | 2034 vim_free(uep->ue_array[i]); |
2042 } | 2035 } |
2043 U_FREE_LINE((char_u *)uep->ue_array); | 2036 vim_free((char_u *)uep->ue_array); |
2044 } | 2037 } |
2045 | 2038 |
2046 /* adjust marks */ | 2039 /* adjust marks */ |
2047 if (oldsize != newsize) | 2040 if (oldsize != newsize) |
2048 { | 2041 { |
2576 } | 2569 } |
2577 | 2570 |
2578 #ifdef U_DEBUG | 2571 #ifdef U_DEBUG |
2579 uhp->uh_magic = 0; | 2572 uhp->uh_magic = 0; |
2580 #endif | 2573 #endif |
2581 U_FREE_LINE((char_u *)uhp); | 2574 vim_free((char_u *)uhp); |
2582 --buf->b_u_numhead; | 2575 --buf->b_u_numhead; |
2583 } | 2576 } |
2584 | 2577 |
2585 /* | 2578 /* |
2586 * free entry 'uep' and 'n' lines in uep->ue_array[] | 2579 * free entry 'uep' and 'n' lines in uep->ue_array[] |
2589 u_freeentry(uep, n) | 2582 u_freeentry(uep, n) |
2590 u_entry_T *uep; | 2583 u_entry_T *uep; |
2591 long n; | 2584 long n; |
2592 { | 2585 { |
2593 while (n > 0) | 2586 while (n > 0) |
2594 U_FREE_LINE(uep->ue_array[--n]); | 2587 vim_free(uep->ue_array[--n]); |
2595 U_FREE_LINE((char_u *)uep->ue_array); | 2588 vim_free((char_u *)uep->ue_array); |
2596 #ifdef U_DEBUG | 2589 #ifdef U_DEBUG |
2597 uep->ue_magic = 0; | 2590 uep->ue_magic = 0; |
2598 #endif | 2591 #endif |
2599 U_FREE_LINE((char_u *)uep); | 2592 vim_free((char_u *)uep); |
2600 } | 2593 } |
2601 | 2594 |
2602 /* | 2595 /* |
2603 * invalidate the undo buffer; called when storage has already been released | 2596 * invalidate the undo buffer; called when storage has already been released |
2604 */ | 2597 */ |
2641 void | 2634 void |
2642 u_clearline() | 2635 u_clearline() |
2643 { | 2636 { |
2644 if (curbuf->b_u_line_ptr != NULL) | 2637 if (curbuf->b_u_line_ptr != NULL) |
2645 { | 2638 { |
2646 U_FREE_LINE(curbuf->b_u_line_ptr); | 2639 vim_free(curbuf->b_u_line_ptr); |
2647 curbuf->b_u_line_ptr = NULL; | 2640 curbuf->b_u_line_ptr = NULL; |
2648 curbuf->b_u_line_lnum = 0; | 2641 curbuf->b_u_line_lnum = 0; |
2649 } | 2642 } |
2650 } | 2643 } |
2651 | 2644 |
2680 do_outofmem_msg((long_u)0); | 2673 do_outofmem_msg((long_u)0); |
2681 return; | 2674 return; |
2682 } | 2675 } |
2683 ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE); | 2676 ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, TRUE); |
2684 changed_bytes(curbuf->b_u_line_lnum, 0); | 2677 changed_bytes(curbuf->b_u_line_lnum, 0); |
2685 U_FREE_LINE(curbuf->b_u_line_ptr); | 2678 vim_free(curbuf->b_u_line_ptr); |
2686 curbuf->b_u_line_ptr = oldp; | 2679 curbuf->b_u_line_ptr = oldp; |
2687 | 2680 |
2688 t = curbuf->b_u_line_colnr; | 2681 t = curbuf->b_u_line_colnr; |
2689 if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) | 2682 if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) |
2690 curbuf->b_u_line_colnr = curwin->w_cursor.col; | 2683 curbuf->b_u_line_colnr = curwin->w_cursor.col; |
2692 curwin->w_cursor.lnum = curbuf->b_u_line_lnum; | 2685 curwin->w_cursor.lnum = curbuf->b_u_line_lnum; |
2693 check_cursor_col(); | 2686 check_cursor_col(); |
2694 } | 2687 } |
2695 | 2688 |
2696 /* | 2689 /* |
2697 * There are two implementations of the memory management for undo: | |
2698 * 1. Use the standard malloc()/free() functions. | |
2699 * This should be fast for allocating memory, but when a buffer is | |
2700 * abandoned every single allocated chunk must be freed, which may be slow. | |
2701 * 2. Allocate larger blocks of memory and keep track of chunks ourselves. | |
2702 * This is fast for abandoning, but the use of linked lists is slow for | |
2703 * finding a free chunk. Esp. when a lot of lines are changed or deleted. | |
2704 * A bit of profiling showed that the first method is faster, especially when | |
2705 * making a large number of changes, under the condition that malloc()/free() | |
2706 * is implemented efficiently. | |
2707 */ | |
2708 #ifdef U_USE_MALLOC | |
2709 /* | |
2710 * Version of undo memory allocation using malloc()/free() | |
2711 * | |
2712 * U_FREE_LINE() and U_ALLOC_LINE() are macros that invoke vim_free() and | |
2713 * lalloc() directly. | |
2714 */ | |
2715 | |
2716 /* | |
2717 * Free all allocated memory blocks for the buffer 'buf'. | 2690 * Free all allocated memory blocks for the buffer 'buf'. |
2718 */ | 2691 */ |
2719 void | 2692 void |
2720 u_blockfree(buf) | 2693 u_blockfree(buf) |
2721 buf_T *buf; | 2694 buf_T *buf; |
2722 { | 2695 { |
2723 while (buf->b_u_oldhead != NULL) | 2696 while (buf->b_u_oldhead != NULL) |
2724 u_freeheader(buf, buf->b_u_oldhead, NULL); | 2697 u_freeheader(buf, buf->b_u_oldhead, NULL); |
2725 U_FREE_LINE(buf->b_u_line_ptr); | 2698 vim_free(buf->b_u_line_ptr); |
2726 } | 2699 } |
2727 | 2700 |
2728 #else | 2701 /* |
2729 /* | 2702 * u_save_line(): allocate memory and copy line 'lnum' into it. |
2730 * Storage allocation for the undo lines and blocks of the current file. | 2703 * Returns NULL when out of memory. |
2731 * Version where Vim keeps track of the available memory. | |
2732 */ | |
2733 | |
2734 /* | |
2735 * Memory is allocated in relatively large blocks. These blocks are linked | |
2736 * in the allocated block list, headed by curbuf->b_block_head. They are all | |
2737 * freed when abandoning a file, so we don't have to free every single line. | |
2738 * The list is kept sorted on memory address. | |
2739 * block_alloc() allocates a block. | |
2740 * m_blockfree() frees all blocks. | |
2741 * | |
2742 * The available chunks of memory are kept in free chunk lists. There is | |
2743 * one free list for each block of allocated memory. The list is kept sorted | |
2744 * on memory address. | |
2745 * u_alloc_line() gets a chunk from the free lists. | |
2746 * u_free_line() returns a chunk to the free lists. | |
2747 * curbuf->b_m_search points to the chunk before the chunk that was | |
2748 * freed/allocated the last time. | |
2749 * curbuf->b_mb_current points to the b_head where curbuf->b_m_search | |
2750 * points into the free list. | |
2751 * | |
2752 * | |
2753 * b_block_head /---> block #1 /---> block #2 | |
2754 * mb_next ---/ mb_next ---/ mb_next ---> NULL | |
2755 * mb_info mb_info mb_info | |
2756 * | | | | |
2757 * V V V | |
2758 * NULL free chunk #1.1 free chunk #2.1 | |
2759 * | | | |
2760 * V V | |
2761 * free chunk #1.2 NULL | |
2762 * | | |
2763 * V | |
2764 * NULL | |
2765 * | |
2766 * When a single free chunk list would have been used, it could take a lot | |
2767 * of time in u_free_line() to find the correct place to insert a chunk in the | |
2768 * free list. The single free list would become very long when many lines are | |
2769 * changed (e.g. with :%s/^M$//). | |
2770 */ | |
2771 | |
2772 /* | |
2773 * this blocksize is used when allocating new lines | |
2774 */ | |
2775 #define MEMBLOCKSIZE 2044 | |
2776 | |
2777 /* | |
2778 * The size field contains the size of the chunk, including the size field | |
2779 * itself. | |
2780 * | |
2781 * When the chunk is not in-use it is preceded with the m_info structure. | |
2782 * The m_next field links it in one of the free chunk lists. | |
2783 * | |
2784 * On most unix systems structures have to be longword (32 or 64 bit) aligned. | |
2785 * On most other systems they are short (16 bit) aligned. | |
2786 */ | |
2787 | |
2788 /* the structure definitions are now in structs.h */ | |
2789 | |
2790 #ifdef ALIGN_LONG | |
2791 /* size of m_size */ | |
2792 # define M_OFFSET (sizeof(long_u)) | |
2793 #else | |
2794 /* size of m_size */ | |
2795 # define M_OFFSET (sizeof(short_u)) | |
2796 #endif | |
2797 | |
2798 static char_u *u_blockalloc __ARGS((long_u)); | |
2799 | |
2800 /* | |
2801 * Allocate a block of memory and link it in the allocated block list. | |
2802 */ | |
2803 static char_u * | |
2804 u_blockalloc(size) | |
2805 long_u size; | |
2806 { | |
2807 mblock_T *p; | |
2808 mblock_T *mp, *next; | |
2809 | |
2810 p = (mblock_T *)lalloc(size + sizeof(mblock_T), FALSE); | |
2811 if (p != NULL) | |
2812 { | |
2813 /* Insert the block into the allocated block list, keeping it | |
2814 sorted on address. */ | |
2815 for (mp = &curbuf->b_block_head; | |
2816 (next = mp->mb_next) != NULL && next < p; | |
2817 mp = next) | |
2818 ; | |
2819 p->mb_next = next; /* link in block list */ | |
2820 p->mb_size = size; | |
2821 p->mb_maxsize = 0; /* nothing free yet */ | |
2822 mp->mb_next = p; | |
2823 p->mb_info.m_next = NULL; /* clear free list */ | |
2824 p->mb_info.m_size = 0; | |
2825 curbuf->b_mb_current = p; /* remember current block */ | |
2826 curbuf->b_m_search = NULL; | |
2827 p++; /* return usable memory */ | |
2828 } | |
2829 return (char_u *)p; | |
2830 } | |
2831 | |
2832 /* | |
2833 * free all allocated memory blocks for the buffer 'buf' | |
2834 */ | |
2835 void | |
2836 u_blockfree(buf) | |
2837 buf_T *buf; | |
2838 { | |
2839 mblock_T *p, *np; | |
2840 | |
2841 for (p = buf->b_block_head.mb_next; p != NULL; p = np) | |
2842 { | |
2843 np = p->mb_next; | |
2844 vim_free(p); | |
2845 } | |
2846 buf->b_block_head.mb_next = NULL; | |
2847 buf->b_m_search = NULL; | |
2848 buf->b_mb_current = NULL; | |
2849 } | |
2850 | |
2851 /* | |
2852 * Free a chunk of memory for the current buffer. | |
2853 * Insert the chunk into the correct free list, keeping it sorted on address. | |
2854 */ | |
2855 static void | |
2856 u_free_line(ptr, keep) | |
2857 char_u *ptr; | |
2858 int keep; /* don't free the block when it's empty */ | |
2859 { | |
2860 minfo_T *next; | |
2861 minfo_T *prev, *curr; | |
2862 minfo_T *mp; | |
2863 mblock_T *nextb; | |
2864 mblock_T *prevb; | |
2865 long_u maxsize; | |
2866 | |
2867 if (ptr == NULL || ptr == IObuff) | |
2868 return; /* illegal address can happen in out-of-memory situations */ | |
2869 | |
2870 mp = (minfo_T *)(ptr - M_OFFSET); | |
2871 | |
2872 /* find block where chunk could be a part off */ | |
2873 /* if we change curbuf->b_mb_current, curbuf->b_m_search is set to NULL */ | |
2874 if (curbuf->b_mb_current == NULL || mp < (minfo_T *)curbuf->b_mb_current) | |
2875 { | |
2876 curbuf->b_mb_current = curbuf->b_block_head.mb_next; | |
2877 curbuf->b_m_search = NULL; | |
2878 } | |
2879 if ((nextb = curbuf->b_mb_current->mb_next) != NULL | |
2880 && (minfo_T *)nextb < mp) | |
2881 { | |
2882 curbuf->b_mb_current = nextb; | |
2883 curbuf->b_m_search = NULL; | |
2884 } | |
2885 while ((nextb = curbuf->b_mb_current->mb_next) != NULL | |
2886 && (minfo_T *)nextb < mp) | |
2887 curbuf->b_mb_current = nextb; | |
2888 | |
2889 curr = NULL; | |
2890 /* | |
2891 * If mp is smaller than curbuf->b_m_search->m_next go to the start of | |
2892 * the free list | |
2893 */ | |
2894 if (curbuf->b_m_search == NULL || mp < (curbuf->b_m_search->m_next)) | |
2895 next = &(curbuf->b_mb_current->mb_info); | |
2896 else | |
2897 next = curbuf->b_m_search; | |
2898 /* | |
2899 * The following loop is executed very often. | |
2900 * Therefore it has been optimized at the cost of readability. | |
2901 * Keep it fast! | |
2902 */ | |
2903 #ifdef SLOW_BUT_EASY_TO_READ | |
2904 do | |
2905 { | |
2906 prev = curr; | |
2907 curr = next; | |
2908 next = next->m_next; | |
2909 } | |
2910 while (mp > next && next != NULL); | |
2911 #else | |
2912 do /* first, middle, last */ | |
2913 { | |
2914 prev = next->m_next; /* curr, next, prev */ | |
2915 if (prev == NULL || mp <= prev) | |
2916 { | |
2917 prev = curr; | |
2918 curr = next; | |
2919 next = next->m_next; | |
2920 break; | |
2921 } | |
2922 curr = prev->m_next; /* next, prev, curr */ | |
2923 if (curr == NULL || mp <= curr) | |
2924 { | |
2925 prev = next; | |
2926 curr = prev->m_next; | |
2927 next = curr->m_next; | |
2928 break; | |
2929 } | |
2930 next = curr->m_next; /* prev, curr, next */ | |
2931 } | |
2932 while (mp > next && next != NULL); | |
2933 #endif | |
2934 | |
2935 /* if *mp and *next are concatenated, join them into one chunk */ | |
2936 if ((char_u *)mp + mp->m_size == (char_u *)next) | |
2937 { | |
2938 mp->m_size += next->m_size; | |
2939 mp->m_next = next->m_next; | |
2940 } | |
2941 else | |
2942 mp->m_next = next; | |
2943 maxsize = mp->m_size; | |
2944 | |
2945 /* if *curr and *mp are concatenated, join them */ | |
2946 if (prev != NULL && (char_u *)curr + curr->m_size == (char_u *)mp) | |
2947 { | |
2948 curr->m_size += mp->m_size; | |
2949 maxsize = curr->m_size; | |
2950 curr->m_next = mp->m_next; | |
2951 curbuf->b_m_search = prev; | |
2952 } | |
2953 else | |
2954 { | |
2955 curr->m_next = mp; | |
2956 curbuf->b_m_search = curr; /* put curbuf->b_m_search before freed | |
2957 chunk */ | |
2958 } | |
2959 | |
2960 /* | |
2961 * If the block only contains free memory now, release it. | |
2962 */ | |
2963 if (!keep && curbuf->b_mb_current->mb_size | |
2964 == curbuf->b_mb_current->mb_info.m_next->m_size) | |
2965 { | |
2966 /* Find the block before the current one to be able to unlink it from | |
2967 * the list of blocks. */ | |
2968 prevb = &curbuf->b_block_head; | |
2969 for (nextb = prevb->mb_next; nextb != curbuf->b_mb_current; | |
2970 nextb = nextb->mb_next) | |
2971 prevb = nextb; | |
2972 prevb->mb_next = nextb->mb_next; | |
2973 vim_free(nextb); | |
2974 curbuf->b_mb_current = NULL; | |
2975 curbuf->b_m_search = NULL; | |
2976 } | |
2977 else if (curbuf->b_mb_current->mb_maxsize < maxsize) | |
2978 curbuf->b_mb_current->mb_maxsize = maxsize; | |
2979 } | |
2980 | |
2981 /* | |
2982 * Allocate and initialize a new line structure with room for at least | |
2983 * 'size' characters plus a terminating NUL. | |
2984 */ | |
2985 static char_u * | |
2986 u_alloc_line(size) | |
2987 unsigned size; | |
2988 { | |
2989 minfo_T *mp, *mprev, *mp2; | |
2990 mblock_T *mbp; | |
2991 int size_align; | |
2992 | |
2993 /* | |
2994 * Add room for size field and trailing NUL byte. | |
2995 * Adjust for minimal size (must be able to store minfo_T | |
2996 * plus a trailing NUL, so the chunk can be released again) | |
2997 */ | |
2998 size += M_OFFSET + 1; | |
2999 if (size < sizeof(minfo_T) + 1) | |
3000 size = sizeof(minfo_T) + 1; | |
3001 | |
3002 /* | |
3003 * round size up for alignment | |
3004 */ | |
3005 size_align = (size + ALIGN_MASK) & ~ALIGN_MASK; | |
3006 | |
3007 /* | |
3008 * If curbuf->b_m_search is NULL (uninitialized free list) start at | |
3009 * curbuf->b_block_head | |
3010 */ | |
3011 if (curbuf->b_mb_current == NULL || curbuf->b_m_search == NULL) | |
3012 { | |
3013 curbuf->b_mb_current = &curbuf->b_block_head; | |
3014 curbuf->b_m_search = &(curbuf->b_block_head.mb_info); | |
3015 } | |
3016 | |
3017 /* Search for a block with enough space. */ | |
3018 mbp = curbuf->b_mb_current; | |
3019 while (mbp->mb_maxsize < size_align) | |
3020 { | |
3021 if (mbp->mb_next != NULL) | |
3022 mbp = mbp->mb_next; | |
3023 else | |
3024 mbp = &curbuf->b_block_head; | |
3025 if (mbp == curbuf->b_mb_current) | |
3026 { | |
3027 int n = (size_align > (MEMBLOCKSIZE / 4) | |
3028 ? size_align : MEMBLOCKSIZE); | |
3029 | |
3030 /* Back where we started in block list: need to add a new block | |
3031 * with enough space. */ | |
3032 mp = (minfo_T *)u_blockalloc((long_u)n); | |
3033 if (mp == NULL) | |
3034 return (NULL); | |
3035 mp->m_size = n; | |
3036 u_free_line((char_u *)mp + M_OFFSET, TRUE); | |
3037 mbp = curbuf->b_mb_current; | |
3038 break; | |
3039 } | |
3040 } | |
3041 if (mbp != curbuf->b_mb_current) | |
3042 curbuf->b_m_search = &(mbp->mb_info); | |
3043 | |
3044 /* In this block find a chunk with enough space. */ | |
3045 mprev = curbuf->b_m_search; | |
3046 mp = curbuf->b_m_search->m_next; | |
3047 for (;;) | |
3048 { | |
3049 if (mp == NULL) /* at end of the list */ | |
3050 mp = &(mbp->mb_info); /* wrap around to begin */ | |
3051 if (mp->m_size >= size) | |
3052 break; | |
3053 if (mp == curbuf->b_m_search) | |
3054 { | |
3055 /* back where we started in free chunk list: "cannot happen" */ | |
3056 EMSG2(_(e_intern2), "u_alloc_line()"); | |
3057 return NULL; | |
3058 } | |
3059 mprev = mp; | |
3060 mp = mp->m_next; | |
3061 } | |
3062 | |
3063 /* when using the largest chunk adjust mb_maxsize */ | |
3064 if (mp->m_size >= mbp->mb_maxsize) | |
3065 mbp->mb_maxsize = 0; | |
3066 | |
3067 /* if the chunk we found is large enough, split it up in two */ | |
3068 if ((long)mp->m_size - size_align >= (long)(sizeof(minfo_T) + 1)) | |
3069 { | |
3070 mp2 = (minfo_T *)((char_u *)mp + size_align); | |
3071 mp2->m_size = mp->m_size - size_align; | |
3072 mp2->m_next = mp->m_next; | |
3073 mprev->m_next = mp2; | |
3074 mp->m_size = size_align; | |
3075 } | |
3076 else /* remove *mp from the free list */ | |
3077 { | |
3078 mprev->m_next = mp->m_next; | |
3079 } | |
3080 curbuf->b_m_search = mprev; | |
3081 curbuf->b_mb_current = mbp; | |
3082 | |
3083 /* If using the largest chunk need to find the new largest chunk */ | |
3084 if (mbp->mb_maxsize == 0) | |
3085 for (mp2 = &(mbp->mb_info); mp2 != NULL; mp2 = mp2->m_next) | |
3086 if (mbp->mb_maxsize < mp2->m_size) | |
3087 mbp->mb_maxsize = mp2->m_size; | |
3088 | |
3089 mp = (minfo_T *)((char_u *)mp + M_OFFSET); | |
3090 *(char_u *)mp = NUL; /* set the first byte to NUL */ | |
3091 | |
3092 return ((char_u *)mp); | |
3093 } | |
3094 #endif | |
3095 | |
3096 /* | |
3097 * u_save_line(): allocate memory with u_alloc_line() and copy line 'lnum' | |
3098 * into it. | |
3099 */ | 2704 */ |
3100 static char_u * | 2705 static char_u * |
3101 u_save_line(lnum) | 2706 u_save_line(lnum) |
3102 linenr_T lnum; | 2707 linenr_T lnum; |
3103 { | 2708 { |
3104 char_u *src; | 2709 return vim_strsave(ml_get(lnum)); |
3105 char_u *dst; | |
3106 unsigned len; | |
3107 | |
3108 src = ml_get(lnum); | |
3109 len = (unsigned)STRLEN(src); | |
3110 if ((dst = U_ALLOC_LINE(len)) != NULL) | |
3111 mch_memmove(dst, src, (size_t)(len + 1)); | |
3112 return (dst); | |
3113 } | 2710 } |
3114 | 2711 |
3115 /* | 2712 /* |
3116 * Check if the 'modified' flag is set, or 'ff' has changed (only need to | 2713 * Check if the 'modified' flag is set, or 'ff' has changed (only need to |
3117 * check the first character, because it can only be "dos", "unix" or "mac"). | 2714 * check the first character, because it can only be "dos", "unix" or "mac"). |