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").