]>
Commit | Line | Data |
---|---|---|
03d4279c AM |
1 | To: vim_dev@googlegroups.com |
2 | Subject: Patch 7.3.434 | |
3 | Fcc: outbox | |
4 | From: Bram Moolenaar <Bram@moolenaar.net> | |
5 | Mime-Version: 1.0 | |
6 | Content-Type: text/plain; charset=UTF-8 | |
7 | Content-Transfer-Encoding: 8bit | |
8 | ------------ | |
9 | ||
10 | Patch 7.3.434 | |
11 | Problem: Using join() can be slow. | |
12 | Solution: Compute the size of the result before allocation to avoid a lot of | |
13 | allocations and copies. (Taro Muraoka) | |
14 | Files: src/eval.c | |
15 | ||
16 | ||
17 | *** ../vim-7.3.433/src/eval.c 2012-02-05 00:39:14.000000000 +0100 | |
18 | --- src/eval.c 2012-02-06 00:05:31.000000000 +0100 | |
19 | *************** | |
20 | *** 442,447 **** | |
21 | --- 442,448 ---- | |
22 | static list_T *list_copy __ARGS((list_T *orig, int deep, int copyID)); | |
23 | static void list_remove __ARGS((list_T *l, listitem_T *item, listitem_T *item2)); | |
24 | static char_u *list2string __ARGS((typval_T *tv, int copyID)); | |
25 | + static int list_join_inner __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo_style, int copyID, garray_T *join_gap)); | |
26 | static int list_join __ARGS((garray_T *gap, list_T *l, char_u *sep, int echo, int copyID)); | |
27 | static int free_unref_items __ARGS((int copyID)); | |
28 | static void set_ref_in_ht __ARGS((hashtab_T *ht, int copyID)); | |
29 | *************** | |
30 | *** 6571,6617 **** | |
31 | return (char_u *)ga.ga_data; | |
32 | } | |
33 | ||
34 | ! /* | |
35 | ! * Join list "l" into a string in "*gap", using separator "sep". | |
36 | ! * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. | |
37 | ! * Return FAIL or OK. | |
38 | ! */ | |
39 | static int | |
40 | ! list_join(gap, l, sep, echo_style, copyID) | |
41 | ! garray_T *gap; | |
42 | list_T *l; | |
43 | char_u *sep; | |
44 | int echo_style; | |
45 | int copyID; | |
46 | { | |
47 | int first = TRUE; | |
48 | char_u *tofree; | |
49 | char_u numbuf[NUMBUFLEN]; | |
50 | listitem_T *item; | |
51 | char_u *s; | |
52 | ||
53 | for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) | |
54 | { | |
55 | - if (first) | |
56 | - first = FALSE; | |
57 | - else | |
58 | - ga_concat(gap, sep); | |
59 | - | |
60 | if (echo_style) | |
61 | s = echo_string(&item->li_tv, &tofree, numbuf, copyID); | |
62 | else | |
63 | s = tv2string(&item->li_tv, &tofree, numbuf, copyID); | |
64 | - if (s != NULL) | |
65 | - ga_concat(gap, s); | |
66 | - vim_free(tofree); | |
67 | if (s == NULL) | |
68 | return FAIL; | |
69 | line_breakcheck(); | |
70 | } | |
71 | return OK; | |
72 | } | |
73 | ||
74 | /* | |
75 | * Garbage collection for lists and dictionaries. | |
76 | * | |
77 | * We use reference counts to be able to free most items right away when they | |
78 | --- 6572,6690 ---- | |
79 | return (char_u *)ga.ga_data; | |
80 | } | |
81 | ||
82 | ! typedef struct join_S { | |
83 | ! char_u *s; | |
84 | ! char_u *tofree; | |
85 | ! } join_T; | |
86 | ! | |
87 | static int | |
88 | ! list_join_inner(gap, l, sep, echo_style, copyID, join_gap) | |
89 | ! garray_T *gap; /* to store the result in */ | |
90 | list_T *l; | |
91 | char_u *sep; | |
92 | int echo_style; | |
93 | int copyID; | |
94 | + garray_T *join_gap; /* to keep each list item string */ | |
95 | { | |
96 | + int i; | |
97 | + join_T *p; | |
98 | + int len; | |
99 | + int sumlen = 0; | |
100 | int first = TRUE; | |
101 | char_u *tofree; | |
102 | char_u numbuf[NUMBUFLEN]; | |
103 | listitem_T *item; | |
104 | char_u *s; | |
105 | ||
106 | + /* Stringify each item in the list. */ | |
107 | for (item = l->lv_first; item != NULL && !got_int; item = item->li_next) | |
108 | { | |
109 | if (echo_style) | |
110 | s = echo_string(&item->li_tv, &tofree, numbuf, copyID); | |
111 | else | |
112 | s = tv2string(&item->li_tv, &tofree, numbuf, copyID); | |
113 | if (s == NULL) | |
114 | return FAIL; | |
115 | + | |
116 | + len = (int)STRLEN(s); | |
117 | + sumlen += len; | |
118 | + | |
119 | + ga_grow(join_gap, 1); | |
120 | + p = ((join_T *)join_gap->ga_data) + (join_gap->ga_len++); | |
121 | + if (tofree != NULL || s != numbuf) | |
122 | + { | |
123 | + p->s = s; | |
124 | + p->tofree = tofree; | |
125 | + } | |
126 | + else | |
127 | + { | |
128 | + p->s = vim_strnsave(s, len); | |
129 | + p->tofree = p->s; | |
130 | + } | |
131 | + | |
132 | + line_breakcheck(); | |
133 | + } | |
134 | + | |
135 | + /* Allocate result buffer with its total size, avoid re-allocation and | |
136 | + * multiple copy operations. Add 2 for a tailing ']' and NUL. */ | |
137 | + if (join_gap->ga_len >= 2) | |
138 | + sumlen += (int)STRLEN(sep) * (join_gap->ga_len - 1); | |
139 | + if (ga_grow(gap, sumlen + 2) == FAIL) | |
140 | + return FAIL; | |
141 | + | |
142 | + for (i = 0; i < join_gap->ga_len && !got_int; ++i) | |
143 | + { | |
144 | + if (first) | |
145 | + first = FALSE; | |
146 | + else | |
147 | + ga_concat(gap, sep); | |
148 | + p = ((join_T *)join_gap->ga_data) + i; | |
149 | + | |
150 | + if (p->s != NULL) | |
151 | + ga_concat(gap, p->s); | |
152 | line_breakcheck(); | |
153 | } | |
154 | + | |
155 | return OK; | |
156 | } | |
157 | ||
158 | /* | |
159 | + * Join list "l" into a string in "*gap", using separator "sep". | |
160 | + * When "echo_style" is TRUE use String as echoed, otherwise as inside a List. | |
161 | + * Return FAIL or OK. | |
162 | + */ | |
163 | + static int | |
164 | + list_join(gap, l, sep, echo_style, copyID) | |
165 | + garray_T *gap; | |
166 | + list_T *l; | |
167 | + char_u *sep; | |
168 | + int echo_style; | |
169 | + int copyID; | |
170 | + { | |
171 | + garray_T join_ga; | |
172 | + int retval; | |
173 | + join_T *p; | |
174 | + int i; | |
175 | + | |
176 | + ga_init2(&join_ga, (int)sizeof(join_T), l->lv_len); | |
177 | + retval = list_join_inner(gap, l, sep, echo_style, copyID, &join_ga); | |
178 | + | |
179 | + /* Dispose each item in join_ga. */ | |
180 | + if (join_ga.ga_data != NULL) | |
181 | + { | |
182 | + p = (join_T *)join_ga.ga_data; | |
183 | + for (i = 0; i < join_ga.ga_len; ++i) | |
184 | + { | |
185 | + vim_free(p->tofree); | |
186 | + ++p; | |
187 | + } | |
188 | + ga_clear(&join_ga); | |
189 | + } | |
190 | + | |
191 | + return retval; | |
192 | + } | |
193 | + | |
194 | + /* | |
195 | * Garbage collection for lists and dictionaries. | |
196 | * | |
197 | * We use reference counts to be able to free most items right away when they | |
198 | *************** | |
199 | *** 13406,13412 **** | |
200 | char_u *rhs; | |
201 | int mode; | |
202 | int abbr = FALSE; | |
203 | ! int get_dict = FALSE; | |
204 | mapblock_T *mp; | |
205 | int buffer_local; | |
206 | ||
207 | --- 13479,13485 ---- | |
208 | char_u *rhs; | |
209 | int mode; | |
210 | int abbr = FALSE; | |
211 | ! int get_dict = FALSE; | |
212 | mapblock_T *mp; | |
213 | int buffer_local; | |
214 | ||
215 | *** ../vim-7.3.433/src/version.c 2012-02-05 23:10:25.000000000 +0100 | |
216 | --- src/version.c 2012-02-06 00:10:23.000000000 +0100 | |
217 | *************** | |
218 | *** 716,717 **** | |
219 | --- 716,719 ---- | |
220 | { /* Add new patch number below this line */ | |
221 | + /**/ | |
222 | + 434, | |
223 | /**/ | |
224 | ||
225 | -- | |
226 | hundred-and-one symptoms of being an internet addict: | |
227 | 30. Even though you died last week, you've managed to retain OPS on your | |
228 | favorite IRC channel. | |
229 | ||
230 | /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ | |
231 | /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ | |
232 | \\\ an exciting new programming language -- http://www.Zimbu.org /// | |
233 | \\\ help me help AIDS victims -- http://ICCF-Holland.org /// |