зеркало из https://github.com/microsoft/git.git
Make 'traverse_tree()' use linked structure rather than 'const char *base'
This makes the calling convention a bit less obvious, but a lot more flexible. Instead of allocating and extending a new 'base' string, we just link the top-most name into a linked list of the 'info' structure when traversing a subdirectory, and we can generate the basename by following the list. Perhaps even more importantly, the linked list of info structures also gives us a place to naturally save off other information than just the directory name. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
0ab9e1e8cd
Коммит
40d934df72
51
merge-tree.c
51
merge-tree.c
|
@ -168,7 +168,13 @@ static struct merge_list *create_entry(unsigned stage, unsigned mode, const unsi
|
|||
return res;
|
||||
}
|
||||
|
||||
static void resolve(const char *base, struct name_entry *branch1, struct name_entry *result)
|
||||
static char *traverse_path(const struct traverse_info *info, const struct name_entry *n)
|
||||
{
|
||||
char *path = xmalloc(traverse_path_len(info, n) + 1);
|
||||
return make_traverse_path(path, info, n);
|
||||
}
|
||||
|
||||
static void resolve(const struct traverse_info *info, struct name_entry *branch1, struct name_entry *result)
|
||||
{
|
||||
struct merge_list *orig, *final;
|
||||
const char *path;
|
||||
|
@ -177,7 +183,7 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en
|
|||
if (!branch1)
|
||||
return;
|
||||
|
||||
path = xstrdup(mkpath("%s%s", base, result->path));
|
||||
path = traverse_path(info, result);
|
||||
orig = create_entry(2, branch1->mode, branch1->sha1, path);
|
||||
final = create_entry(0, result->mode, result->sha1, path);
|
||||
|
||||
|
@ -186,9 +192,8 @@ static void resolve(const char *base, struct name_entry *branch1, struct name_en
|
|||
add_merge_entry(final);
|
||||
}
|
||||
|
||||
static int unresolved_directory(const char *base, struct name_entry n[3])
|
||||
static int unresolved_directory(const struct traverse_info *info, struct name_entry n[3])
|
||||
{
|
||||
int baselen, pathlen;
|
||||
char *newbase;
|
||||
struct name_entry *p;
|
||||
struct tree_desc t[3];
|
||||
|
@ -204,13 +209,7 @@ static int unresolved_directory(const char *base, struct name_entry n[3])
|
|||
}
|
||||
if (!S_ISDIR(p->mode))
|
||||
return 0;
|
||||
baselen = strlen(base);
|
||||
pathlen = tree_entry_len(p->path, p->sha1);
|
||||
newbase = xmalloc(baselen + pathlen + 2);
|
||||
memcpy(newbase, base, baselen);
|
||||
memcpy(newbase + baselen, p->path, pathlen);
|
||||
memcpy(newbase + baselen + pathlen, "/", 2);
|
||||
|
||||
newbase = traverse_path(info, p);
|
||||
buf0 = fill_tree_descriptor(t+0, n[0].sha1);
|
||||
buf1 = fill_tree_descriptor(t+1, n[1].sha1);
|
||||
buf2 = fill_tree_descriptor(t+2, n[2].sha1);
|
||||
|
@ -224,7 +223,7 @@ static int unresolved_directory(const char *base, struct name_entry n[3])
|
|||
}
|
||||
|
||||
|
||||
static struct merge_list *link_entry(unsigned stage, const char *base, struct name_entry *n, struct merge_list *entry)
|
||||
static struct merge_list *link_entry(unsigned stage, const struct traverse_info *info, struct name_entry *n, struct merge_list *entry)
|
||||
{
|
||||
const char *path;
|
||||
struct merge_list *link;
|
||||
|
@ -234,17 +233,17 @@ static struct merge_list *link_entry(unsigned stage, const char *base, struct na
|
|||
if (entry)
|
||||
path = entry->path;
|
||||
else
|
||||
path = xstrdup(mkpath("%s%s", base, n->path));
|
||||
path = traverse_path(info, n);
|
||||
link = create_entry(stage, n->mode, n->sha1, path);
|
||||
link->link = entry;
|
||||
return link;
|
||||
}
|
||||
|
||||
static void unresolved(const char *base, struct name_entry n[3])
|
||||
static void unresolved(const struct traverse_info *info, struct name_entry n[3])
|
||||
{
|
||||
struct merge_list *entry = NULL;
|
||||
|
||||
if (unresolved_directory(base, n))
|
||||
if (unresolved_directory(info, n))
|
||||
return;
|
||||
|
||||
/*
|
||||
|
@ -252,9 +251,9 @@ static void unresolved(const char *base, struct name_entry n[3])
|
|||
* list has the stages in order - link_entry adds new
|
||||
* links at the front.
|
||||
*/
|
||||
entry = link_entry(3, base, n + 2, entry);
|
||||
entry = link_entry(2, base, n + 1, entry);
|
||||
entry = link_entry(1, base, n + 0, entry);
|
||||
entry = link_entry(3, info, n + 2, entry);
|
||||
entry = link_entry(2, info, n + 1, entry);
|
||||
entry = link_entry(1, info, n + 0, entry);
|
||||
|
||||
add_merge_entry(entry);
|
||||
}
|
||||
|
@ -288,36 +287,40 @@ static void unresolved(const char *base, struct name_entry n[3])
|
|||
* The successful merge rules are the same as for the three-way merge
|
||||
* in git-read-tree.
|
||||
*/
|
||||
static void threeway_callback(int n, unsigned long mask, struct name_entry *entry, const char *base)
|
||||
static void threeway_callback(int n, unsigned long mask, struct name_entry *entry, struct traverse_info *info)
|
||||
{
|
||||
/* Same in both? */
|
||||
if (same_entry(entry+1, entry+2)) {
|
||||
if (entry[0].sha1) {
|
||||
resolve(base, NULL, entry+1);
|
||||
resolve(info, NULL, entry+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (same_entry(entry+0, entry+1)) {
|
||||
if (entry[2].sha1 && !S_ISDIR(entry[2].mode)) {
|
||||
resolve(base, entry+1, entry+2);
|
||||
resolve(info, entry+1, entry+2);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (same_entry(entry+0, entry+2)) {
|
||||
if (entry[1].sha1 && !S_ISDIR(entry[1].mode)) {
|
||||
resolve(base, NULL, entry+1);
|
||||
resolve(info, NULL, entry+1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unresolved(base, entry);
|
||||
unresolved(info, entry);
|
||||
}
|
||||
|
||||
static void merge_trees(struct tree_desc t[3], const char *base)
|
||||
{
|
||||
traverse_trees(3, t, base, threeway_callback);
|
||||
struct traverse_info info;
|
||||
|
||||
setup_traverse_info(&info, base);
|
||||
info.fn = threeway_callback;
|
||||
traverse_trees(3, t, &info);
|
||||
}
|
||||
|
||||
static void *get_tree_descriptor(struct tree_desc *desc, const char *rev)
|
||||
|
|
35
tree-walk.c
35
tree-walk.c
|
@ -104,7 +104,38 @@ int tree_entry(struct tree_desc *desc, struct name_entry *entry)
|
|||
return 1;
|
||||
}
|
||||
|
||||
void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback)
|
||||
void setup_traverse_info(struct traverse_info *info, const char *base)
|
||||
{
|
||||
int pathlen = strlen(base);
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
if (pathlen && base[pathlen-1] == '/')
|
||||
pathlen--;
|
||||
info->pathlen = pathlen ? pathlen + 1 : 0;
|
||||
info->name.path = base;
|
||||
info->name.sha1 = (void *)(base + pathlen + 1);
|
||||
}
|
||||
|
||||
char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n)
|
||||
{
|
||||
int len = tree_entry_len(n->path, n->sha1);
|
||||
int pathlen = info->pathlen;
|
||||
|
||||
path[pathlen + len] = 0;
|
||||
for (;;) {
|
||||
memcpy(path + pathlen, n->path, len);
|
||||
if (!pathlen)
|
||||
break;
|
||||
path[--pathlen] = '/';
|
||||
n = &info->name;
|
||||
len = tree_entry_len(n->path, n->sha1);
|
||||
info = info->prev;
|
||||
pathlen -= len;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void traverse_trees(int n, struct tree_desc *t, struct traverse_info *info)
|
||||
{
|
||||
struct name_entry *entry = xmalloc(n*sizeof(*entry));
|
||||
|
||||
|
@ -150,7 +181,7 @@ void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callb
|
|||
}
|
||||
entry_clear(entry + i);
|
||||
}
|
||||
callback(n, mask, entry, base);
|
||||
info->fn(n, mask, entry, info);
|
||||
}
|
||||
free(entry);
|
||||
}
|
||||
|
|
20
tree-walk.h
20
tree-walk.h
|
@ -33,10 +33,26 @@ int tree_entry(struct tree_desc *, struct name_entry *);
|
|||
|
||||
void *fill_tree_descriptor(struct tree_desc *desc, const unsigned char *sha1);
|
||||
|
||||
typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, const char *base);
|
||||
struct traverse_info;
|
||||
typedef void (*traverse_callback_t)(int n, unsigned long mask, struct name_entry *entry, struct traverse_info *);
|
||||
void traverse_trees(int n, struct tree_desc *t, struct traverse_info *info);
|
||||
|
||||
void traverse_trees(int n, struct tree_desc *t, const char *base, traverse_callback_t callback);
|
||||
struct traverse_info {
|
||||
struct traverse_info *prev;
|
||||
struct name_entry name;
|
||||
int pathlen;
|
||||
|
||||
traverse_callback_t fn;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int get_tree_entry(const unsigned char *, const char *, unsigned char *, unsigned *);
|
||||
extern char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);
|
||||
extern void setup_traverse_info(struct traverse_info *info, const char *base);
|
||||
|
||||
static inline int traverse_path_len(const struct traverse_info *info, const struct name_entry *n)
|
||||
{
|
||||
return info->pathlen + tree_entry_len(n->path, n->sha1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Загрузка…
Ссылка в новой задаче