diff options
author | Vicent Marti <tanoku@gmail.com> | 2012-05-19 03:46:11 +0400 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2012-05-19 03:46:11 +0400 |
commit | 5b9fac39d8a76b9139667c26a63e6b3f204b3977 (patch) | |
tree | e6ba28025f92c16563c4ffa8bc60b95f17d69691 /src/revwalk.c | |
parent | 7ef9f1b5606c2672105ecbbf34c022a71ef212fe (diff) | |
parent | ad5df35a47d56c3d716d7a56eac4aeb611987c11 (diff) |
Merge branch 'development'v0.17.0
Conflicts:
.travis.yml
Diffstat (limited to 'src/revwalk.c')
-rw-r--r-- | src/revwalk.c | 592 |
1 files changed, 434 insertions, 158 deletions
diff --git a/src/revwalk.c b/src/revwalk.c index d632a19b8..e64d93f20 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011 the libgit2 contributors + * Copyright (C) 2009-2012 the libgit2 contributors * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. @@ -8,10 +8,21 @@ #include "common.h" #include "commit.h" #include "odb.h" -#include "hashtable.h" #include "pqueue.h" +#include "pool.h" +#include "oidmap.h" #include "git2/revwalk.h" +#include "git2/merge.h" + +#include <regex.h> + +GIT__USE_OIDMAP; + +#define PARENT1 (1 << 0) +#define PARENT2 (1 << 1) +#define RESULT (1 << 2) +#define STALE (1 << 3) typedef struct commit_object { git_oid oid; @@ -19,7 +30,8 @@ typedef struct commit_object { unsigned int seen:1, uninteresting:1, topo_delay:1, - parsed:1; + parsed:1, + flags : 4; unsigned short in_degree; unsigned short out_degree; @@ -36,7 +48,8 @@ struct git_revwalk { git_repository *repo; git_odb *odb; - git_hashtable *commits; + git_oidmap *commits; + git_pool commit_pool; commit_list *iterator_topo; commit_list *iterator_rand; @@ -46,22 +59,47 @@ struct git_revwalk { int (*get_next)(commit_object **, git_revwalk *); int (*enqueue)(git_revwalk *, commit_object *); - git_vector memory_alloc; - size_t chunk_size; - unsigned walking:1; unsigned int sorting; + + /* merge base calculation */ + commit_object *one; + git_vector twos; }; +static int commit_time_cmp(void *a, void *b) +{ + commit_object *commit_a = (commit_object *)a; + commit_object *commit_b = (commit_object *)b; + + return (commit_a->time < commit_b->time); +} + static commit_list *commit_list_insert(commit_object *item, commit_list **list_p) { commit_list *new_list = git__malloc(sizeof(commit_list)); - new_list->item = item; - new_list->next = *list_p; + if (new_list != NULL) { + new_list->item = item; + new_list->next = *list_p; + } *list_p = new_list; return new_list; } +static commit_list *commit_list_insert_by_date(commit_object *item, commit_list **list_p) +{ + commit_list **pp = list_p; + commit_list *p; + + while ((p = *pp) != NULL) { + if (commit_time_cmp(p->item, item) < 0) + break; + + pp = &p->next; + } + + return commit_list_insert(item, pp); +} static void commit_list_free(commit_list **list_p) { commit_list *list = *list_p; @@ -87,68 +125,36 @@ static commit_object *commit_list_pop(commit_list **stack) return item; } -static int commit_time_cmp(void *a, void *b) -{ - commit_object *commit_a = (commit_object *)a; - commit_object *commit_b = (commit_object *)b; - - return (commit_a->time < commit_b->time); -} - -static uint32_t object_table_hash(const void *key, int hash_id) -{ - uint32_t r; - const git_oid *id = key; - - memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r)); - return r; -} - -#define COMMITS_PER_CHUNK 128 -#define CHUNK_STEP 64 -#define PARENTS_PER_COMMIT ((CHUNK_STEP - sizeof(commit_object)) / sizeof(commit_object *)) - -static int alloc_chunk(git_revwalk *walk) -{ - void *chunk; - - chunk = git__calloc(COMMITS_PER_CHUNK, CHUNK_STEP); - if (chunk == NULL) - return GIT_ENOMEM; - - walk->chunk_size = 0; - return git_vector_insert(&walk->memory_alloc, chunk); -} +#define PARENTS_PER_COMMIT 2 +#define COMMIT_ALLOC \ + (sizeof(commit_object) + PARENTS_PER_COMMIT * sizeof(commit_object *)) static commit_object *alloc_commit(git_revwalk *walk) { - unsigned char *chunk; - - if (walk->chunk_size == COMMITS_PER_CHUNK) - alloc_chunk(walk); - - chunk = git_vector_get(&walk->memory_alloc, walk->memory_alloc.length - 1); - chunk += (walk->chunk_size * CHUNK_STEP); - walk->chunk_size++; - - return (commit_object *)chunk; + return (commit_object *)git_pool_malloc(&walk->commit_pool, COMMIT_ALLOC); } -static commit_object **alloc_parents(commit_object *commit, size_t n_parents) +static commit_object **alloc_parents( + git_revwalk *walk, commit_object *commit, size_t n_parents) { if (n_parents <= PARENTS_PER_COMMIT) - return (commit_object **)((unsigned char *)commit + sizeof(commit_object)); + return (commit_object **)((char *)commit + sizeof(commit_object)); - return git__malloc(n_parents * sizeof(commit_object *)); + return (commit_object **)git_pool_malloc( + &walk->commit_pool, (uint32_t)(n_parents * sizeof(commit_object *))); } static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid) { commit_object *commit; + khiter_t pos; + int ret; - if ((commit = git_hashtable_lookup(walk->commits, oid)) != NULL) - return commit; + /* lookup and reserve space if not already present */ + pos = kh_get(oid, walk->commits, oid); + if (pos != kh_end(walk->commits)) + return kh_value(walk->commits, pos); commit = alloc_commit(walk); if (commit == NULL) @@ -156,17 +162,16 @@ static commit_object *commit_lookup(git_revwalk *walk, const git_oid *oid) git_oid_cpy(&commit->oid, oid); - if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) { - git__free(commit); - return NULL; - } + pos = kh_put(oid, walk->commits, &commit->oid, &ret); + assert(ret != 0); + kh_value(walk->commits, pos) = commit; return commit; } static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawobj *raw) { - const int parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; + const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; unsigned char *buffer = raw->data; unsigned char *buffer_end = buffer + raw->len; @@ -183,39 +188,44 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo buffer += parent_len; } - commit->parents = alloc_parents(commit, parents); - if (commit->parents == NULL) - return GIT_ENOMEM; + commit->parents = alloc_parents(walk, commit, parents); + GITERR_CHECK_ALLOC(commit->parents); buffer = parents_start; for (i = 0; i < parents; ++i) { git_oid oid; - if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < GIT_SUCCESS) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Parent object is corrupted"); + if (git_oid_fromstr(&oid, (char *)buffer + strlen("parent ")) < 0) + return -1; commit->parents[i] = commit_lookup(walk, &oid); if (commit->parents[i] == NULL) - return GIT_ENOMEM; + return -1; buffer += parent_len; } commit->out_degree = (unsigned short)parents; - if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Object is corrupted"); + if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) { + giterr_set(GITERR_ODB, "Failed to parse commit. Object is corrupted"); + return -1; + } buffer = memchr(buffer, '>', buffer_end - buffer); - if (buffer == NULL) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't find author"); + if (buffer == NULL) { + giterr_set(GITERR_ODB, "Failed to parse commit. Can't find author"); + return -1; + } - if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS) - return git__throw(GIT_EOBJCORRUPTED, "Failed to parse commit. Can't parse commit time"); + if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < 0) { + giterr_set(GITERR_ODB, "Failed to parse commit. Can't parse commit time"); + return -1; + } commit->time = (time_t)commit_time; commit->parsed = 1; - return GIT_SUCCESS; + return 0; } static int commit_parse(git_revwalk *walk, commit_object *commit) @@ -224,19 +234,159 @@ static int commit_parse(git_revwalk *walk, commit_object *commit) int error; if (commit->parsed) - return GIT_SUCCESS; + return 0; - if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to parse commit. Can't read object"); + if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0) + return error; if (obj->raw.type != GIT_OBJ_COMMIT) { git_odb_object_free(obj); - return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object"); + giterr_set(GITERR_INVALID, "Failed to parse commit. Object is no commit object"); + return -1; } error = commit_quick_parse(walk, commit, &obj->raw); git_odb_object_free(obj); - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse commit"); + return error; +} + +static int interesting(git_pqueue *list) +{ + unsigned int i; + for (i = 1; i < git_pqueue_size(list); i++) { + commit_object *commit = list->d[i]; + if ((commit->flags & STALE) == 0) + return 1; + } + + return 0; +} + +static int merge_bases_many(commit_list **out, git_revwalk *walk, commit_object *one, git_vector *twos) +{ + int error; + unsigned int i; + commit_object *two; + commit_list *result = NULL, *tmp = NULL; + git_pqueue list; + + /* if the commit is repeated, we have a our merge base already */ + git_vector_foreach(twos, i, two) { + if (one == two) + return commit_list_insert(one, out) ? 0 : -1; + } + + if (git_pqueue_init(&list, twos->length * 2, commit_time_cmp) < 0) + return -1; + + if (commit_parse(walk, one) < 0) + return -1; + + one->flags |= PARENT1; + if (git_pqueue_insert(&list, one) < 0) + return -1; + + git_vector_foreach(twos, i, two) { + commit_parse(walk, two); + two->flags |= PARENT2; + if (git_pqueue_insert(&list, two) < 0) + return -1; + } + + /* as long as there are non-STALE commits */ + while (interesting(&list)) { + commit_object *commit; + int flags; + + commit = git_pqueue_pop(&list); + + flags = commit->flags & (PARENT1 | PARENT2 | STALE); + if (flags == (PARENT1 | PARENT2)) { + if (!(commit->flags & RESULT)) { + commit->flags |= RESULT; + if (commit_list_insert(commit, &result) == NULL) + return -1; + } + /* we mark the parents of a merge stale */ + flags |= STALE; + } + + for (i = 0; i < commit->out_degree; i++) { + commit_object *p = commit->parents[i]; + if ((p->flags & flags) == flags) + continue; + + if ((error = commit_parse(walk, p)) < 0) + return error; + + p->flags |= flags; + if (git_pqueue_insert(&list, p) < 0) + return -1; + } + } + + git_pqueue_free(&list); + + /* filter out any stale commits in the results */ + tmp = result; + result = NULL; + + while (tmp) { + struct commit_list *next = tmp->next; + if (!(tmp->item->flags & STALE)) + if (commit_list_insert_by_date(tmp->item, &result) == NULL) + return -1; + + git__free(tmp); + tmp = next; + } + + *out = result; + return 0; +} + +int git_merge_base(git_oid *out, git_repository *repo, git_oid *one, git_oid *two) +{ + git_revwalk *walk; + git_vector list; + commit_list *result = NULL; + commit_object *commit; + void *contents[1]; + + if (git_revwalk_new(&walk, repo) < 0) + return -1; + + commit = commit_lookup(walk, two); + if (commit == NULL) + goto on_error; + + /* This is just one value, so we can do it on the stack */ + memset(&list, 0x0, sizeof(git_vector)); + contents[0] = commit; + list.length = 1; + list.contents = contents; + + commit = commit_lookup(walk, one); + if (commit == NULL) + goto on_error; + + if (merge_bases_many(&result, walk, commit, &list) < 0) + goto on_error; + + if (!result) { + git_revwalk_free(walk); + return GIT_ENOTFOUND; + } + + git_oid_cpy(out, &result->item->oid); + commit_list_free(&result); + git_revwalk_free(walk); + + return 0; + +on_error: + git_revwalk_free(walk); + return -1; } static void mark_uninteresting(commit_object *commit) @@ -246,6 +396,10 @@ static void mark_uninteresting(commit_object *commit) commit->uninteresting = 1; + /* This means we've reached a merge base, so there's no need to walk any more */ + if ((commit->flags & (RESULT | STALE)) == RESULT) + return; + for (i = 0; i < commit->out_degree; ++i) if (!commit->parents[i]->uninteresting) mark_uninteresting(commit->parents[i]); @@ -259,12 +413,12 @@ static int process_commit(git_revwalk *walk, commit_object *commit, int hide) mark_uninteresting(commit); if (commit->seen) - return GIT_SUCCESS; + return 0; commit->seen = 1; - if ((error = commit_parse(walk, commit)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to process commit"); + if ((error = commit_parse(walk, commit)) < 0) + return error; return walk->enqueue(walk, commit); } @@ -272,13 +426,12 @@ static int process_commit(git_revwalk *walk, commit_object *commit, int hide) static int process_commit_parents(git_revwalk *walk, commit_object *commit) { unsigned short i; - int error = GIT_SUCCESS; + int error = 0; - for (i = 0; i < commit->out_degree && error == GIT_SUCCESS; ++i) { + for (i = 0; i < commit->out_degree && !error; ++i) error = process_commit(walk, commit->parents[i], commit->uninteresting); - } - return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to process commit parents"); + return error; } static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) @@ -287,9 +440,17 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) commit = commit_lookup(walk, oid); if (commit == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to push commit. Object not found"); + return -1; /* error already reported by failed lookup */ - return process_commit(walk, commit, uninteresting); + commit->uninteresting = uninteresting; + if (walk->one == NULL && !uninteresting) { + walk->one = commit; + } else { + if (git_vector_insert(&walk->twos, commit) < 0) + return -1; + } + + return 0; } int git_revwalk_push(git_revwalk *walk, const git_oid *oid) @@ -298,12 +459,122 @@ int git_revwalk_push(git_revwalk *walk, const git_oid *oid) return push_commit(walk, oid, 0); } + int git_revwalk_hide(git_revwalk *walk, const git_oid *oid) { assert(walk && oid); return push_commit(walk, oid, 1); } +static int push_ref(git_revwalk *walk, const char *refname, int hide) +{ + git_oid oid; + + if (git_reference_name_to_oid(&oid, walk->repo, refname) < 0) + return -1; + + return push_commit(walk, &oid, hide); +} + +struct push_cb_data { + git_revwalk *walk; + const char *glob; + int hide; +}; + +static int push_glob_cb(const char *refname, void *data_) +{ + struct push_cb_data *data = (struct push_cb_data *)data_; + + if (!p_fnmatch(data->glob, refname, 0)) + return push_ref(data->walk, refname, data->hide); + + return 0; +} + +static int push_glob(git_revwalk *walk, const char *glob, int hide) +{ + git_buf buf = GIT_BUF_INIT; + struct push_cb_data data; + regex_t preg; + + assert(walk && glob); + + /* refs/ is implied if not given in the glob */ + if (strncmp(glob, GIT_REFS_DIR, strlen(GIT_REFS_DIR))) { + git_buf_printf(&buf, GIT_REFS_DIR "%s", glob); + } else { + git_buf_puts(&buf, glob); + } + + /* If no '?', '*' or '[' exist, we append '/ *' to the glob */ + memset(&preg, 0x0, sizeof(regex_t)); + if (regcomp(&preg, "[?*[]", REG_EXTENDED)) { + giterr_set(GITERR_OS, "Regex failed to compile"); + git_buf_free(&buf); + return -1; + } + + if (regexec(&preg, glob, 0, NULL, 0)) + git_buf_puts(&buf, "/*"); + + if (git_buf_oom(&buf)) + goto on_error; + + data.walk = walk; + data.glob = git_buf_cstr(&buf); + data.hide = hide; + + if (git_reference_foreach( + walk->repo, GIT_REF_LISTALL, push_glob_cb, &data) < 0) + goto on_error; + + regfree(&preg); + git_buf_free(&buf); + return 0; + +on_error: + regfree(&preg); + git_buf_free(&buf); + return -1; +} + +int git_revwalk_push_glob(git_revwalk *walk, const char *glob) +{ + assert(walk && glob); + return push_glob(walk, glob, 0); +} + +int git_revwalk_hide_glob(git_revwalk *walk, const char *glob) +{ + assert(walk && glob); + return push_glob(walk, glob, 1); +} + +int git_revwalk_push_head(git_revwalk *walk) +{ + assert(walk); + return push_ref(walk, GIT_HEAD_FILE, 0); +} + +int git_revwalk_hide_head(git_revwalk *walk) +{ + assert(walk); + return push_ref(walk, GIT_HEAD_FILE, 1); +} + +int git_revwalk_push_ref(git_revwalk *walk, const char *refname) +{ + assert(walk && refname); + return push_ref(walk, refname, 0); +} + +int git_revwalk_hide_ref(git_revwalk *walk, const char *refname) +{ + assert(walk && refname); + return push_ref(walk, refname, 1); +} + static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit) { return git_pqueue_insert(&walk->iterator_time, commit); @@ -311,7 +582,7 @@ static int revwalk_enqueue_timesort(git_revwalk *walk, commit_object *commit) static int revwalk_enqueue_unsorted(git_revwalk *walk, commit_object *commit) { - return commit_list_insert(commit, &walk->iterator_rand) ? GIT_SUCCESS : GIT_ENOMEM; + return commit_list_insert(commit, &walk->iterator_rand) ? 0 : -1; } static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk) @@ -320,16 +591,16 @@ static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk) commit_object *next; while ((next = git_pqueue_pop(&walk->iterator_time)) != NULL) { - if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to load next revision"); + if ((error = process_commit_parents(walk, next)) < 0) + return error; if (!next->uninteresting) { *object_out = next; - return GIT_SUCCESS; + return 0; } } - return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); + return GIT_REVWALKOVER; } static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk) @@ -338,16 +609,16 @@ static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk) commit_object *next; while ((next = commit_list_pop(&walk->iterator_rand)) != NULL) { - if ((error = process_commit_parents(walk, next)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to load next revision"); + if ((error = process_commit_parents(walk, next)) < 0) + return error; if (!next->uninteresting) { *object_out = next; - return GIT_SUCCESS; + return 0; } } - return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); + return GIT_REVWALKOVER; } static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) @@ -358,7 +629,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) for (;;) { next = commit_list_pop(&walk->iterator_topo); if (next == NULL) - return git__throw(GIT_EREVWALKOVER, "Failed to load next revision"); + return GIT_REVWALKOVER; if (next->in_degree > 0) { next->topo_delay = 1; @@ -370,58 +641,83 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) if (--parent->in_degree == 0 && parent->topo_delay) { parent->topo_delay = 0; - commit_list_insert(parent, &walk->iterator_topo); + if (commit_list_insert(parent, &walk->iterator_topo) == NULL) + return -1; } } *object_out = next; - return GIT_SUCCESS; + return 0; } } static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk) { *object_out = commit_list_pop(&walk->iterator_reverse); - return *object_out ? GIT_SUCCESS : GIT_EREVWALKOVER; + return *object_out ? 0 : GIT_REVWALKOVER; } static int prepare_walk(git_revwalk *walk) { int error; - commit_object *next; + unsigned int i; + commit_object *next, *two; + commit_list *bases = NULL; + + /* + * If walk->one is NULL, there were no positive references, + * so we know that the walk is already over. + */ + if (walk->one == NULL) + return GIT_REVWALKOVER; + + /* first figure out what the merge bases are */ + if (merge_bases_many(&bases, walk, walk->one, &walk->twos) < 0) + return -1; + + commit_list_free(&bases); + if (process_commit(walk, walk->one, walk->one->uninteresting) < 0) + return -1; + + git_vector_foreach(&walk->twos, i, two) { + if (process_commit(walk, two, two->uninteresting) < 0) + return -1; + } if (walk->sorting & GIT_SORT_TOPOLOGICAL) { unsigned short i; - while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) { + while ((error = walk->get_next(&next, walk)) == 0) { for (i = 0; i < next->out_degree; ++i) { commit_object *parent = next->parents[i]; parent->in_degree++; } - commit_list_insert(next, &walk->iterator_topo); + if (commit_list_insert(next, &walk->iterator_topo) == NULL) + return -1; } - if (error != GIT_EREVWALKOVER) - return git__rethrow(error, "Failed to prepare revision walk"); + if (error != GIT_REVWALKOVER) + return error; walk->get_next = &revwalk_next_toposort; } if (walk->sorting & GIT_SORT_REVERSE) { - while ((error = walk->get_next(&next, walk)) == GIT_SUCCESS) - commit_list_insert(next, &walk->iterator_reverse); + while ((error = walk->get_next(&next, walk)) == 0) + if (commit_list_insert(next, &walk->iterator_reverse) == NULL) + return -1; - if (error != GIT_EREVWALKOVER) - return git__rethrow(error, "Failed to prepare revision walk"); + if (error != GIT_REVWALKOVER) + return error; walk->get_next = &revwalk_next_reverse; } walk->walking = 1; - return GIT_SUCCESS; + return 0; } @@ -430,70 +726,48 @@ static int prepare_walk(git_revwalk *walk) int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { - int error; git_revwalk *walk; walk = git__malloc(sizeof(git_revwalk)); - if (walk == NULL) - return GIT_ENOMEM; + GITERR_CHECK_ALLOC(walk); memset(walk, 0x0, sizeof(git_revwalk)); - walk->commits = git_hashtable_alloc(64, - object_table_hash, - (git_hash_keyeq_ptr)git_oid_cmp); + walk->commits = git_oidmap_alloc(); + GITERR_CHECK_ALLOC(walk->commits); - if (walk->commits == NULL) { - git__free(walk); - return GIT_ENOMEM; - } - - git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp); - git_vector_init(&walk->memory_alloc, 8, NULL); - alloc_chunk(walk); + if (git_pqueue_init(&walk->iterator_time, 8, commit_time_cmp) < 0 || + git_vector_init(&walk->twos, 4, NULL) < 0 || + git_pool_init(&walk->commit_pool, 1, + git_pool__suggest_items_per_page(COMMIT_ALLOC) * COMMIT_ALLOC) < 0) + return -1; walk->get_next = &revwalk_next_unsorted; walk->enqueue = &revwalk_enqueue_unsorted; walk->repo = repo; - error = git_repository_odb(&walk->odb, repo); - if (error < GIT_SUCCESS) { + if (git_repository_odb(&walk->odb, repo) < 0) { git_revwalk_free(walk); - return error; + return -1; } *revwalk_out = walk; - return GIT_SUCCESS; + return 0; } void git_revwalk_free(git_revwalk *walk) { - unsigned int i; - const void *GIT_UNUSED(_unused); - commit_object *commit; - if (walk == NULL) return; git_revwalk_reset(walk); git_odb_free(walk->odb); - /* if the parent has more than PARENTS_PER_COMMIT parents, - * we had to allocate a separate array for those parents. - * make sure it's being free'd */ - GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, { - if (commit->out_degree > PARENTS_PER_COMMIT) - git__free(commit->parents); - }); - - git_hashtable_free(walk->commits); + git_oidmap_free(walk->commits); + git_pool_clear(&walk->commit_pool); git_pqueue_free(&walk->iterator_time); - - for (i = 0; i < walk->memory_alloc.length; ++i) - git__free(git_vector_get(&walk->memory_alloc, i)); - - git_vector_free(&walk->memory_alloc); + git_vector_free(&walk->twos); git__free(walk); } @@ -529,41 +803,43 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk) assert(walk && oid); if (!walk->walking) { - if ((error = prepare_walk(walk)) < GIT_SUCCESS) - return git__rethrow(error, "Failed to load next revision"); + if ((error = prepare_walk(walk)) < 0) + return error; } error = walk->get_next(&next, walk); - if (error == GIT_EREVWALKOVER) { + if (error == GIT_REVWALKOVER) { git_revwalk_reset(walk); - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; } - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to load next revision"); + if (!error) + git_oid_cpy(oid, &next->oid); - git_oid_cpy(oid, &next->oid); - return GIT_SUCCESS; + return error; } void git_revwalk_reset(git_revwalk *walk) { - const void *GIT_UNUSED(_unused); commit_object *commit; assert(walk); - GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, + kh_foreach_value(walk->commits, commit, { commit->seen = 0; commit->in_degree = 0; commit->topo_delay = 0; - ); + commit->uninteresting = 0; + }); git_pqueue_clear(&walk->iterator_time); commit_list_free(&walk->iterator_topo); commit_list_free(&walk->iterator_rand); commit_list_free(&walk->iterator_reverse); walk->walking = 0; + + walk->one = NULL; + git_vector_clear(&walk->twos); } |