diff options
-rw-r--r-- | COPYING | 75 | ||||
-rw-r--r-- | include/git2/revwalk.h | 18 | ||||
-rw-r--r-- | src/commit.c | 40 | ||||
-rw-r--r-- | src/commit_list.c | 6 | ||||
-rw-r--r-- | src/commit_list.h | 2 | ||||
-rw-r--r-- | src/graph.c | 35 | ||||
-rw-r--r-- | src/index.c | 39 | ||||
-rw-r--r-- | src/index.h | 2 | ||||
-rw-r--r-- | src/merge.c | 15 | ||||
-rw-r--r-- | src/pathspec.c | 2 | ||||
-rw-r--r-- | src/posix.h | 13 | ||||
-rw-r--r-- | src/pqueue.c | 192 | ||||
-rw-r--r-- | src/pqueue.h | 115 | ||||
-rw-r--r-- | src/repository.c | 6 | ||||
-rw-r--r-- | src/revparse.c | 3 | ||||
-rw-r--r-- | src/revwalk.c | 75 | ||||
-rw-r--r-- | src/sortedcache.c | 2 | ||||
-rw-r--r-- | src/strnlen.h | 23 | ||||
-rw-r--r-- | src/tree.c | 6 | ||||
-rw-r--r-- | src/util.h | 4 | ||||
-rw-r--r-- | src/vector.c | 17 | ||||
-rw-r--r-- | src/vector.h | 17 | ||||
-rw-r--r-- | src/win32/utf-conv.c | 62 | ||||
-rw-r--r-- | tests/core/pqueue.c | 97 | ||||
-rw-r--r-- | tests/index/tests.c | 42 | ||||
-rw-r--r-- | tests/object/tree/write.c | 100 | ||||
-rw-r--r-- | tests/repo/head.c | 2 | ||||
-rw-r--r-- | tests/repo/message.c | 28 | ||||
-rw-r--r-- | tests/revwalk/basic.c | 38 |
29 files changed, 564 insertions, 512 deletions
@@ -388,19 +388,7 @@ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler ---------------------------------------------------------------------- -The priority queue implementation is based on code licensed under the -Apache 2.0 license: - - Copyright 2010 Volkan Yazıcı <volkan.yazici@gmail.com> - Copyright 2006-2010 The Apache Software Foundation - -The full text of the Apache 2.0 license is available at: - - http://www.apache.org/licenses/LICENSE-2.0 - ----------------------------------------------------------------------- - -The Clay framework is licensed under the MIT license: +The Clar framework is licensed under the MIT license: Copyright (C) 2011 by Vicent Marti @@ -930,64 +918,3 @@ necessary. Here is a sample; alter the names: That's all there is to it! ---------------------------------------------------------------------- - -Portions of src/win32/posix_w32.c are derrived from link_win32.c in PHP: - --------------------------------------------------------------------- - The PHP License, version 3.01 -Copyright (c) 1999 - 2012 The PHP Group. All rights reserved. --------------------------------------------------------------------- - -Redistribution and use in source and binary forms, with or without -modification, is permitted provided that the following conditions -are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - 3. The name "PHP" must not be used to endorse or promote products - derived from this software without prior written permission. For - written permission, please contact group@php.net. - - 4. Products derived from this software may not be called "PHP", nor - may "PHP" appear in their name, without prior written permission - from group@php.net. You may indicate that your software works in - conjunction with PHP by saying "Foo for PHP" instead of calling - it "PHP Foo" or "phpfoo" - - 5. The PHP Group may publish revised and/or new versions of the - license from time to time. Each version will be given a - distinguishing version number. - Once covered code has been published under a particular version - of the license, you may always continue to use it under the terms - of that version. You may also choose to use such covered code - under the terms of any subsequent version of the license - published by the PHP Group. No one other than the PHP Group has - the right to modify the terms applicable to covered code created - under this License. - - 6. Redistributions of any form whatsoever must retain the following - acknowledgment: - "This product includes PHP software, freely available from - <http://www.php.net/software/>". - -THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND -ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP -DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -OF THE POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------------------------- - diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index c59b79938..aef0b5fa6 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -87,7 +87,7 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); /** * Mark a commit to start traversal from. * - * The given OID must belong to a commit on the walked + * The given OID must belong to a committish on the walked * repository. * * The given commit will be used as one of the roots @@ -108,7 +108,10 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *id); * pattern will be pushed to the revision walker. * * A leading 'refs/' is implied if not present as well as a trailing - * '/ *' if the glob lacks '?', '*' or '['. + * '/\*' if the glob lacks '?', '\*' or '['. + * + * Any references matching this glob which do not point to a + * committish will be ignored. * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match @@ -127,7 +130,7 @@ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk); /** * Mark a commit (and its ancestors) uninteresting for the output. * - * The given OID must belong to a commit on the walked + * The given OID must belong to a committish on the walked * repository. * * The resolved commit and all its parents will be hidden from the @@ -147,7 +150,10 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *commit_id); * revision walk. * * A leading 'refs/' is implied if not present as well as a trailing - * '/ *' if the glob lacks '?', '*' or '['. + * '/\*' if the glob lacks '?', '\*' or '['. + * + * Any references matching this glob which do not point to a + * committish will be ignored. * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match @@ -166,7 +172,7 @@ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk); /** * Push the OID pointed to by a reference * - * The reference must point to a commit. + * The reference must point to a committish. * * @param walk the walker being used for the traversal * @param refname the reference to push @@ -177,7 +183,7 @@ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname); /** * Hide the OID pointed to by a reference * - * The reference must point to a commit. + * The reference must point to a committish. * * @param walk the walker being used for the traversal * @param refname the reference to hide diff --git a/src/commit.c b/src/commit.c index da7c4992e..730fa6403 100644 --- a/src/commit.c +++ b/src/commit.c @@ -164,33 +164,15 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) const char *buffer_start = git_odb_object_data(odb_obj), *buffer; const char *buffer_end = buffer_start + git_odb_object_size(odb_obj); git_oid parent_id; - uint32_t parent_count = 0; size_t header_len; - /* find end-of-header (counting parents as we go) */ - for (buffer = buffer_start; buffer < buffer_end; ++buffer) { - if (!strncmp("\n\n", buffer, 2)) { - ++buffer; - break; - } - if (!strncmp("\nparent ", buffer, strlen("\nparent "))) - ++parent_count; - } - - header_len = buffer - buffer_start; - commit->raw_header = git__strndup(buffer_start, header_len); - GITERR_CHECK_ALLOC(commit->raw_header); + buffer = buffer_start; - /* point "buffer" to header data */ - buffer = commit->raw_header; - buffer_end = commit->raw_header + header_len; - - if (parent_count < 1) - parent_count = 1; - - git_array_init_to_size(commit->parent_ids, parent_count); + /* Allocate for one, which will allow not to realloc 90% of the time */ + git_array_init_to_size(commit->parent_ids, 1); GITERR_CHECK_ARRAY(commit->parent_ids); + /* The tree is always the first field */ if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) goto bad_buffer; @@ -221,6 +203,9 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) /* Parse add'l header entries */ while (buffer < buffer_end) { const char *eoln = buffer; + if (buffer[-1] == '\n' && buffer[0] == '\n') + break; + while (eoln < buffer_end && *eoln != '\n') ++eoln; @@ -236,13 +221,12 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) buffer = eoln; } - /* point "buffer" to data after header */ - buffer = git_odb_object_data(odb_obj); - buffer_end = buffer + git_odb_object_size(odb_obj); + header_len = buffer - buffer_start; + commit->raw_header = git__strndup(buffer_start, header_len); + GITERR_CHECK_ALLOC(commit->raw_header); - buffer += header_len; - if (*buffer == '\n') - ++buffer; + /* point "buffer" to data after header, +1 for the final LF */ + buffer = buffer_start + header_len + 1; /* extract commit message */ if (buffer <= buffer_end) { diff --git a/src/commit_list.c b/src/commit_list.c index 64416e54d..9db3f5633 100644 --- a/src/commit_list.c +++ b/src/commit_list.c @@ -11,10 +11,10 @@ #include "pool.h" #include "odb.h" -int git_commit_list_time_cmp(void *a, void *b) +int git_commit_list_time_cmp(const void *a, const void *b) { - git_commit_list_node *commit_a = (git_commit_list_node *)a; - git_commit_list_node *commit_b = (git_commit_list_node *)b; + const git_commit_list_node *commit_a = a; + const git_commit_list_node *commit_b = b; return (commit_a->time < commit_b->time); } diff --git a/src/commit_list.h b/src/commit_list.h index d2f54b3ca..490d841be 100644 --- a/src/commit_list.h +++ b/src/commit_list.h @@ -39,7 +39,7 @@ typedef struct git_commit_list { } git_commit_list; git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk); -int git_commit_list_time_cmp(void *a, void *b); +int git_commit_list_time_cmp(const void *a, const void *b); void git_commit_list_free(git_commit_list **list_p); git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p); git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p); diff --git a/src/graph.c b/src/graph.c index f39af5ed5..96fda7add 100644 --- a/src/graph.c +++ b/src/graph.c @@ -1,4 +1,3 @@ - /* * Copyright (C) the libgit2 contributors. All rights reserved. * @@ -13,9 +12,9 @@ static int interesting(git_pqueue *list, git_commit_list *roots) { unsigned int i; - /* element 0 isn't used - we need to start at 1 */ - for (i = 1; i < list->size; i++) { - git_commit_list_node *commit = list->d[i]; + + for (i = 0; i < git_pqueue_size(list); i++) { + git_commit_list_node *commit = git_pqueue_get(list, i); if ((commit->flags & STALE) == 0) return 1; } @@ -42,7 +41,7 @@ static int mark_parents(git_revwalk *walk, git_commit_list_node *one, return 0; } - if (git_pqueue_init(&list, 2, git_commit_list_time_cmp) < 0) + if (git_pqueue_init(&list, 0, 2, git_commit_list_time_cmp) < 0) return -1; if (git_commit_list_parse(walk, one) < 0) @@ -59,10 +58,9 @@ static int mark_parents(git_revwalk *walk, git_commit_list_node *one, /* as long as there are non-STALE commits */ while (interesting(&list, roots)) { - git_commit_list_node *commit; + git_commit_list_node *commit = git_pqueue_pop(&list); int flags; - commit = git_pqueue_pop(&list); if (commit == NULL) break; @@ -110,16 +108,16 @@ static int ahead_behind(git_commit_list_node *one, git_commit_list_node *two, { git_commit_list_node *commit; git_pqueue pq; - int i; + int error = 0, i; *ahead = 0; *behind = 0; - if (git_pqueue_init(&pq, 2, git_commit_list_time_cmp) < 0) + if (git_pqueue_init(&pq, 0, 2, git_commit_list_time_cmp) < 0) return -1; - if (git_pqueue_insert(&pq, one) < 0) - goto on_error; - if (git_pqueue_insert(&pq, two) < 0) - goto on_error; + + if ((error = git_pqueue_insert(&pq, one)) < 0 || + (error = git_pqueue_insert(&pq, two)) < 0) + goto done; while ((commit = git_pqueue_pop(&pq)) != NULL) { if (commit->flags & RESULT || @@ -132,18 +130,15 @@ static int ahead_behind(git_commit_list_node *one, git_commit_list_node *two, for (i = 0; i < commit->out_degree; i++) { git_commit_list_node *p = commit->parents[i]; - if (git_pqueue_insert(&pq, p) < 0) - return -1; + if ((error = git_pqueue_insert(&pq, p)) < 0) + goto done; } commit->flags |= RESULT; } +done: git_pqueue_free(&pq); - return 0; - -on_error: - git_pqueue_free(&pq); - return -1; + return error; } int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, diff --git a/src/index.c b/src/index.c index 7bc5d5b24..aa1aebf8a 100644 --- a/src/index.c +++ b/src/index.c @@ -90,7 +90,7 @@ struct entry_long { struct entry_srch_key { const char *path; - int path_len; + size_t path_len; int stage; }; @@ -110,7 +110,8 @@ static int index_srch(const void *key, const void *array_member) { const struct entry_srch_key *srch_key = key; const git_index_entry *entry = array_member; - int cmp, len1, len2, len; + int cmp; + size_t len1, len2, len; len1 = srch_key->path_len; len2 = strlen(entry->path); @@ -134,7 +135,8 @@ static int index_isrch(const void *key, const void *array_member) { const struct entry_srch_key *srch_key = key; const git_index_entry *entry = array_member; - int cmp, len1, len2, len; + int cmp; + size_t len1, len2, len; len1 = srch_key->path_len; len2 = strlen(entry->path); @@ -599,9 +601,7 @@ const git_index_entry *git_index_get_bypath( assert(index); - git_vector_sort(&index->entries); - - if (git_index__find(&pos, index, path, strlen(path), stage) < 0) { + if (git_index__find(&pos, index, path, 0, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s", path); return NULL; } @@ -837,8 +837,7 @@ static int index_insert(git_index *index, git_index_entry *entry, int replace) /* look if an entry with this path already exists */ if (!git_index__find( - &position, index, entry->path, strlen(entry->path), - GIT_IDXENTRY_STAGE(entry))) { + &position, index, entry->path, 0, GIT_IDXENTRY_STAGE(entry))) { existing = (git_index_entry **)&index->entries.contents[position]; /* update filemode to existing values if stat is not trusted */ entry->mode = index_merge_mode(index, *existing, entry->mode); @@ -950,9 +949,7 @@ int git_index_remove(git_index *index, const char *path, int stage) int error; git_index_entry *entry; - git_vector_sort(&index->entries); - - if (git_index__find(&position, index, path, strlen(path), stage) < 0) { + if (git_index__find(&position, index, path, 0, stage) < 0) { giterr_set(GITERR_INDEX, "Index does not contain %s at stage %d", path, stage); return GIT_ENOTFOUND; @@ -1009,18 +1006,20 @@ int git_index_remove_directory(git_index *index, const char *dir, int stage) } int git_index__find( - size_t *at_pos, git_index *index, const char *path, int path_len, int stage) + size_t *out, git_index *index, const char *path, size_t path_len, int stage) { struct entry_srch_key srch_key; assert(path); + git_vector_sort(&index->entries); + srch_key.path = path; - srch_key.path_len = path_len; + srch_key.path_len = !path_len ? strlen(path) : path_len; srch_key.stage = stage; return git_vector_bsearch2( - at_pos, &index->entries, index->entries_search, &srch_key); + out, &index->entries, index->entries_search, &srch_key); } int git_index_find(size_t *at_pos, git_index *index, const char *path) @@ -1564,7 +1563,7 @@ static int read_reuc(git_index *index, const char *buffer, size_t size) } /* entries are guaranteed to be sorted on-disk */ - index->reuc.sorted = 1; + git_vector_set_sorted(&index->reuc, true); return 0; } @@ -1610,7 +1609,7 @@ static int read_conflict_names(git_index *index, const char *buffer, size_t size #undef read_conflict_name /* entries are guaranteed to be sorted on-disk */ - index->names.sorted = 1; + git_vector_set_sorted(&index->names, true); return 0; } @@ -1811,8 +1810,10 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) #undef seek_forward - /* Entries are stored case-sensitively on disk. */ - index->entries.sorted = !index->ignore_case; + /* Entries are stored case-sensitively on disk, so re-sort now if + * in-memory index is supposed to be case-insensitive + */ + git_vector_set_sorted(&index->entries, !index->ignore_case); git_vector_sort(&index->entries); return 0; @@ -2232,7 +2233,7 @@ int git_index_add_all( /* skip ignored items that are not already in the index */ if ((flags & GIT_INDEX_ADD_FORCE) == 0 && git_iterator_current_is_ignored(wditer) && - git_index__find(&existing, index, wd->path, strlen(wd->path), 0) < 0) + git_index__find(&existing, index, wd->path, 0, 0) < 0) continue; /* issue notification callback if requested */ diff --git a/src/index.h b/src/index.h index 3dea4aa14..f88d110f7 100644 --- a/src/index.h +++ b/src/index.h @@ -56,7 +56,7 @@ extern int git_index_entry__cmp(const void *a, const void *b); extern int git_index_entry__cmp_icase(const void *a, const void *b); extern int git_index__find( - size_t *at_pos, git_index *index, const char *path, int path_len, int stage); + size_t *at_pos, git_index *index, const char *path, size_t path_len, int stage); extern void git_index__set_ignore_case(git_index *index, bool ignore_case); diff --git a/src/merge.c b/src/merge.c index ac973efd0..97c147920 100644 --- a/src/merge.c +++ b/src/merge.c @@ -161,10 +161,10 @@ on_error: static int interesting(git_pqueue *list) { - unsigned int i; - /* element 0 isn't used - we need to start at 1 */ - for (i = 1; i < list->size; i++) { - git_commit_list_node *commit = list->d[i]; + size_t i; + + for (i = 0; i < git_pqueue_size(list); i++) { + git_commit_list_node *commit = git_pqueue_get(list, i); if ((commit->flags & STALE) == 0) return 1; } @@ -186,7 +186,7 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l return git_commit_list_insert(one, out) ? 0 : -1; } - if (git_pqueue_init(&list, twos->length * 2, git_commit_list_time_cmp) < 0) + if (git_pqueue_init(&list, 0, twos->length * 2, git_commit_list_time_cmp) < 0) return -1; if (git_commit_list_parse(walk, one) < 0) @@ -205,10 +205,11 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l /* as long as there are non-STALE commits */ while (interesting(&list)) { - git_commit_list_node *commit; + git_commit_list_node *commit = git_pqueue_pop(&list); int flags; - commit = git_pqueue_pop(&list); + if (commit == NULL) + break; flags = commit->flags & (PARENT1 | PARENT2 | STALE); if (flags == (PARENT1 | PARENT2)) { diff --git a/src/pathspec.c b/src/pathspec.c index bee320576..471488495 100644 --- a/src/pathspec.c +++ b/src/pathspec.c @@ -445,7 +445,7 @@ static int pathspec_match_from_iterator( /* check if path is ignored and untracked */ if (index != NULL && git_iterator_current_is_ignored(iter) && - git_index__find(NULL, index, entry->path, strlen(entry->path), GIT_INDEX_STAGE_ANY) < 0) + git_index__find(NULL, index, entry->path, 0, GIT_INDEX_STAGE_ANY) < 0) continue; /* mark the matched pattern as used */ diff --git a/src/posix.h b/src/posix.h index 0d9be49a9..6d3a84eba 100644 --- a/src/posix.h +++ b/src/posix.h @@ -89,18 +89,7 @@ extern struct tm * p_gmtime_r (const time_t *timer, struct tm *result); # include "unix/posix.h" #endif -#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__) -# define NO_STRNLEN -#endif - -#ifdef NO_STRNLEN -GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) { - const char *end = memchr(s, 0, maxlen); - return end ? (size_t)(end - s) : maxlen; -} -#else -# define p_strnlen strnlen -#endif +#include "strnlen.h" #ifdef NO_READDIR_R # include <dirent.h> diff --git a/src/pqueue.c b/src/pqueue.c index 7819ed41e..172cf43d5 100644 --- a/src/pqueue.c +++ b/src/pqueue.c @@ -3,161 +3,115 @@ * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. - * - * This file is based on a modified version of the priority queue found - * in the Apache project and libpqueue library. - * - * https://github.com/vy/libpqueue - * - * Original file notice: - * - * Copyright 2010 Volkan Yazici <volkan.yazici@gmail.com> - * Copyright 2006-2010 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. */ -#include "common.h" #include "pqueue.h" +#include "util.h" -#define left(i) ((i) << 1) -#define right(i) (((i) << 1) + 1) -#define parent(i) ((i) >> 1) +#define PQUEUE_LCHILD_OF(I) (((I)<<1)+1) +#define PQUEUE_RCHILD_OF(I) (((I)<<1)+2) +#define PQUEUE_PARENT_OF(I) (((I)-1)>>1) -int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri) +int git_pqueue_init( + git_pqueue *pq, + uint32_t flags, + size_t init_size, + git_vector_cmp cmp) { - assert(q); + int error = git_vector_init(pq, init_size, cmp); - /* Need to allocate n+1 elements since element 0 isn't used. */ - q->d = git__malloc((n + 1) * sizeof(void *)); - GITERR_CHECK_ALLOC(q->d); + if (!error) { + /* mix in our flags */ + pq->flags |= flags; - q->size = 1; - q->avail = q->step = (n + 1); /* see comment above about n+1 */ - q->cmppri = cmppri; + /* if fixed size heap, pretend vector is exactly init_size elements */ + if ((flags & GIT_PQUEUE_FIXED_SIZE) && init_size > 0) + pq->_alloc_size = init_size; + } - return 0; + return error; } - -void git_pqueue_free(git_pqueue *q) +static void pqueue_up(git_pqueue *pq, size_t el) { - git__free(q->d); - q->d = NULL; -} + size_t parent_el = PQUEUE_PARENT_OF(el); + void *kid = git_vector_get(pq, el); -void git_pqueue_clear(git_pqueue *q) -{ - q->size = 1; -} + while (el > 0) { + void *parent = pq->contents[parent_el]; -size_t git_pqueue_size(git_pqueue *q) -{ - /* queue element 0 exists but doesn't count since it isn't used. */ - return (q->size - 1); -} + if (pq->_cmp(parent, kid) <= 0) + break; + pq->contents[el] = parent; -static void bubble_up(git_pqueue *q, size_t i) -{ - size_t parent_node; - void *moving_node = q->d[i]; - - for (parent_node = parent(i); - ((i > 1) && q->cmppri(q->d[parent_node], moving_node)); - i = parent_node, parent_node = parent(i)) { - q->d[i] = q->d[parent_node]; + el = parent_el; + parent_el = PQUEUE_PARENT_OF(el); } - q->d[i] = moving_node; + pq->contents[el] = kid; } - -static size_t maxchild(git_pqueue *q, size_t i) +static void pqueue_down(git_pqueue *pq, size_t el) { - size_t child_node = left(i); + void *parent = git_vector_get(pq, el), *kid, *rkid; - if (child_node >= q->size) - return 0; + while (1) { + size_t kid_el = PQUEUE_LCHILD_OF(el); - if ((child_node + 1) < q->size && - q->cmppri(q->d[child_node], q->d[child_node + 1])) - child_node++; /* use right child instead of left */ + if ((kid = git_vector_get(pq, kid_el)) == NULL) + break; - return child_node; -} + if ((rkid = git_vector_get(pq, kid_el + 1)) != NULL && + pq->_cmp(kid, rkid) > 0) { + kid = rkid; + kid_el += 1; + } + if (pq->_cmp(parent, kid) < 0) + break; -static void percolate_down(git_pqueue *q, size_t i) -{ - size_t child_node; - void *moving_node = q->d[i]; - - while ((child_node = maxchild(q, i)) != 0 && - q->cmppri(moving_node, q->d[child_node])) { - q->d[i] = q->d[child_node]; - i = child_node; + pq->contents[el] = kid; + el = kid_el; } - q->d[i] = moving_node; + pq->contents[el] = parent; } - -int git_pqueue_insert(git_pqueue *q, void *d) +int git_pqueue_insert(git_pqueue *pq, void *item) { - void *tmp; - size_t i; - size_t newsize; - - if (!q) return 1; - - /* allocate more memory if necessary */ - if (q->size >= q->avail) { - newsize = q->size + q->step; - tmp = git__realloc(q->d, sizeof(void *) * newsize); - GITERR_CHECK_ALLOC(tmp); - - q->d = tmp; - q->avail = newsize; + int error = 0; + + /* if heap is full, pop the top element if new one should replace it */ + if ((pq->flags & GIT_PQUEUE_FIXED_SIZE) != 0 && + pq->length >= pq->_alloc_size) + { + /* skip this item if below min item in heap */ + if (pq->_cmp(item, git_vector_get(pq, 0)) <= 0) + return 0; + /* otherwise remove the min item before inserting new */ + (void)git_pqueue_pop(pq); } - /* insert item */ - i = q->size++; - q->d[i] = d; - bubble_up(q, i); + if (!(error = git_vector_insert(pq, item))) + pqueue_up(pq, pq->length - 1); - return 0; + return error; } - -void *git_pqueue_pop(git_pqueue *q) +void *git_pqueue_pop(git_pqueue *pq) { - void *head; - - if (!q || q->size == 1) - return NULL; - - head = q->d[1]; - q->d[1] = q->d[--q->size]; - percolate_down(q, 1); - - return head; -} - + void *rval = git_pqueue_get(pq, 0); + + if (git_pqueue_size(pq) > 1) { + /* move last item to top of heap, shrink, and push item down */ + pq->contents[0] = git_vector_last(pq); + git_vector_pop(pq); + pqueue_down(pq, 0); + } else { + /* all we need to do is shrink the heap in this case */ + git_vector_pop(pq); + } -void *git_pqueue_peek(git_pqueue *q) -{ - if (!q || q->size == 1) - return NULL; - return q->d[1]; + return rval; } diff --git a/src/pqueue.h b/src/pqueue.h index 9061f8279..da7b74edf 100644 --- a/src/pqueue.h +++ b/src/pqueue.h @@ -3,99 +3,54 @@ * * This file is part of libgit2, distributed under the GNU GPL v2 with * a Linking Exception. For full terms see the included COPYING file. - * - * This file is based on a modified version of the priority queue found - * in the Apache project and libpqueue library. - * - * https://github.com/vy/libpqueue - * - * Original file notice: - * - * Copyright 2010 Volkan Yazici <volkan.yazici@gmail.com> - * Copyright 2006-2010 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. */ - #ifndef INCLUDE_pqueue_h__ #define INCLUDE_pqueue_h__ -/** callback functions to get/set/compare the priority of an element */ -typedef int (*git_pqueue_cmp)(void *a, void *b); +#include "vector.h" -/** the priority queue handle */ -typedef struct { - size_t size, avail, step; - git_pqueue_cmp cmppri; - void **d; -} git_pqueue; +typedef git_vector git_pqueue; +enum { + /* flag meaning: don't grow heap, keep highest values only */ + GIT_PQUEUE_FIXED_SIZE = (GIT_VECTOR_FLAG_MAX << 1), +}; /** - * initialize the queue + * Initialize priority queue * - * @param n the initial estimate of the number of queue items for which memory - * should be preallocated - * @param cmppri the callback function to compare two nodes of the queue - * - * @return the handle or NULL for insufficent memory - */ -int git_pqueue_init(git_pqueue *q, size_t n, git_pqueue_cmp cmppri); - - -/** - * free all memory used by the queue - * @param q the queue - */ -void git_pqueue_free(git_pqueue *q); - -/** - * clear all the elements in the queue - * @param q the queue - */ -void git_pqueue_clear(git_pqueue *q); + * @param pq The priority queue struct to initialize + * @param flags Flags (see above) to control queue behavior + * @param init_size The initial queue size + * @param cmp The entry priority comparison function + * @return 0 on success, <0 on error + */ +extern int git_pqueue_init( + git_pqueue *pq, + uint32_t flags, + size_t init_size, + git_vector_cmp cmp); + +#define git_pqueue_free git_vector_free +#define git_pqueue_clear git_vector_clear +#define git_pqueue_size git_vector_length +#define git_pqueue_get git_vector_get /** - * return the size of the queue. - * @param q the queue - */ -size_t git_pqueue_size(git_pqueue *q); - - -/** - * insert an item into the queue. - * @param q the queue - * @param d the item - * @return 0 on success - */ -int git_pqueue_insert(git_pqueue *q, void *d); - - -/** - * pop the highest-ranking item from the queue. - * @param q the queue - * @return NULL on error, otherwise the entry + * Insert a new item into the queue + * + * @param pq The priority queue + * @param item Pointer to the item data + * @return 0 on success, <0 on failure */ -void *git_pqueue_pop(git_pqueue *q); - +extern int git_pqueue_insert(git_pqueue *pq, void *item); /** - * access highest-ranking item without removing it. - * @param q the queue - * @return NULL on error, otherwise the entry + * Remove the top item in the priority queue + * + * @param pq The priority queue + * @return item from heap on success, NULL if queue is empty */ -void *git_pqueue_peek(git_pqueue *q); - -#endif /* PQUEUE_H */ -/** @} */ +extern void *git_pqueue_pop(git_pqueue *pq); +#endif diff --git a/src/repository.c b/src/repository.c index 2c1b60266..44d0f0b7d 100644 --- a/src/repository.c +++ b/src/repository.c @@ -1716,7 +1716,7 @@ cleanup: return error; } -int git_repository_message(git_buf *out, git_repository *repo) +int git_repository_message(git_buf *out, git_repository *repo) { git_buf path = GIT_BUF_INIT; struct stat st; @@ -1731,10 +1731,10 @@ int git_repository_message(git_buf *out, git_repository *repo) if (errno == ENOENT) error = GIT_ENOTFOUND; giterr_set(GITERR_OS, "Could not access message file"); + } else { + error = git_futils_readbuffer(out, git_buf_cstr(&path)); } - error = git_futils_readbuffer(out, git_buf_cstr(&path)); - git_buf_free(&path); return error; diff --git a/src/revparse.c b/src/revparse.c index 5cce3be63..60872e187 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -490,8 +490,7 @@ static int handle_grep_syntax(git_object **out, git_repository *repo, const git_ git_revwalk_sorting(walk, GIT_SORT_TIME); if (spec_oid == NULL) { - // TODO: @carlosmn: The glob should be refs/* but this makes git_revwalk_next() fails - if ((error = git_revwalk_push_glob(walk, GIT_REFS_HEADS_DIR "*")) < 0) + if ((error = git_revwalk_push_glob(walk, "refs/*")) < 0) goto cleanup; } else if ((error = git_revwalk_push(walk, spec_oid)) < 0) goto cleanup; diff --git a/src/revwalk.c b/src/revwalk.c index c0a053211..753911246 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -110,25 +110,34 @@ static int process_commit_parents(git_revwalk *walk, git_commit_list_node *commi return error; } -static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) +static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting, int from_glob) { + git_oid commit_id; int error; - git_object *obj; - git_otype type; + git_object *obj, *oobj; git_commit_list_node *commit; - if ((error = git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY)) < 0) + if ((error = git_object_lookup(&oobj, walk->repo, oid, GIT_OBJ_ANY)) < 0) return error; - type = git_object_type(obj); - git_object_free(obj); + error = git_object_peel(&obj, oobj, GIT_OBJ_COMMIT); + git_object_free(oobj); + + if (error == GIT_ENOTFOUND) { + /* If this comes from e.g. push_glob("tags"), ignore this */ + if (from_glob) + return 0; - if (type != GIT_OBJ_COMMIT) { - giterr_set(GITERR_INVALID, "Object is no commit object"); + giterr_set(GITERR_INVALID, "Object is not a committish"); return -1; } + if (error < 0) + return error; + + git_oid_cpy(&commit_id, git_object_id(obj)); + git_object_free(obj); - commit = git_revwalk__commit_lookup(walk, oid); + commit = git_revwalk__commit_lookup(walk, &commit_id); if (commit == NULL) return -1; /* error already reported by failed lookup */ @@ -146,24 +155,24 @@ static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting) int git_revwalk_push(git_revwalk *walk, const git_oid *oid) { assert(walk && oid); - return push_commit(walk, oid, 0); + return push_commit(walk, oid, 0, false); } int git_revwalk_hide(git_revwalk *walk, const git_oid *oid) { assert(walk && oid); - return push_commit(walk, oid, 1); + return push_commit(walk, oid, 1, false); } -static int push_ref(git_revwalk *walk, const char *refname, int hide) +static int push_ref(git_revwalk *walk, const char *refname, int hide, int from_glob) { git_oid oid; if (git_reference_name_to_id(&oid, walk->repo, refname) < 0) return -1; - return push_commit(walk, &oid, hide); + return push_commit(walk, &oid, hide, from_glob); } struct push_cb_data { @@ -171,17 +180,12 @@ struct push_cb_data { int hide; }; -static int push_glob_cb(const char *refname, void *data_) -{ - struct push_cb_data *data = (struct push_cb_data *)data_; - return push_ref(data->walk, refname, data->hide); -} - static int push_glob(git_revwalk *walk, const char *glob, int hide) { int error = 0; git_buf buf = GIT_BUF_INIT; - struct push_cb_data data; + git_reference *ref; + git_reference_iterator *iter; size_t wildcard; assert(walk && glob); @@ -199,12 +203,20 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide) if (!glob[wildcard]) git_buf_put(&buf, "/*", 2); - data.walk = walk; - data.hide = hide; + if ((error = git_reference_iterator_glob_new(&iter, walk->repo, buf.ptr)) < 0) + goto out; - error = git_reference_foreach_glob( - walk->repo, git_buf_cstr(&buf), push_glob_cb, &data); + while ((error = git_reference_next(&ref, iter)) == 0) { + error = push_ref(walk, git_reference_name(ref), hide, true); + git_reference_free(ref); + if (error < 0) + break; + } + git_reference_iterator_free(iter); + if (error == GIT_ITEROVER) + error = 0; +out: git_buf_free(&buf); return error; } @@ -224,19 +236,19 @@ int git_revwalk_hide_glob(git_revwalk *walk, const char *glob) int git_revwalk_push_head(git_revwalk *walk) { assert(walk); - return push_ref(walk, GIT_HEAD_FILE, 0); + return push_ref(walk, GIT_HEAD_FILE, 0, false); } int git_revwalk_hide_head(git_revwalk *walk) { assert(walk); - return push_ref(walk, GIT_HEAD_FILE, 1); + return push_ref(walk, GIT_HEAD_FILE, 1, false); } int git_revwalk_push_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); - return push_ref(walk, refname, 0); + return push_ref(walk, refname, 0, false); } int git_revwalk_push_range(git_revwalk *walk, const char *range) @@ -253,10 +265,10 @@ int git_revwalk_push_range(git_revwalk *walk, const char *range) return GIT_EINVALIDSPEC; } - if ((error = push_commit(walk, git_object_id(revspec.from), 1))) + if ((error = push_commit(walk, git_object_id(revspec.from), 1, false))) goto out; - error = push_commit(walk, git_object_id(revspec.to), 0); + error = push_commit(walk, git_object_id(revspec.to), 0, false); out: git_object_free(revspec.from); @@ -267,7 +279,7 @@ out: int git_revwalk_hide_ref(git_revwalk *walk, const char *refname) { assert(walk && refname); - return push_ref(walk, refname, 1); + return push_ref(walk, refname, 1, false); } static int revwalk_enqueue_timesort(git_revwalk *walk, git_commit_list_node *commit) @@ -439,7 +451,8 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) walk->commits = git_oidmap_alloc(); GITERR_CHECK_ALLOC(walk->commits); - if (git_pqueue_init(&walk->iterator_time, 8, git_commit_list_time_cmp) < 0 || + if (git_pqueue_init( + &walk->iterator_time, 0, 8, git_commit_list_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) diff --git a/src/sortedcache.c b/src/sortedcache.c index 466e55dbe..13f0921f1 100644 --- a/src/sortedcache.c +++ b/src/sortedcache.c @@ -321,7 +321,7 @@ size_t git_sortedcache_entrycount(const git_sortedcache *sc) void *git_sortedcache_entry(git_sortedcache *sc, size_t pos) { /* make sure the items are sorted so this gets the correct item */ - if (!sc->items.sorted) + if (!git_vector_is_sorted(&sc->items)) git_vector_sort(&sc->items); return git_vector_get(&sc->items, pos); diff --git a/src/strnlen.h b/src/strnlen.h new file mode 100644 index 000000000..007da2e55 --- /dev/null +++ b/src/strnlen.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#ifndef INCLUDE_strlen_h__ +#define INCLUDE_strlen_h__ + +#if defined(__MINGW32__) || defined(__sun) || defined(__APPLE__) +# define NO_STRNLEN +#endif + +#ifdef NO_STRNLEN +GIT_INLINE(size_t) p_strnlen(const char *s, size_t maxlen) { + const char *end = memchr(s, 0, maxlen); + return end ? (size_t)(end - s) : maxlen; +} +#else +# define p_strnlen strnlen +#endif + +#endif diff --git a/src/tree.c b/src/tree.c index 877a3fcee..94f779eca 100644 --- a/src/tree.c +++ b/src/tree.c @@ -283,7 +283,8 @@ static const git_tree_entry *entry_fromname( { size_t idx; - assert(tree->entries.sorted); /* be safe when we cast away constness */ + /* be safe when we cast away constness - i.e. don't trigger a sort */ + assert(git_vector_is_sorted(&tree->entries)); if (tree_key_search(&idx, (git_vector *)&tree->entries, name, name_len) < 0) return NULL; @@ -333,7 +334,8 @@ int git_tree__prefix_position(const git_tree *tree, const char *path) ksearch.filename = path; ksearch.filename_len = strlen(path); - assert(tree->entries.sorted); /* be safe when we cast away constness */ + /* be safe when we cast away constness - i.e. don't trigger a sort */ + assert(git_vector_is_sorted(&tree->entries)); /* Find tree entry with appropriate prefix */ git_vector_bsearch2( diff --git a/src/util.h b/src/util.h index f9de909e9..e378786d9 100644 --- a/src/util.h +++ b/src/util.h @@ -8,6 +8,7 @@ #define INCLUDE_util_h__ #include "common.h" +#include "strnlen.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #define bitsizeof(x) (CHAR_BIT * sizeof(x)) @@ -50,8 +51,7 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n) size_t length = 0; char *ptr; - while (length < n && str[length]) - ++length; + length = p_strnlen(str, n); ptr = (char*)git__malloc(length + 1); diff --git a/src/vector.c b/src/vector.c index f0c2f06c2..e5d8919d3 100644 --- a/src/vector.c +++ b/src/vector.c @@ -56,7 +56,9 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp) v->_alloc_size = src->length; v->_cmp = cmp; v->length = src->length; - v->sorted = src->sorted && cmp == src->_cmp; + v->flags = src->flags; + if (cmp != src->_cmp) + git_vector_set_sorted(v, 0); v->contents = git__malloc(bytes); GITERR_CHECK_ALLOC(v->contents); @@ -97,7 +99,7 @@ int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp) v->_alloc_size = 0; v->_cmp = cmp; v->length = 0; - v->sorted = 1; + v->flags = GIT_VECTOR_SORTED; v->contents = NULL; return resize_vector(v, max(initial_size, MIN_ALLOCSIZE)); @@ -128,7 +130,8 @@ int git_vector_insert(git_vector *v, void *element) return -1; v->contents[v->length++] = element; - v->sorted = 0; + + git_vector_set_sorted(v, v->length <= 1); return 0; } @@ -141,7 +144,7 @@ int git_vector_insert_sorted( assert(v && v->_cmp); - if (!v->sorted) + if (!git_vector_is_sorted(v)) git_vector_sort(v); if (v->length >= v->_alloc_size && @@ -171,11 +174,11 @@ void git_vector_sort(git_vector *v) { assert(v); - if (v->sorted || !v->_cmp) + if (git_vector_is_sorted(v) || !v->_cmp) return; git__tsort(v->contents, v->length, v->_cmp); - v->sorted = 1; + git_vector_set_sorted(v, 1); } int git_vector_bsearch2( @@ -291,7 +294,7 @@ void git_vector_clear(git_vector *v) { assert(v); v->length = 0; - v->sorted = 1; + git_vector_set_sorted(v, 1); } void git_vector_swap(git_vector *a, git_vector *b) diff --git a/src/vector.h b/src/vector.h index d318463c6..f8256853b 100644 --- a/src/vector.h +++ b/src/vector.h @@ -11,12 +11,17 @@ typedef int (*git_vector_cmp)(const void *, const void *); +enum { + GIT_VECTOR_SORTED = (1u << 0), + GIT_VECTOR_FLAG_MAX = (1u << 1), +}; + typedef struct git_vector { size_t _alloc_size; git_vector_cmp _cmp; void **contents; size_t length; - int sorted; + uint32_t flags; } git_vector; #define GIT_VECTOR_INIT {0} @@ -86,12 +91,20 @@ void git_vector_remove_matching( int git_vector_resize_to(git_vector *v, size_t new_length); int git_vector_set(void **old, git_vector *v, size_t position, void *value); +/** Check if vector is sorted */ +#define git_vector_is_sorted(V) (((V)->flags & GIT_VECTOR_SORTED) != 0) + +/** Directly set sorted state of vector */ +#define git_vector_set_sorted(V,S) do { \ + (V)->flags = (S) ? ((V)->flags | GIT_VECTOR_SORTED) : \ + ((V)->flags & ~GIT_VECTOR_SORTED); } while (0) + /** Set the comparison function used for sorting the vector */ GIT_INLINE(void) git_vector_set_cmp(git_vector *v, git_vector_cmp cmp) { if (cmp != v->_cmp) { v->_cmp = cmp; - v->sorted = 0; + git_vector_set_sorted(v, 0); } } diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index d4dbfbab9..a96385f10 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -8,68 +8,6 @@ #include "common.h" #include "utf-conv.h" -#define U16_LEAD(c) (wchar_t)(((c)>>10)+0xd7c0) -#define U16_TRAIL(c) (wchar_t)(((c)&0x3ff)|0xdc00) - -#if 0 -void git__utf8_to_16(wchar_t *dest, size_t length, const char *src) -{ - wchar_t *pDest = dest; - uint32_t ch; - const uint8_t* pSrc = (uint8_t*) src; - - assert(dest && src && length); - - length--; - - while(*pSrc && length > 0) { - ch = *pSrc++; - length--; - - if(ch < 0xc0) { - /* - * ASCII, or a trail byte in lead position which is treated like - * a single-byte sequence for better character boundary - * resynchronization after illegal sequences. - */ - *pDest++ = (wchar_t)ch; - continue; - } else if(ch < 0xe0) { /* U+0080..U+07FF */ - if (pSrc[0]) { - /* 0x3080 = (0xc0 << 6) + 0x80 */ - *pDest++ = (wchar_t)((ch << 6) + *pSrc++ - 0x3080); - continue; - } - } else if(ch < 0xf0) { /* U+0800..U+FFFF */ - if (pSrc[0] && pSrc[1]) { - /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */ - /* 0x2080 = (0x80 << 6) + 0x80 */ - ch = (ch << 12) + (*pSrc++ << 6); - *pDest++ = (wchar_t)(ch + *pSrc++ - 0x2080); - continue; - } - } else /* f0..f4 */ { /* U+10000..U+10FFFF */ - if (length >= 1 && pSrc[0] && pSrc[1] && pSrc[2]) { - /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */ - ch = (ch << 18) + (*pSrc++ << 12); - ch += *pSrc++ << 6; - ch += *pSrc++ - 0x3c82080; - *(pDest++) = U16_LEAD(ch); - *(pDest++) = U16_TRAIL(ch); - length--; /* two bytes for this character */ - continue; - } - } - - /* truncated character at the end */ - *pDest++ = 0xfffd; - break; - } - - *pDest++ = 0x0; -} -#endif - int git__utf8_to_16(wchar_t * dest, size_t dest_size, const char *src) { return MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, (int)dest_size); diff --git a/tests/core/pqueue.c b/tests/core/pqueue.c new file mode 100644 index 000000000..d91dbb0cd --- /dev/null +++ b/tests/core/pqueue.c @@ -0,0 +1,97 @@ +#include "clar_libgit2.h" +#include "pqueue.h" + +static int cmp_ints(const void *v1, const void *v2) +{ + int i1 = *(int *)v1, i2 = *(int *)v2; + return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0; +} + +void test_core_pqueue__items_are_put_in_order(void) +{ + git_pqueue pq; + int i, vals[20]; + + cl_git_pass(git_pqueue_init(&pq, 0, 20, cmp_ints)); + + for (i = 0; i < 20; ++i) { + if (i < 10) + vals[i] = 10 - i; /* 10 down to 1 */ + else + vals[i] = i + 1; /* 11 up to 20 */ + + cl_git_pass(git_pqueue_insert(&pq, &vals[i])); + } + + cl_assert_equal_i(20, git_pqueue_size(&pq)); + + for (i = 1; i <= 20; ++i) { + void *p = git_pqueue_pop(&pq); + cl_assert(p); + cl_assert_equal_i(i, *(int *)p); + } + + cl_assert_equal_i(0, git_pqueue_size(&pq)); + + git_pqueue_free(&pq); +} + +void test_core_pqueue__interleave_inserts_and_pops(void) +{ + git_pqueue pq; + int chunk, v, i, vals[200]; + + cl_git_pass(git_pqueue_init(&pq, 0, 20, cmp_ints)); + + for (v = 0, chunk = 20; chunk <= 200; chunk += 20) { + /* push the next 20 */ + for (; v < chunk; ++v) { + vals[v] = (v & 1) ? 200 - v : v; + cl_git_pass(git_pqueue_insert(&pq, &vals[v])); + } + + /* pop the lowest 10 */ + for (i = 0; i < 10; ++i) + (void)git_pqueue_pop(&pq); + } + + cl_assert_equal_i(100, git_pqueue_size(&pq)); + + /* at this point, we've popped 0-99 */ + + for (v = 100; v < 200; ++v) { + void *p = git_pqueue_pop(&pq); + cl_assert(p); + cl_assert_equal_i(v, *(int *)p); + } + + cl_assert_equal_i(0, git_pqueue_size(&pq)); + + git_pqueue_free(&pq); +} + +void test_core_pqueue__max_heap_size(void) +{ + git_pqueue pq; + int i, vals[100]; + + cl_git_pass(git_pqueue_init(&pq, GIT_PQUEUE_FIXED_SIZE, 50, cmp_ints)); + + for (i = 0; i < 100; ++i) { + vals[i] = (i & 1) ? 100 - i : i; + cl_git_pass(git_pqueue_insert(&pq, &vals[i])); + } + + cl_assert_equal_i(50, git_pqueue_size(&pq)); + + for (i = 50; i < 100; ++i) { + void *p = git_pqueue_pop(&pq); + cl_assert(p); + cl_assert_equal_i(i, *(int *)p); + } + + cl_assert_equal_i(0, git_pqueue_size(&pq)); + + git_pqueue_free(&pq); + +} diff --git a/tests/index/tests.c b/tests/index/tests.c index bd90bc557..6e28af1f7 100644 --- a/tests/index/tests.c +++ b/tests/index/tests.c @@ -80,7 +80,7 @@ void test_index_tests__empty_index(void) cl_assert(index->on_disk == 0); cl_assert(git_index_entrycount(index) == 0); - cl_assert(index->entries.sorted); + cl_assert(git_vector_is_sorted(&index->entries)); git_index_free(index); } @@ -95,7 +95,7 @@ void test_index_tests__default_test_index(void) cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count); - cl_assert(index->entries.sorted); + cl_assert(git_vector_is_sorted(&index->entries)); entries = (git_index_entry **)index->entries.contents; @@ -118,7 +118,7 @@ void test_index_tests__gitgit_index(void) cl_assert(index->on_disk); cl_assert(git_index_entrycount(index) == index_entry_count_2); - cl_assert(index->entries.sorted); + cl_assert(git_vector_is_sorted(&index->entries)); cl_assert(index->tree != NULL); git_index_free(index); @@ -195,7 +195,7 @@ void test_index_tests__sort1(void) cl_git_pass(git_index_open(&index, "fake-index")); /* FIXME: this test is slightly dumb */ - cl_assert(index->entries.sorted); + cl_assert(git_vector_is_sorted(&index->entries)); git_index_free(index); } @@ -543,3 +543,37 @@ void test_index_tests__corrupted_extension(void) cl_git_fail_with(git_index_open(&index, TEST_INDEXBAD_PATH), GIT_ERROR); } + +static void assert_index_is_sorted(git_index *index) +{ + git_vector *entries = &index->entries; + size_t i; + + cl_assert(git_vector_is_sorted(entries)); + + for (i = 1; i < git_vector_length(entries); ++i) { + git_index_entry *prev = git_vector_get(entries, i - 1); + git_index_entry *curr = git_vector_get(entries, i); + cl_assert(index->entries._cmp(prev, curr) <= 0); + } +} + +void test_index_tests__reload_while_ignoring_case(void) +{ + git_index *index; + unsigned int caps; + + cl_git_pass(git_index_open(&index, TEST_INDEX_PATH)); + assert_index_is_sorted(index); + + caps = git_index_caps(index); + cl_git_pass(git_index_set_caps(index, caps &= ~GIT_INDEXCAP_IGNORE_CASE)); + cl_git_pass(git_index_read(index, true)); + assert_index_is_sorted(index); + + cl_git_pass(git_index_set_caps(index, caps | GIT_INDEXCAP_IGNORE_CASE)); + cl_git_pass(git_index_read(index, true)); + assert_index_is_sorted(index); + + git_index_free(index); +} diff --git a/tests/object/tree/write.c b/tests/object/tree/write.c index 3bea0ed4d..45356e807 100644 --- a/tests/object/tree/write.c +++ b/tests/object/tree/write.c @@ -9,7 +9,7 @@ static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488"; static git_repository *g_repo; -// Fixture setup and teardown +/* Fixture setup and teardown */ void test_object_tree_write__initialize(void) { g_repo = cl_git_sandbox_init("testrepo"); @@ -22,7 +22,7 @@ void test_object_tree_write__cleanup(void) void test_object_tree_write__from_memory(void) { - // write a tree from a memory + /* write a tree from a memory */ git_treebuilder *builder; git_tree *tree; git_oid id, bid, rid, id2; @@ -31,7 +31,9 @@ void test_object_tree_write__from_memory(void) git_oid_fromstr(&id2, second_tree); git_oid_fromstr(&bid, blob_oid); - //create a second tree from first tree using `git_treebuilder_insert` on REPOSITORY_FOLDER. + /* create a second tree from first tree using `git_treebuilder_insert` + * on REPOSITORY_FOLDER. + */ cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_treebuilder_create(&builder, tree)); @@ -61,7 +63,7 @@ void test_object_tree_write__from_memory(void) void test_object_tree_write__subtree(void) { - // write a hierarchical tree from a memory + /* write a hierarchical tree from a memory */ git_treebuilder *builder; git_tree *tree; git_oid id, bid, subtree_id, id2, id3; @@ -72,25 +74,25 @@ void test_object_tree_write__subtree(void) git_oid_fromstr(&id3, third_tree); git_oid_fromstr(&bid, blob_oid); - //create subtree + /* create subtree */ cl_git_pass(git_treebuilder_create(&builder, NULL)); cl_git_pass(git_treebuilder_insert( - NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); //-V536 + NULL, builder, "new.txt", &bid, GIT_FILEMODE_BLOB)); /* -V536 */ cl_git_pass(git_treebuilder_write(&subtree_id, g_repo, builder)); git_treebuilder_free(builder); - // create parent tree + /* create parent tree */ cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); cl_git_pass(git_treebuilder_create(&builder, tree)); cl_git_pass(git_treebuilder_insert( - NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); //-V536 + NULL, builder, "new", &subtree_id, GIT_FILEMODE_TREE)); /* -V536 */ cl_git_pass(git_treebuilder_write(&id_hiearar, g_repo, builder)); git_treebuilder_free(builder); git_tree_free(tree); cl_assert(git_oid_cmp(&id_hiearar, &id3) == 0); - // check data is correct + /* check data is correct */ cl_git_pass(git_tree_lookup(&tree, g_repo, &id_hiearar)); cl_assert(2 == git_tree_entrycount(tree)); git_tree_free(tree); @@ -314,3 +316,83 @@ void test_object_tree_write__filtering(void) git_tree_free(tree); } + +void test_object_tree_write__cruel_paths(void) +{ + static const char *the_paths[] = { + "C:\\", + " : * ? \" \n < > |", + "a\\b", + "\\\\b\a", + ":\\", + "COM1", + "foo.aux", + REP1024("1234"), /* 4096 char string */ + REP1024("12345678"), /* 8192 char string */ + "\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD", /* Ūnĭcōde̽ */ + NULL + }; + git_treebuilder *builder; + git_tree *tree; + git_oid id, bid, subid; + const char **scan; + int count = 0, i, j; + git_tree_entry *te; + + git_oid_fromstr(&bid, blob_oid); + + /* create tree */ + cl_git_pass(git_treebuilder_create(&builder, NULL)); + for (scan = the_paths; *scan; ++scan) { + cl_git_pass(git_treebuilder_insert( + NULL, builder, *scan, &bid, GIT_FILEMODE_BLOB)); + count++; + } + cl_git_pass(git_treebuilder_write(&id, g_repo, builder)); + git_treebuilder_free(builder); + + /* check data is correct */ + cl_git_pass(git_tree_lookup(&tree, g_repo, &id)); + + cl_assert_equal_i(count, git_tree_entrycount(tree)); + + for (scan = the_paths; *scan; ++scan) { + const git_tree_entry *cte = git_tree_entry_byname(tree, *scan); + cl_assert(cte != NULL); + cl_assert_equal_s(*scan, git_tree_entry_name(cte)); + } + for (scan = the_paths; *scan; ++scan) { + cl_git_pass(git_tree_entry_bypath(&te, tree, *scan)); + cl_assert_equal_s(*scan, git_tree_entry_name(te)); + git_tree_entry_free(te); + } + + git_tree_free(tree); + + /* let's try longer paths */ + cl_git_pass(git_treebuilder_create(&builder, NULL)); + for (scan = the_paths; *scan; ++scan) { + cl_git_pass(git_treebuilder_insert( + NULL, builder, *scan, &id, GIT_FILEMODE_TREE)); + } + cl_git_pass(git_treebuilder_write(&subid, g_repo, builder)); + git_treebuilder_free(builder); + + /* check data is correct */ + cl_git_pass(git_tree_lookup(&tree, g_repo, &subid)); + + cl_assert_equal_i(count, git_tree_entrycount(tree)); + + for (i = 0; i < count; ++i) { + for (j = 0; j < count; ++j) { + git_buf b = GIT_BUF_INIT; + cl_git_pass(git_buf_joinpath(&b, the_paths[i], the_paths[j])); + cl_git_pass(git_tree_entry_bypath(&te, tree, b.ptr)); + cl_assert_equal_s(the_paths[j], git_tree_entry_name(te)); + git_tree_entry_free(te); + git_buf_free(&b); + } + } + + git_tree_free(tree); +} diff --git a/tests/repo/head.c b/tests/repo/head.c index 8ea9a0f42..127176d12 100644 --- a/tests/repo/head.c +++ b/tests/repo/head.c @@ -200,7 +200,7 @@ static void test_reflog(git_repository *repo, size_t idx, const char *email, const char *message) { git_reflog *log; - git_reflog_entry *entry; + const git_reflog_entry *entry; cl_git_pass(git_reflog_read(&log, repo, "HEAD")); entry = git_reflog_entry_byindex(log, idx); diff --git a/tests/repo/message.c b/tests/repo/message.c index 57e8e5f4d..87574590b 100644 --- a/tests/repo/message.c +++ b/tests/repo/message.c @@ -4,38 +4,36 @@ #include "posix.h" static git_repository *_repo; -static git_buf _path; -static git_buf _actual; void test_repo_message__initialize(void) { - _repo = cl_git_sandbox_init("testrepo.git"); - git_buf_init(&_actual, 0); + _repo = cl_git_sandbox_init("testrepo.git"); } void test_repo_message__cleanup(void) { - cl_git_sandbox_cleanup(); - git_buf_free(&_path); - git_buf_free(&_actual); + cl_git_sandbox_cleanup(); } void test_repo_message__none(void) { - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&_actual, _repo)); + git_buf actual = GIT_BUF_INIT; + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&actual, _repo)); } void test_repo_message__message(void) { + git_buf path = GIT_BUF_INIT, actual = GIT_BUF_INIT; const char expected[] = "Test\n\nThis is a test of the emergency broadcast system\n"; - cl_git_pass(git_buf_joinpath(&_path, git_repository_path(_repo), "MERGE_MSG")); - cl_git_mkfile(git_buf_cstr(&_path), expected); + cl_git_pass(git_buf_joinpath(&path, git_repository_path(_repo), "MERGE_MSG")); + cl_git_mkfile(git_buf_cstr(&path), expected); - cl_git_pass(git_repository_message(&_actual, _repo)); - cl_assert_equal_s(expected, _actual); - git_buf_free(&_actual); + cl_git_pass(git_repository_message(&actual, _repo)); + cl_assert_equal_s(expected, git_buf_cstr(&actual)); + git_buf_free(&actual); - cl_git_pass(p_unlink(git_buf_cstr(&_path))); - cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&_actual, _repo)); + cl_git_pass(p_unlink(git_buf_cstr(&path))); + cl_assert_equal_i(GIT_ENOTFOUND, git_repository_message(&actual, _repo)); + git_buf_free(&path); } diff --git a/tests/revwalk/basic.c b/tests/revwalk/basic.c index 6d55aed54..9fe8a350b 100644 --- a/tests/revwalk/basic.c +++ b/tests/revwalk/basic.c @@ -252,3 +252,41 @@ void test_revwalk_basic__push_range(void) cl_git_pass(git_revwalk_push_range(_walk, "9fd738e~2..9fd738e")); cl_git_pass(test_walk_only(_walk, commit_sorting_segment, 1)); } + +void test_revwalk_basic__push_mixed(void) +{ + git_oid oid; + int i = 0; + + revwalk_basic_setup_walk(NULL); + + git_revwalk_reset(_walk); + git_revwalk_sorting(_walk, 0); + cl_git_pass(git_revwalk_push_glob(_walk, "tags")); + + while (git_revwalk_next(&oid, _walk) == 0) { + i++; + } + + /* git rev-list --count --glob=tags #=> 9 */ + cl_assert_equal_i(9, i); +} + +void test_revwalk_basic__push_all(void) +{ + git_oid oid; + int i = 0; + + revwalk_basic_setup_walk(NULL); + + git_revwalk_reset(_walk); + git_revwalk_sorting(_walk, 0); + cl_git_pass(git_revwalk_push_glob(_walk, "*")); + + while (git_revwalk_next(&oid, _walk) == 0) { + i++; + } + + /* git rev-list --count --all #=> 15 */ + cl_assert_equal_i(15, i); +} |