]> git.proxmox.com Git - libgit2.git/blame - src/vector.c
Vector improvements and their fallout
[libgit2.git] / src / vector.c
CommitLineData
c4034e63 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
c4034e63 3 *
bb742ede
VM
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.
c4034e63
VM
6 */
7
8#include "common.h"
9#include "repository.h"
10#include "vector.h"
11
11d9f6b3
PK
12/* In elements, not bytes */
13#define MIN_ALLOCSIZE 8
c4034e63 14
11d9f6b3 15GIT_INLINE(size_t) compute_new_size(git_vector *v)
c4034e63 16{
11d9f6b3
PK
17 size_t new_size = v->_alloc_size;
18
19 /* Use a resize factor of 1.5, which is quick to compute using integer
20 * instructions and less than the golden ratio (1.618...) */
21 if (new_size < MIN_ALLOCSIZE)
22 new_size = MIN_ALLOCSIZE;
23 else if (new_size <= SIZE_MAX / 3)
24 new_size = new_size * 3 / 2 + 1;
25 else
26 new_size = SIZE_MAX;
27
28 return new_size;
29}
c4034e63 30
11d9f6b3
PK
31GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size)
32{
33 size_t new_bytes = new_size * sizeof(void *);
34 void *new_contents;
35
36 /* Check for overflow */
37 if (new_bytes / sizeof(void *) != new_size)
38 GITERR_CHECK_ALLOC(NULL);
39
40 new_contents = git__realloc(v->contents, new_bytes);
41 GITERR_CHECK_ALLOC(new_contents);
42
43 v->_alloc_size = new_size;
44 v->contents = new_contents;
c4034e63 45
ae9e29fd 46 return 0;
c4034e63
VM
47}
48
16248ee2 49int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
ec40b7f9 50{
11d9f6b3
PK
51 size_t bytes;
52
ec40b7f9
PK
53 assert(v && src);
54
11d9f6b3
PK
55 bytes = src->length * sizeof(void *);
56
ec40b7f9
PK
57 v->_alloc_size = src->length;
58 v->_cmp = cmp;
59 v->length = src->length;
60 v->sorted = src->sorted && cmp == src->_cmp;
11d9f6b3 61 v->contents = git__malloc(bytes);
ec40b7f9
PK
62 GITERR_CHECK_ALLOC(v->contents);
63
11d9f6b3 64 memcpy(v->contents, src->contents, bytes);
ec40b7f9
PK
65
66 return 0;
67}
68
c4034e63
VM
69void git_vector_free(git_vector *v)
70{
71 assert(v);
ee1f0b1a 72
3286c408 73 git__free(v->contents);
ee1f0b1a
RB
74 v->contents = NULL;
75
76 v->length = 0;
77 v->_alloc_size = 0;
c4034e63
VM
78}
79
b8457baa 80int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
c4034e63
VM
81{
82 assert(v);
83
11d9f6b3 84 v->_alloc_size = 0;
c4034e63 85 v->_cmp = cmp;
c4034e63 86 v->length = 0;
86d7e1ca 87 v->sorted = 1;
11d9f6b3 88 v->contents = NULL;
c4034e63 89
11d9f6b3 90 return resize_vector(v, max(initial_size, MIN_ALLOCSIZE));
c4034e63
VM
91}
92
93int git_vector_insert(git_vector *v, void *element)
94{
95 assert(v);
96
ae9e29fd 97 if (v->length >= v->_alloc_size &&
11d9f6b3 98 resize_vector(v, compute_new_size(v)) < 0)
ae9e29fd 99 return -1;
c4034e63
VM
100
101 v->contents[v->length++] = element;
86d7e1ca 102 v->sorted = 0;
c4034e63 103
ae9e29fd 104 return 0;
c4034e63
VM
105}
106
ae9e29fd
RB
107int git_vector_insert_sorted(
108 git_vector *v, void *element, int (*on_dup)(void **old, void *new))
bd370b14 109{
ae9e29fd 110 int result;
bd370b14
RB
111 size_t pos;
112
113 assert(v && v->_cmp);
114
115 if (!v->sorted)
116 git_vector_sort(v);
117
ae9e29fd 118 if (v->length >= v->_alloc_size &&
11d9f6b3 119 resize_vector(v, compute_new_size(v)) < 0)
ae9e29fd 120 return -1;
bd370b14 121
ae9e29fd
RB
122 /* If we find the element and have a duplicate handler callback,
123 * invoke it. If it returns non-zero, then cancel insert, otherwise
bd370b14
RB
124 * proceed with normal insert.
125 */
11d9f6b3
PK
126 if (!git__bsearch(v->contents, v->length, element, v->_cmp, &pos) &&
127 on_dup && (result = on_dup(&v->contents[pos], element)) < 0)
ae9e29fd 128 return result;
bd370b14
RB
129
130 /* shift elements to the right */
11d9f6b3 131 if (pos < v->length)
bd370b14
RB
132 memmove(v->contents + pos + 1, v->contents + pos,
133 (v->length - pos) * sizeof(void *));
bd370b14
RB
134
135 v->contents[pos] = element;
136 v->length++;
11d9f6b3 137
ae9e29fd 138 return 0;
bd370b14
RB
139}
140
c4034e63
VM
141void git_vector_sort(git_vector *v)
142{
143 assert(v);
144
11d9f6b3 145 if (v->sorted || !v->_cmp)
86d7e1ca
VM
146 return;
147
de18f276 148 git__tsort(v->contents, v->length, v->_cmp);
86d7e1ca 149 v->sorted = 1;
c4034e63
VM
150}
151
11d9f6b3 152int git_vector_bsearch2(
16248ee2 153 size_t *at_pos,
41a82592
RB
154 git_vector *v,
155 git_vector_cmp key_lookup,
156 const void *key)
c4034e63 157{
86d7e1ca
VM
158 assert(v && key && key_lookup);
159
48c27f86 160 /* need comparison function to sort the vector */
11d9f6b3
PK
161 if (!v->_cmp)
162 return -1;
48c27f86 163
86d7e1ca
VM
164 git_vector_sort(v);
165
11d9f6b3 166 return git__bsearch(v->contents, v->length, key, key_lookup, at_pos);
86d7e1ca
VM
167}
168
41a82592 169int git_vector_search2(
11d9f6b3 170 size_t *at_pos, const git_vector *v, git_vector_cmp key_lookup, const void *key)
86d7e1ca 171{
16248ee2 172 size_t i;
86d7e1ca
VM
173
174 assert(v && key && key_lookup);
175
176 for (i = 0; i < v->length; ++i) {
11d9f6b3
PK
177 if (key_lookup(key, v->contents[i]) == 0) {
178 if (at_pos)
179 *at_pos = i;
180
181 return 0;
182 }
86d7e1ca
VM
183 }
184
ae9e29fd 185 return GIT_ENOTFOUND;
86d7e1ca
VM
186}
187
48c27f86 188static int strict_comparison(const void *a, const void *b)
86d7e1ca 189{
3c41c635 190 return (a == b) ? 0 : -1;
48c27f86 191}
c4034e63 192
11d9f6b3 193int git_vector_search(size_t *at_pos, const git_vector *v, const void *entry)
48c27f86 194{
11d9f6b3 195 return git_vector_search2(at_pos, v, v->_cmp ? v->_cmp : strict_comparison, entry);
86d7e1ca
VM
196}
197
16248ee2 198int git_vector_remove(git_vector *v, size_t idx)
c4034e63 199{
11d9f6b3 200 size_t shift_count;
c4034e63
VM
201
202 assert(v);
203
11d9f6b3 204 if (idx >= v->length)
ae9e29fd 205 return GIT_ENOTFOUND;
c4034e63 206
11d9f6b3
PK
207 shift_count = v->length - idx - 1;
208
209 if (shift_count)
210 memmove(&v->contents[idx], &v->contents[idx + 1],
211 shift_count * sizeof(void *));
c4034e63
VM
212
213 v->length--;
ae9e29fd 214 return 0;
c4034e63
VM
215}
216
0534641d 217void git_vector_pop(git_vector *v)
b6c93aef 218{
0534641d
RB
219 if (v->length > 0)
220 v->length--;
b6c93aef
RB
221}
222
476c42ac
KS
223void git_vector_uniq(git_vector *v)
224{
225 git_vector_cmp cmp;
16248ee2 226 size_t i, j;
476c42ac
KS
227
228 if (v->length <= 1)
229 return;
230
231 git_vector_sort(v);
232 cmp = v->_cmp ? v->_cmp : strict_comparison;
233
234 for (i = 0, j = 1 ; j < v->length; ++j)
de18f276 235 if (!cmp(v->contents[i], v->contents[j]))
476c42ac
KS
236 v->contents[i] = v->contents[j];
237 else
238 v->contents[++i] = v->contents[j];
239
240 v->length -= j - i - 1;
241}
242
16248ee2
RB
243void git_vector_remove_matching(
244 git_vector *v, int (*match)(const git_vector *v, size_t idx))
f45ec1a0 245{
16248ee2 246 size_t i, j;
f45ec1a0
ET
247
248 for (i = 0, j = 0; j < v->length; ++j) {
249 v->contents[i] = v->contents[j];
250
251 if (!match(v, i))
252 i++;
253 }
254
255 v->length = i;
256}
257
c4034e63
VM
258void git_vector_clear(git_vector *v)
259{
260 assert(v);
261 v->length = 0;
86d7e1ca 262 v->sorted = 1;
c4034e63
VM
263}
264
74fa4bfa
RB
265void git_vector_swap(git_vector *a, git_vector *b)
266{
267 git_vector t;
268
11d9f6b3 269 assert(a && b);
c4034e63 270
11d9f6b3
PK
271 if (a != b) {
272 memcpy(&t, a, sizeof(t));
273 memcpy(a, b, sizeof(t));
274 memcpy(b, &t, sizeof(t));
275 }
74fa4bfa 276}
db106d01
RB
277
278int git_vector_resize_to(git_vector *v, size_t new_length)
279{
280 if (new_length <= v->length)
281 return 0;
282
11d9f6b3
PK
283 if (new_length > v->_alloc_size &&
284 resize_vector(v, new_length) < 0)
285 return -1;
db106d01
RB
286
287 memset(&v->contents[v->length], 0,
288 sizeof(void *) * (new_length - v->length));
289
290 v->length = new_length;
291
292 return 0;
293}
294
295int git_vector_set(void **old, git_vector *v, size_t position, void *value)
296{
297 if (git_vector_resize_to(v, position + 1) < 0)
298 return -1;
299
300 if (old != NULL)
301 *old = v->contents[position];
302
303 v->contents[position] = value;
304
305 return 0;
306}