]>
Commit | Line | Data |
---|---|---|
2bc8fa02 | 1 | #include "pool.h" |
62e562f9 | 2 | #include "posix.h" |
2bc8fa02 RB |
3 | #ifndef GIT_WIN32 |
4 | #include <unistd.h> | |
5 | #endif | |
6 | ||
7 | struct git_pool_page { | |
8 | git_pool_page *next; | |
9 | uint32_t size; | |
10 | uint32_t avail; | |
1e5e02b4 | 11 | char data[GIT_FLEX_ARRAY]; |
2bc8fa02 RB |
12 | }; |
13 | ||
1e5e02b4 | 14 | static void *pool_alloc_page(git_pool *pool, uint32_t size); |
14bedad9 | 15 | |
1e5e02b4 VM |
16 | uint32_t git_pool__system_page_size(void) |
17 | { | |
18 | static uint32_t size = 0; | |
2bc8fa02 | 19 | |
1e5e02b4 VM |
20 | if (!size) { |
21 | size_t page_size; | |
22 | if (git__page_size(&page_size) < 0) | |
23 | page_size = 4096; | |
410efda8 VM |
24 | /* allow space for malloc overhead */ |
25 | size = page_size - (2 * sizeof(void *)) - sizeof(git_pool_page); | |
1e5e02b4 | 26 | } |
2bc8fa02 | 27 | |
1e5e02b4 VM |
28 | return size; |
29 | } | |
30 | ||
31 | void git_pool_init(git_pool *pool, uint32_t item_size) | |
2bc8fa02 | 32 | { |
1e5e02b4 | 33 | const uint32_t align_size = sizeof(void *) - 1; |
2bc8fa02 RB |
34 | assert(pool); |
35 | ||
1e5e02b4 VM |
36 | if (item_size > 1) |
37 | item_size = (item_size + align_size) & ~align_size; | |
2bc8fa02 RB |
38 | |
39 | memset(pool, 0, sizeof(git_pool)); | |
40 | pool->item_size = item_size; | |
1e5e02b4 | 41 | pool->page_size = git_pool__system_page_size(); |
2bc8fa02 RB |
42 | } |
43 | ||
44 | void git_pool_clear(git_pool *pool) | |
45 | { | |
46 | git_pool_page *scan, *next; | |
47 | ||
1e5e02b4 | 48 | for (scan = pool->pages; scan != NULL; scan = next) { |
2bc8fa02 RB |
49 | next = scan->next; |
50 | git__free(scan); | |
51 | } | |
2bc8fa02 | 52 | |
1e5e02b4 | 53 | pool->pages = NULL; |
19fa2bc1 | 54 | pool->items = 0; |
2bc8fa02 RB |
55 | } |
56 | ||
19fa2bc1 RB |
57 | void git_pool_swap(git_pool *a, git_pool *b) |
58 | { | |
59 | git_pool temp; | |
60 | ||
61 | if (a == b) | |
62 | return; | |
63 | ||
64 | memcpy(&temp, a, sizeof(temp)); | |
65 | memcpy(a, b, sizeof(temp)); | |
66 | memcpy(b, &temp, sizeof(temp)); | |
67 | } | |
68 | ||
19fa2bc1 | 69 | static void *pool_alloc_page(git_pool *pool, uint32_t size) |
2bc8fa02 RB |
70 | { |
71 | git_pool_page *page; | |
1e5e02b4 | 72 | const uint32_t new_page_size = (size <= pool->page_size) ? pool->page_size : size; |
f1453c59 | 73 | size_t alloc_size; |
2bc8fa02 | 74 | |
f1453c59 ET |
75 | if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) || |
76 | !(page = git__calloc(1, alloc_size))) | |
19fa2bc1 | 77 | return NULL; |
2bc8fa02 | 78 | |
1e5e02b4 | 79 | page->size = new_page_size; |
f1453c59 | 80 | page->avail = new_page_size - size; |
1e5e02b4 | 81 | page->next = pool->pages; |
2bc8fa02 | 82 | |
1e5e02b4 | 83 | pool->pages = page; |
19fa2bc1 | 84 | pool->items++; |
2bc8fa02 | 85 | |
19fa2bc1 | 86 | return page->data; |
2bc8fa02 RB |
87 | } |
88 | ||
19fa2bc1 | 89 | void *git_pool_malloc(git_pool *pool, uint32_t items) |
2bc8fa02 | 90 | { |
1e5e02b4 | 91 | const uint32_t size = items * pool->item_size; |
2bc8fa02 | 92 | |
1e5e02b4 VM |
93 | git_pool_page *page = pool->pages; |
94 | void *ptr = NULL; | |
2bc8fa02 | 95 | |
1e5e02b4 | 96 | if (!page || page->avail < size) |
19fa2bc1 RB |
97 | return pool_alloc_page(pool, size); |
98 | ||
1e5e02b4 VM |
99 | ptr = &page->data[page->size - page->avail]; |
100 | page->avail -= size; | |
19fa2bc1 | 101 | pool->items++; |
2bc8fa02 | 102 | |
19fa2bc1 | 103 | return ptr; |
2bc8fa02 RB |
104 | } |
105 | ||
106 | char *git_pool_strndup(git_pool *pool, const char *str, size_t n) | |
107 | { | |
ce33645f | 108 | char *ptr = NULL; |
2bc8fa02 RB |
109 | |
110 | assert(pool && str && pool->item_size == sizeof(char)); | |
111 | ||
437f7d69 VM |
112 | if ((uint32_t)(n + 1) < n) |
113 | return NULL; | |
114 | ||
821f6bc7 | 115 | if ((ptr = git_pool_malloc(pool, (uint32_t)(n + 1))) != NULL) { |
2bc8fa02 | 116 | memcpy(ptr, str, n); |
ce33645f | 117 | ptr[n] = '\0'; |
19fa2bc1 | 118 | } |
ce33645f | 119 | |
2bc8fa02 RB |
120 | return ptr; |
121 | } | |
122 | ||
123 | char *git_pool_strdup(git_pool *pool, const char *str) | |
124 | { | |
125 | assert(pool && str && pool->item_size == sizeof(char)); | |
19fa2bc1 RB |
126 | return git_pool_strndup(pool, str, strlen(str)); |
127 | } | |
128 | ||
71d27358 RB |
129 | char *git_pool_strdup_safe(git_pool *pool, const char *str) |
130 | { | |
ce33645f | 131 | return str ? git_pool_strdup(pool, str) : NULL; |
71d27358 RB |
132 | } |
133 | ||
19fa2bc1 RB |
134 | char *git_pool_strcat(git_pool *pool, const char *a, const char *b) |
135 | { | |
136 | void *ptr; | |
137 | size_t len_a, len_b; | |
138 | ||
9ae4ad2d | 139 | assert(pool && pool->item_size == sizeof(char)); |
19fa2bc1 RB |
140 | |
141 | len_a = a ? strlen(a) : 0; | |
142 | len_b = b ? strlen(b) : 0; | |
143 | ||
821f6bc7 | 144 | if ((ptr = git_pool_malloc(pool, (uint32_t)(len_a + len_b + 1))) != NULL) { |
19fa2bc1 RB |
145 | if (len_a) |
146 | memcpy(ptr, a, len_a); | |
147 | if (len_b) | |
148 | memcpy(((char *)ptr) + len_a, b, len_b); | |
149 | *(((char *)ptr) + len_a + len_b) = '\0'; | |
150 | } | |
19fa2bc1 | 151 | return ptr; |
2bc8fa02 RB |
152 | } |
153 | ||
2bc8fa02 RB |
154 | uint32_t git_pool__open_pages(git_pool *pool) |
155 | { | |
156 | uint32_t ct = 0; | |
157 | git_pool_page *scan; | |
1e5e02b4 | 158 | for (scan = pool->pages; scan != NULL; scan = scan->next) ct++; |
2bc8fa02 RB |
159 | return ct; |
160 | } | |
161 | ||
162 | bool git_pool__ptr_in_pool(git_pool *pool, void *ptr) | |
163 | { | |
164 | git_pool_page *scan; | |
1e5e02b4 | 165 | for (scan = pool->pages; scan != NULL; scan = scan->next) |
821f6bc7 RB |
166 | if ((void *)scan->data <= ptr && |
167 | (void *)(((char *)scan->data) + scan->size) > ptr) | |
2bc8fa02 RB |
168 | return true; |
169 | return false; | |
170 | } |