]> git.proxmox.com Git - libgit2.git/blame - src/vector.c
New upstream version 1.3.0+dfsg.1
[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
c4034e63 8#include "vector.h"
eae0bfdc 9
e564fc65 10#include "integer.h"
c4034e63 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;
590365db
PK
23 else if (new_size <= (SIZE_MAX / 3) * 2)
24 new_size += new_size / 2;
11d9f6b3
PK
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{
11d9f6b3
PK
33 void *new_contents;
34
6c7cee42
RD
35 if (new_size == 0)
36 return 0;
37
3603cb09 38 new_contents = git__reallocarray(v->contents, new_size, sizeof(void *));
ac3d33df 39 GIT_ERROR_CHECK_ALLOC(new_contents);
11d9f6b3
PK
40
41 v->_alloc_size = new_size;
42 v->contents = new_contents;
c4034e63 43
ae9e29fd 44 return 0;
c4034e63
VM
45}
46
d7d46cfb
VM
47int git_vector_size_hint(git_vector *v, size_t size_hint)
48{
49 if (v->_alloc_size >= size_hint)
50 return 0;
51 return resize_vector(v, size_hint);
52}
53
16248ee2 54int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
ec40b7f9 55{
c25aa7cd
PP
56 GIT_ASSERT_ARG(v);
57 GIT_ASSERT_ARG(src);
ec40b7f9 58
6c7cee42
RD
59 v->_alloc_size = 0;
60 v->contents = NULL;
aa78c9ba 61 v->_cmp = cmp ? cmp : src->_cmp;
ec40b7f9 62 v->length = src->length;
882c7742
RB
63 v->flags = src->flags;
64 if (cmp != src->_cmp)
65 git_vector_set_sorted(v, 0);
ec40b7f9 66
6c7cee42
RD
67 if (src->length) {
68 size_t bytes;
ac3d33df 69 GIT_ERROR_CHECK_ALLOC_MULTIPLY(&bytes, src->length, sizeof(void *));
6c7cee42 70 v->contents = git__malloc(bytes);
ac3d33df 71 GIT_ERROR_CHECK_ALLOC(v->contents);
6c7cee42
RD
72 v->_alloc_size = src->length;
73 memcpy(v->contents, src->contents, bytes);
74 }
ec40b7f9
PK
75
76 return 0;
77}
78
c4034e63
VM
79void git_vector_free(git_vector *v)
80{
c25aa7cd
PP
81 if (!v)
82 return;
ee1f0b1a 83
3286c408 84 git__free(v->contents);
ee1f0b1a
RB
85 v->contents = NULL;
86
87 v->length = 0;
88 v->_alloc_size = 0;
c4034e63
VM
89}
90
9cfce273 91void git_vector_free_deep(git_vector *v)
fcd324c6
RB
92{
93 size_t i;
94
c25aa7cd
PP
95 if (!v)
96 return;
fcd324c6
RB
97
98 for (i = 0; i < v->length; ++i) {
99 git__free(v->contents[i]);
100 v->contents[i] = NULL;
101 }
102
103 git_vector_free(v);
104}
105
b8457baa 106int git_vector_init(git_vector *v, size_t initial_size, git_vector_cmp cmp)
c4034e63 107{
c25aa7cd 108 GIT_ASSERT_ARG(v);
c4034e63 109
11d9f6b3 110 v->_alloc_size = 0;
c4034e63 111 v->_cmp = cmp;
c4034e63 112 v->length = 0;
882c7742 113 v->flags = GIT_VECTOR_SORTED;
11d9f6b3 114 v->contents = NULL;
c4034e63 115
11d9f6b3 116 return resize_vector(v, max(initial_size, MIN_ALLOCSIZE));
c4034e63
VM
117}
118
25e0b157
RB
119void **git_vector_detach(size_t *size, size_t *asize, git_vector *v)
120{
121 void **data = v->contents;
122
123 if (size)
124 *size = v->length;
125 if (asize)
126 *asize = v->_alloc_size;
127
128 v->_alloc_size = 0;
129 v->length = 0;
130 v->contents = NULL;
131
132 return data;
133}
134
c4034e63
VM
135int git_vector_insert(git_vector *v, void *element)
136{
c25aa7cd 137 GIT_ASSERT_ARG(v);
c4034e63 138
ae9e29fd 139 if (v->length >= v->_alloc_size &&
11d9f6b3 140 resize_vector(v, compute_new_size(v)) < 0)
ae9e29fd 141 return -1;
c4034e63
VM
142
143 v->contents[v->length++] = element;
882c7742
RB
144
145 git_vector_set_sorted(v, v->length <= 1);
c4034e63 146
ae9e29fd 147 return 0;
c4034e63
VM
148}
149
ae9e29fd
RB
150int git_vector_insert_sorted(
151 git_vector *v, void *element, int (*on_dup)(void **old, void *new))
bd370b14 152{
ae9e29fd 153 int result;
bd370b14
RB
154 size_t pos;
155
c25aa7cd
PP
156 GIT_ASSERT_ARG(v);
157 GIT_ASSERT(v->_cmp);
bd370b14 158
882c7742 159 if (!git_vector_is_sorted(v))
bd370b14
RB
160 git_vector_sort(v);
161
ae9e29fd 162 if (v->length >= v->_alloc_size &&
11d9f6b3 163 resize_vector(v, compute_new_size(v)) < 0)
ae9e29fd 164 return -1;
bd370b14 165
ae9e29fd
RB
166 /* If we find the element and have a duplicate handler callback,
167 * invoke it. If it returns non-zero, then cancel insert, otherwise
bd370b14
RB
168 * proceed with normal insert.
169 */
11d9f6b3
PK
170 if (!git__bsearch(v->contents, v->length, element, v->_cmp, &pos) &&
171 on_dup && (result = on_dup(&v->contents[pos], element)) < 0)
ae9e29fd 172 return result;
bd370b14
RB
173
174 /* shift elements to the right */
11d9f6b3 175 if (pos < v->length)
bd370b14
RB
176 memmove(v->contents + pos + 1, v->contents + pos,
177 (v->length - pos) * sizeof(void *));
bd370b14
RB
178
179 v->contents[pos] = element;
180 v->length++;
11d9f6b3 181
ae9e29fd 182 return 0;
bd370b14
RB
183}
184
c4034e63
VM
185void git_vector_sort(git_vector *v)
186{
882c7742 187 if (git_vector_is_sorted(v) || !v->_cmp)
86d7e1ca
VM
188 return;
189
3b4c401a
RB
190 if (v->length > 1)
191 git__tsort(v->contents, v->length, v->_cmp);
882c7742 192 git_vector_set_sorted(v, 1);
c4034e63
VM
193}
194
11d9f6b3 195int git_vector_bsearch2(
16248ee2 196 size_t *at_pos,
41a82592
RB
197 git_vector *v,
198 git_vector_cmp key_lookup,
199 const void *key)
c4034e63 200{
c25aa7cd
PP
201 GIT_ASSERT_ARG(v);
202 GIT_ASSERT_ARG(key);
203 GIT_ASSERT(key_lookup);
86d7e1ca 204
48c27f86 205 /* need comparison function to sort the vector */
11d9f6b3
PK
206 if (!v->_cmp)
207 return -1;
48c27f86 208
86d7e1ca
VM
209 git_vector_sort(v);
210
11d9f6b3 211 return git__bsearch(v->contents, v->length, key, key_lookup, at_pos);
86d7e1ca
VM
212}
213
41a82592 214int git_vector_search2(
11d9f6b3 215 size_t *at_pos, const git_vector *v, git_vector_cmp key_lookup, const void *key)
86d7e1ca 216{
16248ee2 217 size_t i;
86d7e1ca 218
c25aa7cd
PP
219 GIT_ASSERT_ARG(v);
220 GIT_ASSERT_ARG(key);
221 GIT_ASSERT(key_lookup);
86d7e1ca
VM
222
223 for (i = 0; i < v->length; ++i) {
11d9f6b3
PK
224 if (key_lookup(key, v->contents[i]) == 0) {
225 if (at_pos)
226 *at_pos = i;
227
228 return 0;
229 }
86d7e1ca
VM
230 }
231
ae9e29fd 232 return GIT_ENOTFOUND;
86d7e1ca
VM
233}
234
48c27f86 235static int strict_comparison(const void *a, const void *b)
86d7e1ca 236{
3c41c635 237 return (a == b) ? 0 : -1;
48c27f86 238}
c4034e63 239
11d9f6b3 240int git_vector_search(size_t *at_pos, const git_vector *v, const void *entry)
48c27f86 241{
11d9f6b3 242 return git_vector_search2(at_pos, v, v->_cmp ? v->_cmp : strict_comparison, entry);
86d7e1ca
VM
243}
244
16248ee2 245int git_vector_remove(git_vector *v, size_t idx)
c4034e63 246{
11d9f6b3 247 size_t shift_count;
c4034e63 248
c25aa7cd 249 GIT_ASSERT_ARG(v);
c4034e63 250
11d9f6b3 251 if (idx >= v->length)
ae9e29fd 252 return GIT_ENOTFOUND;
c4034e63 253
11d9f6b3
PK
254 shift_count = v->length - idx - 1;
255
256 if (shift_count)
257 memmove(&v->contents[idx], &v->contents[idx + 1],
258 shift_count * sizeof(void *));
c4034e63
VM
259
260 v->length--;
ae9e29fd 261 return 0;
c4034e63
VM
262}
263
0534641d 264void git_vector_pop(git_vector *v)
b6c93aef 265{
0534641d
RB
266 if (v->length > 0)
267 v->length--;
b6c93aef
RB
268}
269
191adce8 270void git_vector_uniq(git_vector *v, void (*git_free_cb)(void *))
476c42ac
KS
271{
272 git_vector_cmp cmp;
16248ee2 273 size_t i, j;
476c42ac
KS
274
275 if (v->length <= 1)
276 return;
277
278 git_vector_sort(v);
279 cmp = v->_cmp ? v->_cmp : strict_comparison;
280
281 for (i = 0, j = 1 ; j < v->length; ++j)
191adce8 282 if (!cmp(v->contents[i], v->contents[j])) {
283 if (git_free_cb)
284 git_free_cb(v->contents[i]);
285
476c42ac 286 v->contents[i] = v->contents[j];
191adce8 287 } else
476c42ac
KS
288 v->contents[++i] = v->contents[j];
289
290 v->length -= j - i - 1;
291}
292
16248ee2 293void git_vector_remove_matching(
c67fd4c9
RB
294 git_vector *v,
295 int (*match)(const git_vector *v, size_t idx, void *payload),
296 void *payload)
f45ec1a0 297{
16248ee2 298 size_t i, j;
f45ec1a0
ET
299
300 for (i = 0, j = 0; j < v->length; ++j) {
301 v->contents[i] = v->contents[j];
302
c67fd4c9 303 if (!match(v, i, payload))
f45ec1a0
ET
304 i++;
305 }
306
307 v->length = i;
308}
309
c4034e63
VM
310void git_vector_clear(git_vector *v)
311{
c4034e63 312 v->length = 0;
882c7742 313 git_vector_set_sorted(v, 1);
c4034e63
VM
314}
315
74fa4bfa
RB
316void git_vector_swap(git_vector *a, git_vector *b)
317{
318 git_vector t;
319
11d9f6b3
PK
320 if (a != b) {
321 memcpy(&t, a, sizeof(t));
322 memcpy(a, b, sizeof(t));
323 memcpy(b, &t, sizeof(t));
324 }
74fa4bfa 325}
db106d01
RB
326
327int git_vector_resize_to(git_vector *v, size_t new_length)
328{
11d9f6b3
PK
329 if (new_length > v->_alloc_size &&
330 resize_vector(v, new_length) < 0)
331 return -1;
db106d01 332
e26b14c0
RB
333 if (new_length > v->length)
334 memset(&v->contents[v->length], 0,
335 sizeof(void *) * (new_length - v->length));
db106d01
RB
336
337 v->length = new_length;
338
339 return 0;
340}
341
53571f2f 342int git_vector_insert_null(git_vector *v, size_t idx, size_t insert_len)
7cb904ba 343{
e564fc65 344 size_t new_length;
7cb904ba 345
c25aa7cd
PP
346 GIT_ASSERT_ARG(insert_len > 0);
347 GIT_ASSERT_ARG(idx <= v->length);
7cb904ba 348
ac3d33df 349 GIT_ERROR_CHECK_ALLOC_ADD(&new_length, v->length, insert_len);
e564fc65
ET
350
351 if (new_length > v->_alloc_size && resize_vector(v, new_length) < 0)
7cb904ba
ET
352 return -1;
353
53571f2f 354 memmove(&v->contents[idx + insert_len], &v->contents[idx],
7cb904ba 355 sizeof(void *) * (v->length - idx));
53571f2f 356 memset(&v->contents[idx], 0, sizeof(void *) * insert_len);
7cb904ba
ET
357
358 v->length = new_length;
359 return 0;
360}
361
53571f2f 362int git_vector_remove_range(git_vector *v, size_t idx, size_t remove_len)
7cb904ba 363{
53571f2f 364 size_t new_length = v->length - remove_len;
e564fc65 365 size_t end_idx = 0;
c25aa7cd
PP
366
367 GIT_ASSERT_ARG(remove_len > 0);
7cb904ba 368
53571f2f 369 if (git__add_sizet_overflow(&end_idx, idx, remove_len))
c25aa7cd 370 GIT_ASSERT(0);
7cb904ba 371
c25aa7cd 372 GIT_ASSERT(end_idx <= v->length);
7cb904ba 373
e564fc65 374 if (end_idx < v->length)
7cb904ba 375 memmove(&v->contents[idx], &v->contents[end_idx],
e564fc65 376 sizeof(void *) * (v->length - end_idx));
7cb904ba 377
53571f2f 378 memset(&v->contents[new_length], 0, sizeof(void *) * remove_len);
7cb904ba
ET
379
380 v->length = new_length;
381 return 0;
382}
383
db106d01
RB
384int git_vector_set(void **old, git_vector *v, size_t position, void *value)
385{
4998009a
JG
386 if (position + 1 > v->length) {
387 if (git_vector_resize_to(v, position + 1) < 0)
388 return -1;
389 }
db106d01
RB
390
391 if (old != NULL)
392 *old = v->contents[position];
393
394 v->contents[position] = value;
395
396 return 0;
397}
c67fd4c9
RB
398
399int git_vector_verify_sorted(const git_vector *v)
400{
401 size_t i;
402
403 if (!git_vector_is_sorted(v))
404 return -1;
405
406 for (i = 1; i < v->length; ++i) {
407 if (v->_cmp(v->contents[i - 1], v->contents[i]) > 0)
408 return -1;
409 }
410
411 return 0;
412}
0bd43371
CMN
413
414void git_vector_reverse(git_vector *v)
415{
416 size_t a, b;
417
f47db3c7
PS
418 if (v->length == 0)
419 return;
420
0bd43371
CMN
421 a = 0;
422 b = v->length - 1;
423
424 while (a < b) {
425 void *tmp = v->contents[a];
426 v->contents[a] = v->contents[b];
427 v->contents[b] = tmp;
428 a++;
429 b--;
430 }
431}