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