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