File Coverage

deps/libgit2/src/libgit2/commit_list.c
Criterion Covered Total %
statement 76 105 72.3
branch 31 60 51.6
condition n/a
subroutine n/a
pod n/a
total 107 165 64.8


line stmt bran cond sub pod time code
1             /*
2             * Copyright (C) the libgit2 contributors. All rights reserved.
3             *
4             * This file is part of libgit2, distributed under the GNU GPL v2 with
5             * a Linking Exception. For full terms see the included COPYING file.
6             */
7              
8             #include "commit_list.h"
9              
10             #include "revwalk.h"
11             #include "pool.h"
12             #include "odb.h"
13             #include "commit.h"
14              
15 169           int git_commit_list_generation_cmp(const void *a, const void *b)
16             {
17 169           uint32_t generation_a = ((git_commit_list_node *) a)->generation;
18 169           uint32_t generation_b = ((git_commit_list_node *) b)->generation;
19              
20 169 50         if (!generation_a || !generation_b) {
    0          
21             /* Fall back to comparing by timestamps if at least one commit lacks a generation. */
22 169           return git_commit_list_time_cmp(a, b);
23             }
24              
25 0 0         if (generation_a < generation_b)
26 0           return 1;
27 0 0         if (generation_a > generation_b)
28 0           return -1;
29              
30 0           return 0;
31             }
32              
33 215           int git_commit_list_time_cmp(const void *a, const void *b)
34             {
35 215           int64_t time_a = ((git_commit_list_node *) a)->time;
36 215           int64_t time_b = ((git_commit_list_node *) b)->time;
37              
38 215 100         if (time_a < time_b)
39 14           return 1;
40 201 100         if (time_a > time_b)
41 17           return -1;
42              
43 184           return 0;
44             }
45              
46 292           git_commit_list *git_commit_list_insert(git_commit_list_node *item, git_commit_list **list_p)
47             {
48 292           git_commit_list *new_list = git__malloc(sizeof(git_commit_list));
49 292 50         if (new_list != NULL) {
50 292           new_list->item = item;
51 292           new_list->next = *list_p;
52             }
53 292           *list_p = new_list;
54 292           return new_list;
55             }
56              
57 87           git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_commit_list **list_p)
58             {
59 87           git_commit_list **pp = list_p;
60             git_commit_list *p;
61              
62 97 100         while ((p = *pp) != NULL) {
63 10 50         if (git_commit_list_time_cmp(p->item, item) > 0)
64 0           break;
65              
66 10           pp = &p->next;
67             }
68              
69 87           return git_commit_list_insert(item, pp);
70             }
71              
72 182           git_commit_list_node *git_commit_list_alloc_node(git_revwalk *walk)
73             {
74 182           return (git_commit_list_node *)git_pool_mallocz(&walk->commit_pool, 1);
75             }
76              
77 178           static git_commit_list_node **alloc_parents(
78             git_revwalk *walk, git_commit_list_node *commit, size_t n_parents)
79             {
80             size_t bytes;
81              
82 178 50         if (n_parents <= PARENTS_PER_COMMIT)
83 178           return (git_commit_list_node **)((char *)commit + sizeof(git_commit_list_node));
84              
85 0 0         if (git__multiply_sizet_overflow(&bytes, n_parents, sizeof(git_commit_list_node *)))
86 0           return NULL;
87              
88 178           return (git_commit_list_node **)git_pool_malloc(&walk->commit_pool, bytes);
89             }
90              
91              
92 424           void git_commit_list_free(git_commit_list **list_p)
93             {
94 424           git_commit_list *list = *list_p;
95              
96 424 100         if (list == NULL)
97 339           return;
98              
99 207 100         while (list) {
100 122           git_commit_list *temp = list;
101 122           list = temp->next;
102 122           git__free(temp);
103             }
104              
105 85           *list_p = NULL;
106             }
107              
108 191           git_commit_list_node *git_commit_list_pop(git_commit_list **stack)
109             {
110 191           git_commit_list *top = *stack;
111 191 100         git_commit_list_node *item = top ? top->item : NULL;
112              
113 191 100         if (top) {
114 170           *stack = top->next;
115 170           git__free(top);
116             }
117 191           return item;
118             }
119              
120 178           static int commit_quick_parse(
121             git_revwalk *walk,
122             git_commit_list_node *node,
123             git_odb_object *obj)
124             {
125             git_oid *parent_oid;
126             git_commit *commit;
127             size_t i;
128              
129 178           commit = git__calloc(1, sizeof(*commit));
130 178 50         GIT_ERROR_CHECK_ALLOC(commit);
131 178           commit->object.repo = walk->repo;
132              
133 178 50         if (git_commit__parse_ext(commit, obj, GIT_COMMIT_PARSE_QUICK) < 0) {
134 0           git__free(commit);
135 0           return -1;
136             }
137              
138 178 50         if (!git__is_uint16(git_array_size(commit->parent_ids))) {
139 0           git__free(commit);
140 0           git_error_set(GIT_ERROR_INVALID, "commit has more than 2^16 parents");
141 0           return -1;
142             }
143              
144 178           node->generation = 0;
145 178           node->time = commit->committer->when.time;
146 178           node->out_degree = (uint16_t) git_array_size(commit->parent_ids);
147 178           node->parents = alloc_parents(walk, node, node->out_degree);
148 178 50         GIT_ERROR_CHECK_ALLOC(node->parents);
149              
150 323 100         git_array_foreach(commit->parent_ids, i, parent_oid) {
    50          
151 145           node->parents[i] = git_revwalk__commit_lookup(walk, parent_oid);
152             }
153              
154 178           git_commit__free(commit);
155              
156 178           node->parsed = 1;
157              
158 178           return 0;
159             }
160              
161 293           int git_commit_list_parse(git_revwalk *walk, git_commit_list_node *commit)
162             {
163             git_odb_object *obj;
164 293           git_commit_graph_file *cgraph_file = NULL;
165             int error;
166              
167 293 100         if (commit->parsed)
168 114           return 0;
169              
170             /* Let's try to use the commit graph first. */
171 179           git_odb__get_commit_graph_file(&cgraph_file, walk->odb);
172 179 50         if (cgraph_file) {
173             git_commit_graph_entry e;
174              
175 0           error = git_commit_graph_entry_find(&e, cgraph_file, &commit->oid, GIT_OID_RAWSZ);
176 0 0         if (error == 0 && git__is_uint16(e.parent_count)) {
    0          
177             size_t i;
178 0           commit->generation = (uint32_t)e.generation;
179 0           commit->time = e.commit_time;
180 0           commit->out_degree = (uint16_t)e.parent_count;
181 0           commit->parents = alloc_parents(walk, commit, commit->out_degree);
182 0 0         GIT_ERROR_CHECK_ALLOC(commit->parents);
183              
184 0 0         for (i = 0; i < commit->out_degree; ++i) {
185             git_commit_graph_entry parent;
186 0           error = git_commit_graph_entry_parent(&parent, cgraph_file, &e, i);
187 0 0         if (error < 0)
188 0           return error;
189 0           commit->parents[i] = git_revwalk__commit_lookup(walk, &parent.sha1);
190             }
191 0           commit->parsed = 1;
192 0           return 0;
193             }
194             }
195              
196 179 100         if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0)
197 1           return error;
198              
199 178 50         if (obj->cached.type != GIT_OBJECT_COMMIT) {
200 0           git_error_set(GIT_ERROR_INVALID, "object is no commit object");
201 0           error = -1;
202             } else
203 178           error = commit_quick_parse(walk, commit, obj);
204              
205 178           git_odb_object_free(obj);
206 293           return error;
207             }
208