@matheusbsbs / matheus-bagliano / commits / 48932677d6
Fork 0

diff-tree: convert base+baselen to writable strbuf

In traversing trees, a full path is splitted into two parts: base directory and entry. They are however quite often concatenated whenever a full path is needed. Current code allocates a new buffer, do two memcpy(), use it, then release. Instead this patch turns "base" to a writable, extendable buffer. When a concatenation is needed, the callee only needs to append "entry" to base, use it, then truncate the entry out again. "base" must remain unchanged before and after entering a function. This avoids quite a bit of malloc() and memcpy(). Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Dec 15, 2010 at 22:02 UTC 48932677d62e426b3f26ac236384cb5195fb9dfd
3 files changed +56 -71
tree-diff.c
+52 -68
@@ -6,34 +6,18 @@
6 #include "diffcore.h"
7 #include "tree.h"
8
9 -static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)
10 -{
11 - char *newbase = xmalloc(baselen + pathlen + 2);
12 - memcpy(newbase, base, baselen);
13 - memcpy(newbase + baselen, path, pathlen);
14 - memcpy(newbase + baselen + pathlen, "/", 2);
15 - return newbase;
16 -}
9 +static void show_entry(struct diff_options *opt, const char *prefix,
10 + struct tree_desc *desc, struct strbuf *base);
11
18 -static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen)
19 -{
20 - char *fullname = xmalloc(baselen + pathlen + 1);
21 - memcpy(fullname, base, baselen);
22 - memcpy(fullname + baselen, path, pathlen);
23 - fullname[baselen + pathlen] = 0;
24 - return fullname;
25 -}
26 -
27 -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
28 - const char *base, int baselen);
29 -
30 -static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)
12 +static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,
13 + struct strbuf *base, struct diff_options *opt)
14 {
15 unsigned mode1, mode2;
16 const char *path1, *path2;
17 const unsigned char *sha1, *sha2;
18 int cmp, pathlen1, pathlen2;
36 - char *fullname;
19 + int old_baselen = base->len;
20 + int retval = 0;
21
22 sha1 = tree_entry_extract(t1, &path1, &mode1);
23 sha2 = tree_entry_extract(t2, &path2, &mode2);
@@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
26 pathlen2 = tree_entry_len(path2, sha2);
27 cmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);
28 if (cmp < 0) {
45 - show_entry(opt, "-", t1, base, baselen);
29 + show_entry(opt, "-", t1, base);
30 return -1;
31 }
32 if (cmp > 0) {
49 - show_entry(opt, "+", t2, base, baselen);
33 + show_entry(opt, "+", t2, base);
34 return 1;
35 }
36 if (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2)
@@ -57,33 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const
41 * file, we need to consider it a remove and an add.
42 */
43 if (S_ISDIR(mode1) != S_ISDIR(mode2)) {
60 - show_entry(opt, "-", t1, base, baselen);
61 - show_entry(opt, "+", t2, base, baselen);
44 + show_entry(opt, "-", t1, base);
45 + show_entry(opt, "+", t2, base);
46 return 0;
47 }
48
49 + strbuf_add(base, path1, pathlen1);
50 if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {
66 - int retval;
67 - char *newbase = malloc_base(base, baselen, path1, pathlen1);
51 if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
69 - newbase[baselen + pathlen1] = 0;
52 opt->change(opt, mode1, mode2,
71 - sha1, sha2, newbase, 0, 0);
72 - newbase[baselen + pathlen1] = '/';
53 + sha1, sha2, base->buf, 0, 0);
54 }
74 - retval = diff_tree_sha1(sha1, sha2, newbase, opt);
75 - free(newbase);
76 - return retval;
55 + strbuf_addch(base, '/');
56 + retval = diff_tree_sha1(sha1, sha2, base->buf, opt);
57 + } else {
58 + opt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);
59 }
78 -
79 - fullname = malloc_fullname(base, baselen, path1, pathlen1);
80 - opt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0);
81 - free(fullname);
60 + strbuf_setlen(base, old_baselen);
61 return 0;
62 }
63
64 /* A whole sub-tree went away or appeared */
86 -static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)
65 +static void show_tree(struct diff_options *opt, const char *prefix,
66 + struct tree_desc *desc, struct strbuf *base)
67 {
68 int all_interesting = 0;
69 while (desc->size) {
@@ -92,30 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_
72 if (all_interesting)
73 show = 1;
74 else {
95 - show = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec);
75 + show = tree_entry_interesting(&desc->entry, base,
76 + &opt->pathspec);
77 if (show == 2)
78 all_interesting = 1;
79 }
80 if (show < 0)
81 break;
82 if (show)
102 - show_entry(opt, prefix, desc, base, baselen);
83 + show_entry(opt, prefix, desc, base);
84 update_tree_entry(desc);
85 }
86 }
87
88 /* A file entry went away or appeared */
108 -static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,
109 - const char *base, int baselen)
89 +static void show_entry(struct diff_options *opt, const char *prefix,
90 + struct tree_desc *desc, struct strbuf *base)
91 {
92 unsigned mode;
93 const char *path;
94 const unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);
95 int pathlen = tree_entry_len(path, sha1);
96 + int old_baselen = base->len;
97
98 + strbuf_add(base, path, pathlen);
99 if (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {
100 enum object_type type;
118 - char *newbase = malloc_base(base, baselen, path, pathlen);
101 struct tree_desc inner;
102 void *tree;
103 unsigned long size;
@@ -124,28 +106,25 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree
106 if (!tree || type != OBJ_TREE)
107 die("corrupt tree sha %s", sha1_to_hex(sha1));
108
127 - if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {
128 - newbase[baselen + pathlen] = 0;
129 - opt->add_remove(opt, *prefix, mode, sha1, newbase, 0);
130 - newbase[baselen + pathlen] = '/';
131 - }
109 + if (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))
110 + opt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);
111
133 - init_tree_desc(&inner, tree, size);
134 - show_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);
112 + strbuf_addch(base, '/');
113
114 + init_tree_desc(&inner, tree, size);
115 + show_tree(opt, prefix, &inner, base);
116 free(tree);
137 - free(newbase);
138 - } else {
139 - char *fullname = malloc_fullname(base, baselen, path, pathlen);
140 - opt->add_remove(opt, prefix[0], mode, sha1, fullname, 0);
141 - free(fullname);
142 - }
117 + } else
118 + opt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);
119 +
120 + strbuf_setlen(base, old_baselen);
121 }
122
145 -static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt, int *all_interesting)
123 +static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,
124 + struct diff_options *opt, int *all_interesting)
125 {
126 while (t->size) {
148 - int show = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec);
127 + int show = tree_entry_interesting(&t->entry, base, &opt->pathspec);
128 if (show == 2)
129 *all_interesting = 1;
130 if (!show) {
@@ -159,37 +138,40 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele
138 }
139 }
140
162 -int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)
141 +int diff_tree(struct tree_desc *t1, struct tree_desc *t2,
142 + const char *base_str, struct diff_options *opt)
143 {
164 - int baselen = strlen(base);
144 + struct strbuf base;
145 + int baselen = strlen(base_str);
146 int all_t1_interesting = 0;
147 int all_t2_interesting = 0;
148
149 + strbuf_init(&base, PATH_MAX);
150 + strbuf_add(&base, base_str, baselen);
151 +
152 for (;;) {
153 if (DIFF_OPT_TST(opt, QUICK) &&
154 DIFF_OPT_TST(opt, HAS_CHANGES))
155 break;
156 if (opt->pathspec.nr) {
157 if (!all_t1_interesting)
174 - skip_uninteresting(t1, base, baselen, opt,
175 - &all_t1_interesting);
158 + skip_uninteresting(t1, &base, opt, &all_t1_interesting);
159 if (!all_t2_interesting)
177 - skip_uninteresting(t2, base, baselen, opt,
178 - &all_t2_interesting);
160 + skip_uninteresting(t2, &base, opt, &all_t2_interesting);
161 }
162 if (!t1->size) {
163 if (!t2->size)
164 break;
183 - show_entry(opt, "+", t2, base, baselen);
165 + show_entry(opt, "+", t2, &base);
166 update_tree_entry(t2);
167 continue;
168 }
169 if (!t2->size) {
188 - show_entry(opt, "-", t1, base, baselen);
170 + show_entry(opt, "-", t1, &base);
171 update_tree_entry(t1);
172 continue;
173 }
192 - switch (compare_tree_entry(t1, t2, base, baselen, opt)) {
174 + switch (compare_tree_entry(t1, t2, &base, opt)) {
175 case -1:
176 update_tree_entry(t1);
177 continue;
@@ -202,6 +184,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru
184 }
185 die("git diff-tree: internal error");
186 }
187 +
188 + strbuf_release(&base);
189 return 0;
190 }
191
tree-walk.c
+3 -2
@@ -468,12 +468,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch
468 * - negative for "no, and no subsequent entries will be either"
469 */
470 int tree_entry_interesting(const struct name_entry *entry,
471 - const char *base, int baselen,
471 + const struct strbuf *base_buf,
472 const struct pathspec *ps)
473 {
474 int i;
475 - int pathlen;
475 + int pathlen, baselen = base_buf->len;
476 int never_interesting = -1;
477 + const char *base = base_buf->buf;
478
479 if (!ps || !ps->nr)
480 return 2;
tree-walk.h
+1 -1
@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru
60 return info->pathlen + tree_entry_len(n->path, n->sha1);
61 }
62
63 -extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps);
63 +extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps);
64
65 #endif