]> git.proxmox.com Git - libgit2.git/blob - src/pool.c
Drop patch as it is merged upstream
[libgit2.git] / src / pool.c
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 "pool.h"
9
10 #include "posix.h"
11 #ifndef GIT_WIN32
12 #include <unistd.h>
13 #endif
14
15 struct git_pool_page {
16 git_pool_page *next;
17 size_t size;
18 size_t avail;
19 GIT_ALIGN(char data[GIT_FLEX_ARRAY], 8);
20 };
21
22 static void *pool_alloc_page(git_pool *pool, size_t size);
23
24 size_t git_pool__system_page_size(void)
25 {
26 static size_t size = 0;
27
28 if (!size) {
29 size_t page_size;
30 if (git__page_size(&page_size) < 0)
31 page_size = 4096;
32 /* allow space for malloc overhead */
33 size = (page_size - (2 * sizeof(void *)) - sizeof(git_pool_page));
34 }
35
36 return size;
37 }
38
39 #ifndef GIT_DEBUG_POOL
40 void git_pool_init(git_pool *pool, size_t item_size)
41 {
42 assert(pool);
43 assert(item_size >= 1);
44
45 memset(pool, 0, sizeof(git_pool));
46 pool->item_size = item_size;
47 pool->page_size = git_pool__system_page_size();
48 }
49
50 void git_pool_clear(git_pool *pool)
51 {
52 git_pool_page *scan, *next;
53
54 for (scan = pool->pages; scan != NULL; scan = next) {
55 next = scan->next;
56 git__free(scan);
57 }
58
59 pool->pages = NULL;
60 }
61
62 static void *pool_alloc_page(git_pool *pool, size_t size)
63 {
64 git_pool_page *page;
65 const size_t new_page_size = (size <= pool->page_size) ? pool->page_size : size;
66 size_t alloc_size;
67
68 if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
69 !(page = git__malloc(alloc_size)))
70 return NULL;
71
72 page->size = new_page_size;
73 page->avail = new_page_size - size;
74 page->next = pool->pages;
75
76 pool->pages = page;
77
78 return page->data;
79 }
80
81 static void *pool_alloc(git_pool *pool, size_t size)
82 {
83 git_pool_page *page = pool->pages;
84 void *ptr = NULL;
85
86 if (!page || page->avail < size)
87 return pool_alloc_page(pool, size);
88
89 ptr = &page->data[page->size - page->avail];
90 page->avail -= size;
91
92 return ptr;
93 }
94
95 uint32_t git_pool__open_pages(git_pool *pool)
96 {
97 uint32_t ct = 0;
98 git_pool_page *scan;
99 for (scan = pool->pages; scan != NULL; scan = scan->next) ct++;
100 return ct;
101 }
102
103 bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
104 {
105 git_pool_page *scan;
106 for (scan = pool->pages; scan != NULL; scan = scan->next)
107 if ((void *)scan->data <= ptr &&
108 (void *)(((char *)scan->data) + scan->size) > ptr)
109 return true;
110 return false;
111 }
112
113 #else
114
115 static int git_pool__ptr_cmp(const void * a, const void * b)
116 {
117 if(a > b) {
118 return 1;
119 }
120 if(a < b) {
121 return -1;
122 }
123 else {
124 return 0;
125 }
126 }
127
128 void git_pool_init(git_pool *pool, size_t item_size)
129 {
130 assert(pool);
131 assert(item_size >= 1);
132
133 memset(pool, 0, sizeof(git_pool));
134 pool->item_size = item_size;
135 pool->page_size = git_pool__system_page_size();
136 git_vector_init(&pool->allocations, 100, git_pool__ptr_cmp);
137 }
138
139 void git_pool_clear(git_pool *pool)
140 {
141 git_vector_free_deep(&pool->allocations);
142 }
143
144 static void *pool_alloc(git_pool *pool, size_t size) {
145 void *ptr = NULL;
146 if((ptr = git__malloc(size)) == NULL) {
147 return NULL;
148 }
149 git_vector_insert_sorted(&pool->allocations, ptr, NULL);
150 return ptr;
151 }
152
153 bool git_pool__ptr_in_pool(git_pool *pool, void *ptr)
154 {
155 size_t pos;
156 return git_vector_bsearch(&pos, &pool->allocations, ptr) != GIT_ENOTFOUND;
157 }
158 #endif
159
160 void git_pool_swap(git_pool *a, git_pool *b)
161 {
162 git_pool temp;
163
164 if (a == b)
165 return;
166
167 memcpy(&temp, a, sizeof(temp));
168 memcpy(a, b, sizeof(temp));
169 memcpy(b, &temp, sizeof(temp));
170 }
171
172 static size_t alloc_size(git_pool *pool, size_t count)
173 {
174 const size_t align = sizeof(void *) - 1;
175
176 if (pool->item_size > 1) {
177 const size_t item_size = (pool->item_size + align) & ~align;
178 return item_size * count;
179 }
180
181 return (count + align) & ~align;
182 }
183
184 void *git_pool_malloc(git_pool *pool, size_t items)
185 {
186 return pool_alloc(pool, alloc_size(pool, items));
187 }
188
189 void *git_pool_mallocz(git_pool *pool, size_t items)
190 {
191 const size_t size = alloc_size(pool, items);
192 void *ptr = pool_alloc(pool, size);
193 if (ptr)
194 memset(ptr, 0x0, size);
195 return ptr;
196 }
197
198 char *git_pool_strndup(git_pool *pool, const char *str, size_t n)
199 {
200 char *ptr = NULL;
201
202 assert(pool && str && pool->item_size == sizeof(char));
203
204 if (n == SIZE_MAX)
205 return NULL;
206
207 if ((ptr = git_pool_malloc(pool, (n + 1))) != NULL) {
208 memcpy(ptr, str, n);
209 ptr[n] = '\0';
210 }
211
212 return ptr;
213 }
214
215 char *git_pool_strdup(git_pool *pool, const char *str)
216 {
217 assert(pool && str && pool->item_size == sizeof(char));
218 return git_pool_strndup(pool, str, strlen(str));
219 }
220
221 char *git_pool_strdup_safe(git_pool *pool, const char *str)
222 {
223 return str ? git_pool_strdup(pool, str) : NULL;
224 }
225
226 char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
227 {
228 void *ptr;
229 size_t len_a, len_b, total;
230
231 assert(pool && pool->item_size == sizeof(char));
232
233 len_a = a ? strlen(a) : 0;
234 len_b = b ? strlen(b) : 0;
235
236 if (GIT_ADD_SIZET_OVERFLOW(&total, len_a, len_b) ||
237 GIT_ADD_SIZET_OVERFLOW(&total, total, 1))
238 return NULL;
239
240 if ((ptr = git_pool_malloc(pool, total)) != NULL) {
241 if (len_a)
242 memcpy(ptr, a, len_a);
243 if (len_b)
244 memcpy(((char *)ptr) + len_a, b, len_b);
245 *(((char *)ptr) + len_a + len_b) = '\0';
246 }
247 return ptr;
248 }