diff --git a/src/idxmap.h b/src/idxmap.h index 74304bb97..4122a89fe 100644 --- a/src/idxmap.h +++ b/src/idxmap.h @@ -70,6 +70,7 @@ static kh_inline khint_t idxentry_hash(const git_index_entry *e) #define git_idxmap_valid_index(h, idx) (idx != kh_end(h)) #define git_idxmap_has_data(h, idx) kh_exist(h, idx) +#define git_idxmap_resize(h,s) kh_resize(idx, h, s) #define git_idxmap_free(h) kh_destroy(idx, h), h = NULL #define git_idxmap_clear(h) kh_clear(idx, h) diff --git a/src/index.c b/src/index.c index 60e4d443c..5c7bd90dd 100644 --- a/src/index.c +++ b/src/index.c @@ -879,6 +879,18 @@ void git_index_entry__init_from_stat( entry->file_size = st->st_size; } +static void index_entry_adjust_namemask( + git_index_entry *entry, + size_t path_length) +{ + entry->flags &= ~GIT_IDXENTRY_NAMEMASK; + + if (path_length < GIT_IDXENTRY_NAMEMASK) + entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK; + else + entry->flags |= GIT_IDXENTRY_NAMEMASK; +} + static int index_entry_create( git_index_entry **out, git_repository *repo, @@ -1279,13 +1291,7 @@ static int index_insert( /* make sure that the path length flag is correct */ path_length = ((struct entry_internal *)entry)->pathlen; - - entry->flags &= ~GIT_IDXENTRY_NAMEMASK; - - if (path_length < GIT_IDXENTRY_NAMEMASK) - entry->flags |= path_length & GIT_IDXENTRY_NAMEMASK; - else - entry->flags |= GIT_IDXENTRY_NAMEMASK; + index_entry_adjust_namemask(entry, path_length); /* this entry is now up-to-date and should not be checked for raciness */ entry->flags_extended |= GIT_IDXENTRY_UPTODATE; @@ -1550,21 +1556,28 @@ int git_index__fill(git_index *index, const git_vector *source_entries) assert(index); + if (!source_entries->length) + return 0; + if (git_mutex_lock(&index->lock) < 0) { giterr_set(GITERR_OS, "Unable to acquire index lock"); return -1; } + git_vector_size_hint(&index->entries, source_entries->length); + git_idxmap_resize(index->entries_map, source_entries->length * 1.3); + git_vector_foreach(source_entries, i, source_entry) { git_index_entry *entry = NULL; if ((ret = index_entry_dup(&entry, index, source_entry)) < 0) break; + index_entry_adjust_namemask(entry, ((struct entry_internal *)entry)->pathlen); entry->flags_extended |= GIT_IDXENTRY_UPTODATE; + entry->mode = git_index__create_mode(entry->mode); - ret = git_vector_insert(&index->entries, entry); - if (ret < 0) + if ((ret = git_vector_insert(&index->entries, entry)) < 0) break; INSERT_IN_MAP(index, entry, ret); @@ -2889,11 +2902,7 @@ static int read_tree_cb( entry->flags_extended = 0; } - if (path.size < GIT_IDXENTRY_NAMEMASK) - entry->flags = path.size & GIT_IDXENTRY_NAMEMASK; - else - entry->flags = GIT_IDXENTRY_NAMEMASK; - + index_entry_adjust_namemask(entry, path.size); git_buf_free(&path); if (git_vector_insert(data->new_entries, entry) < 0) { diff --git a/src/vector.c b/src/vector.c index 93d09bb5b..a81d463ef 100644 --- a/src/vector.c +++ b/src/vector.c @@ -40,6 +40,13 @@ GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size) return 0; } +int git_vector_size_hint(git_vector *v, size_t size_hint) +{ + if (v->_alloc_size >= size_hint) + return 0; + return resize_vector(v, size_hint); +} + int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) { size_t bytes; diff --git a/src/vector.h b/src/vector.h index aac46c4b3..b7500ded3 100644 --- a/src/vector.h +++ b/src/vector.h @@ -32,6 +32,7 @@ void git_vector_free_deep(git_vector *v); /* free each entry and self */ void git_vector_clear(git_vector *v); int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp); void git_vector_swap(git_vector *a, git_vector *b); +int git_vector_size_hint(git_vector *v, size_t size_hint); void **git_vector_detach(size_t *size, size_t *asize, git_vector *v);