/src/git/reftable/basics.h
Line | Count | Source |
1 | | /* |
2 | | * Copyright 2020 Google LLC |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style |
5 | | * license that can be found in the LICENSE file or at |
6 | | * https://developers.google.com/open-source/licenses/bsd |
7 | | */ |
8 | | |
9 | | #ifndef BASICS_H |
10 | | #define BASICS_H |
11 | | |
12 | | /* |
13 | | * miscellaneous utilities that are not provided by Git. |
14 | | */ |
15 | | |
16 | | #include "system.h" |
17 | | #include "reftable-basics.h" |
18 | | |
19 | | #ifdef __GNUC__ |
20 | | #define REFTABLE_UNUSED __attribute__((__unused__)) |
21 | | #else |
22 | | #define REFTABLE_UNUSED |
23 | | #endif |
24 | | |
25 | | /* |
26 | | * Initialize the buffer such that it is ready for use. This is equivalent to |
27 | | * using REFTABLE_BUF_INIT for stack-allocated variables. |
28 | | */ |
29 | | void reftable_buf_init(struct reftable_buf *buf); |
30 | | |
31 | | /* |
32 | | * Release memory associated with the buffer. The buffer is reinitialized such |
33 | | * that it can be reused for subsequent operations. |
34 | | */ |
35 | | void reftable_buf_release(struct reftable_buf *buf); |
36 | | |
37 | | /* |
38 | | * Reset the buffer such that it is effectively empty, without releasing the |
39 | | * memory that this structure holds on to. This is equivalent to calling |
40 | | * `reftable_buf_setlen(buf, 0)`. |
41 | | */ |
42 | | void reftable_buf_reset(struct reftable_buf *buf); |
43 | | |
44 | | /* |
45 | | * Trim the buffer to a shorter length by updating the `len` member and writing |
46 | | * a NUL byte to `buf[len]`. Returns 0 on success, -1 when `len` points outside |
47 | | * of the array. |
48 | | */ |
49 | | int reftable_buf_setlen(struct reftable_buf *buf, size_t len); |
50 | | |
51 | | /* |
52 | | * Lexicographically compare the two buffers. Returns 0 when both buffers have |
53 | | * the same contents, -1 when `a` is lexicographically smaller than `b`, and 1 |
54 | | * otherwise. |
55 | | */ |
56 | | int reftable_buf_cmp(const struct reftable_buf *a, const struct reftable_buf *b); |
57 | | |
58 | | /* |
59 | | * Append `len` bytes from `data` to the buffer. This function works with |
60 | | * arbitrary byte sequences, including ones that contain embedded NUL |
61 | | * characters. As such, we use `void *` as input type. Returns 0 on success, |
62 | | * REFTABLE_OUT_OF_MEMORY_ERROR on allocation failure. |
63 | | */ |
64 | | int reftable_buf_add(struct reftable_buf *buf, const void *data, size_t len); |
65 | | |
66 | | /* Equivalent to `reftable_buf_add(buf, s, strlen(s))`. */ |
67 | | int reftable_buf_addstr(struct reftable_buf *buf, const char *s); |
68 | | |
69 | | /* |
70 | | * Detach the buffer from the structure such that the underlying memory is now |
71 | | * owned by the caller. The buffer is reinitialized such that it can be reused |
72 | | * for subsequent operations. |
73 | | */ |
74 | | char *reftable_buf_detach(struct reftable_buf *buf); |
75 | | |
76 | | /* Bigendian en/decoding of integers */ |
77 | | |
78 | | static inline void reftable_put_be16(void *out, uint16_t i) |
79 | 0 | { |
80 | 0 | unsigned char *p = out; |
81 | 0 | p[0] = (uint8_t)((i >> 8) & 0xff); |
82 | 0 | p[1] = (uint8_t)((i >> 0) & 0xff); |
83 | 0 | } Unexecuted instantiation: fsck.c:reftable_put_be16 Unexecuted instantiation: iter.c:reftable_put_be16 Unexecuted instantiation: record.c:reftable_put_be16 Unexecuted instantiation: stack.c:reftable_put_be16 Unexecuted instantiation: system.c:reftable_put_be16 Unexecuted instantiation: table.c:reftable_put_be16 Unexecuted instantiation: writer.c:reftable_put_be16 Unexecuted instantiation: basics.c:reftable_put_be16 Unexecuted instantiation: block.c:reftable_put_be16 Unexecuted instantiation: blocksource.c:reftable_put_be16 Unexecuted instantiation: merged.c:reftable_put_be16 Unexecuted instantiation: pq.c:reftable_put_be16 Unexecuted instantiation: tree.c:reftable_put_be16 |
84 | | |
85 | | static inline void reftable_put_be24(void *out, uint32_t i) |
86 | 0 | { |
87 | 0 | unsigned char *p = out; |
88 | 0 | p[0] = (uint8_t)((i >> 16) & 0xff); |
89 | 0 | p[1] = (uint8_t)((i >> 8) & 0xff); |
90 | 0 | p[2] = (uint8_t)((i >> 0) & 0xff); |
91 | 0 | } Unexecuted instantiation: fsck.c:reftable_put_be24 Unexecuted instantiation: iter.c:reftable_put_be24 Unexecuted instantiation: record.c:reftable_put_be24 Unexecuted instantiation: stack.c:reftable_put_be24 Unexecuted instantiation: system.c:reftable_put_be24 Unexecuted instantiation: table.c:reftable_put_be24 Unexecuted instantiation: writer.c:reftable_put_be24 Unexecuted instantiation: basics.c:reftable_put_be24 Unexecuted instantiation: block.c:reftable_put_be24 Unexecuted instantiation: blocksource.c:reftable_put_be24 Unexecuted instantiation: merged.c:reftable_put_be24 Unexecuted instantiation: pq.c:reftable_put_be24 Unexecuted instantiation: tree.c:reftable_put_be24 |
92 | | |
93 | | static inline void reftable_put_be32(void *out, uint32_t i) |
94 | 0 | { |
95 | 0 | unsigned char *p = out; |
96 | 0 | p[0] = (uint8_t)((i >> 24) & 0xff); |
97 | 0 | p[1] = (uint8_t)((i >> 16) & 0xff); |
98 | 0 | p[2] = (uint8_t)((i >> 8) & 0xff); |
99 | 0 | p[3] = (uint8_t)((i >> 0) & 0xff); |
100 | 0 | } Unexecuted instantiation: fsck.c:reftable_put_be32 Unexecuted instantiation: iter.c:reftable_put_be32 Unexecuted instantiation: record.c:reftable_put_be32 Unexecuted instantiation: stack.c:reftable_put_be32 Unexecuted instantiation: system.c:reftable_put_be32 Unexecuted instantiation: table.c:reftable_put_be32 Unexecuted instantiation: writer.c:reftable_put_be32 Unexecuted instantiation: basics.c:reftable_put_be32 Unexecuted instantiation: block.c:reftable_put_be32 Unexecuted instantiation: blocksource.c:reftable_put_be32 Unexecuted instantiation: merged.c:reftable_put_be32 Unexecuted instantiation: pq.c:reftable_put_be32 Unexecuted instantiation: tree.c:reftable_put_be32 |
101 | | |
102 | | static inline void reftable_put_be64(void *out, uint64_t i) |
103 | 0 | { |
104 | 0 | unsigned char *p = out; |
105 | 0 | p[0] = (uint8_t)((i >> 56) & 0xff); |
106 | 0 | p[1] = (uint8_t)((i >> 48) & 0xff); |
107 | 0 | p[2] = (uint8_t)((i >> 40) & 0xff); |
108 | 0 | p[3] = (uint8_t)((i >> 32) & 0xff); |
109 | 0 | p[4] = (uint8_t)((i >> 24) & 0xff); |
110 | 0 | p[5] = (uint8_t)((i >> 16) & 0xff); |
111 | 0 | p[6] = (uint8_t)((i >> 8) & 0xff); |
112 | 0 | p[7] = (uint8_t)((i >> 0) & 0xff); |
113 | 0 | } Unexecuted instantiation: fsck.c:reftable_put_be64 Unexecuted instantiation: iter.c:reftable_put_be64 Unexecuted instantiation: record.c:reftable_put_be64 Unexecuted instantiation: stack.c:reftable_put_be64 Unexecuted instantiation: system.c:reftable_put_be64 Unexecuted instantiation: table.c:reftable_put_be64 Unexecuted instantiation: writer.c:reftable_put_be64 Unexecuted instantiation: basics.c:reftable_put_be64 Unexecuted instantiation: block.c:reftable_put_be64 Unexecuted instantiation: blocksource.c:reftable_put_be64 Unexecuted instantiation: merged.c:reftable_put_be64 Unexecuted instantiation: pq.c:reftable_put_be64 Unexecuted instantiation: tree.c:reftable_put_be64 |
114 | | |
115 | | static inline uint16_t reftable_get_be16(const void *in) |
116 | 0 | { |
117 | 0 | const unsigned char *p = in; |
118 | 0 | return (uint16_t)(p[0]) << 8 | |
119 | 0 | (uint16_t)(p[1]) << 0; |
120 | 0 | } Unexecuted instantiation: fsck.c:reftable_get_be16 Unexecuted instantiation: iter.c:reftable_get_be16 Unexecuted instantiation: record.c:reftable_get_be16 Unexecuted instantiation: stack.c:reftable_get_be16 Unexecuted instantiation: system.c:reftable_get_be16 Unexecuted instantiation: table.c:reftable_get_be16 Unexecuted instantiation: writer.c:reftable_get_be16 Unexecuted instantiation: basics.c:reftable_get_be16 Unexecuted instantiation: block.c:reftable_get_be16 Unexecuted instantiation: blocksource.c:reftable_get_be16 Unexecuted instantiation: merged.c:reftable_get_be16 Unexecuted instantiation: pq.c:reftable_get_be16 Unexecuted instantiation: tree.c:reftable_get_be16 |
121 | | |
122 | | static inline uint32_t reftable_get_be24(const void *in) |
123 | 0 | { |
124 | 0 | const unsigned char *p = in; |
125 | 0 | return (uint32_t)(p[0]) << 16 | |
126 | 0 | (uint32_t)(p[1]) << 8 | |
127 | 0 | (uint32_t)(p[2]) << 0; |
128 | 0 | } Unexecuted instantiation: fsck.c:reftable_get_be24 Unexecuted instantiation: iter.c:reftable_get_be24 Unexecuted instantiation: record.c:reftable_get_be24 Unexecuted instantiation: stack.c:reftable_get_be24 Unexecuted instantiation: system.c:reftable_get_be24 Unexecuted instantiation: table.c:reftable_get_be24 Unexecuted instantiation: writer.c:reftable_get_be24 Unexecuted instantiation: basics.c:reftable_get_be24 Unexecuted instantiation: block.c:reftable_get_be24 Unexecuted instantiation: blocksource.c:reftable_get_be24 Unexecuted instantiation: merged.c:reftable_get_be24 Unexecuted instantiation: pq.c:reftable_get_be24 Unexecuted instantiation: tree.c:reftable_get_be24 |
129 | | |
130 | | static inline uint32_t reftable_get_be32(const void *in) |
131 | 0 | { |
132 | 0 | const unsigned char *p = in; |
133 | 0 | return (uint32_t)(p[0]) << 24 | |
134 | 0 | (uint32_t)(p[1]) << 16 | |
135 | 0 | (uint32_t)(p[2]) << 8| |
136 | 0 | (uint32_t)(p[3]) << 0; |
137 | 0 | } Unexecuted instantiation: fsck.c:reftable_get_be32 Unexecuted instantiation: iter.c:reftable_get_be32 Unexecuted instantiation: record.c:reftable_get_be32 Unexecuted instantiation: stack.c:reftable_get_be32 Unexecuted instantiation: system.c:reftable_get_be32 Unexecuted instantiation: table.c:reftable_get_be32 Unexecuted instantiation: writer.c:reftable_get_be32 Unexecuted instantiation: basics.c:reftable_get_be32 Unexecuted instantiation: block.c:reftable_get_be32 Unexecuted instantiation: blocksource.c:reftable_get_be32 Unexecuted instantiation: merged.c:reftable_get_be32 Unexecuted instantiation: pq.c:reftable_get_be32 Unexecuted instantiation: tree.c:reftable_get_be32 |
138 | | |
139 | | static inline uint64_t reftable_get_be64(const void *in) |
140 | 0 | { |
141 | 0 | const unsigned char *p = in; |
142 | 0 | return (uint64_t)(p[0]) << 56 | |
143 | 0 | (uint64_t)(p[1]) << 48 | |
144 | 0 | (uint64_t)(p[2]) << 40 | |
145 | 0 | (uint64_t)(p[3]) << 32 | |
146 | 0 | (uint64_t)(p[4]) << 24 | |
147 | 0 | (uint64_t)(p[5]) << 16 | |
148 | 0 | (uint64_t)(p[6]) << 8 | |
149 | 0 | (uint64_t)(p[7]) << 0; |
150 | 0 | } Unexecuted instantiation: fsck.c:reftable_get_be64 Unexecuted instantiation: iter.c:reftable_get_be64 Unexecuted instantiation: record.c:reftable_get_be64 Unexecuted instantiation: stack.c:reftable_get_be64 Unexecuted instantiation: system.c:reftable_get_be64 Unexecuted instantiation: table.c:reftable_get_be64 Unexecuted instantiation: writer.c:reftable_get_be64 Unexecuted instantiation: basics.c:reftable_get_be64 Unexecuted instantiation: block.c:reftable_get_be64 Unexecuted instantiation: blocksource.c:reftable_get_be64 Unexecuted instantiation: merged.c:reftable_get_be64 Unexecuted instantiation: pq.c:reftable_get_be64 Unexecuted instantiation: tree.c:reftable_get_be64 |
151 | | |
152 | | /* |
153 | | * find smallest index i in [0, sz) at which `f(i) > 0`, assuming that f is |
154 | | * ascending. Return sz if `f(i) == 0` for all indices. The search is aborted |
155 | | * and `sz` is returned in case `f(i) < 0`. |
156 | | * |
157 | | * Contrary to bsearch(3), this returns something useful if the argument is not |
158 | | * found. |
159 | | */ |
160 | | size_t binsearch(size_t sz, int (*f)(size_t k, void *args), void *args); |
161 | | |
162 | | /* |
163 | | * Frees a NULL terminated array of malloced strings. The array itself is also |
164 | | * freed. |
165 | | */ |
166 | | void free_names(char **a); |
167 | | |
168 | | /* |
169 | | * Parse a newline separated list of names. `size` is the length of the buffer, |
170 | | * without terminating '\0'. Empty names are discarded. |
171 | | * |
172 | | * Returns 0 on success, a reftable error code on error. |
173 | | */ |
174 | | int parse_names(char *buf, int size, char ***out); |
175 | | |
176 | | /* compares two NULL-terminated arrays of strings. */ |
177 | | int names_equal(const char **a, const char **b); |
178 | | |
179 | | /* returns the array size of a NULL-terminated array of strings. */ |
180 | | size_t names_length(const char **names); |
181 | | |
182 | | /* Allocation routines; they invoke the functions set through |
183 | | * reftable_set_alloc() */ |
184 | | void *reftable_malloc(size_t sz); |
185 | | void *reftable_realloc(void *p, size_t sz); |
186 | | void reftable_free(void *p); |
187 | | void *reftable_calloc(size_t nelem, size_t elsize); |
188 | | char *reftable_strdup(const char *str); |
189 | | |
190 | | static inline int reftable_alloc_size(size_t nelem, size_t elsize, size_t *out) |
191 | 0 | { |
192 | 0 | if (nelem && elsize > SIZE_MAX / nelem) |
193 | 0 | return -1; |
194 | 0 | *out = nelem * elsize; |
195 | 0 | return 0; |
196 | 0 | } Unexecuted instantiation: fsck.c:reftable_alloc_size Unexecuted instantiation: iter.c:reftable_alloc_size Unexecuted instantiation: record.c:reftable_alloc_size Unexecuted instantiation: stack.c:reftable_alloc_size Unexecuted instantiation: system.c:reftable_alloc_size Unexecuted instantiation: table.c:reftable_alloc_size Unexecuted instantiation: writer.c:reftable_alloc_size Unexecuted instantiation: basics.c:reftable_alloc_size Unexecuted instantiation: block.c:reftable_alloc_size Unexecuted instantiation: blocksource.c:reftable_alloc_size Unexecuted instantiation: merged.c:reftable_alloc_size Unexecuted instantiation: pq.c:reftable_alloc_size Unexecuted instantiation: tree.c:reftable_alloc_size |
197 | | |
198 | 0 | #define REFTABLE_ALLOC_ARRAY(x, alloc) do { \ |
199 | 0 | size_t alloc_size; \ |
200 | 0 | if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \ |
201 | 0 | errno = ENOMEM; \ |
202 | 0 | (x) = NULL; \ |
203 | 0 | } else { \ |
204 | 0 | (x) = reftable_malloc(alloc_size); \ |
205 | 0 | } \ |
206 | 0 | } while (0) |
207 | 0 | #define REFTABLE_CALLOC_ARRAY(x, alloc) (x) = reftable_calloc((alloc), sizeof(*(x))) |
208 | | #define REFTABLE_REALLOC_ARRAY(x, alloc) do { \ |
209 | | size_t alloc_size; \ |
210 | | if (reftable_alloc_size(sizeof(*(x)), (alloc), &alloc_size) < 0) { \ |
211 | | errno = ENOMEM; \ |
212 | | (x) = NULL; \ |
213 | | } else { \ |
214 | | (x) = reftable_realloc((x), alloc_size); \ |
215 | | } \ |
216 | | } while (0) |
217 | | |
218 | | static inline void *reftable_alloc_grow(void *p, size_t nelem, size_t elsize, |
219 | | size_t *allocp) |
220 | 0 | { |
221 | 0 | void *new_p; |
222 | 0 | size_t alloc = *allocp * 2 + 1, alloc_bytes; |
223 | 0 | if (alloc < nelem) |
224 | 0 | alloc = nelem; |
225 | 0 | if (reftable_alloc_size(elsize, alloc, &alloc_bytes) < 0) { |
226 | 0 | errno = ENOMEM; |
227 | 0 | return p; |
228 | 0 | } |
229 | 0 | new_p = reftable_realloc(p, alloc_bytes); |
230 | 0 | if (!new_p) |
231 | 0 | return p; |
232 | 0 | *allocp = alloc; |
233 | 0 | return new_p; |
234 | 0 | } Unexecuted instantiation: fsck.c:reftable_alloc_grow Unexecuted instantiation: iter.c:reftable_alloc_grow Unexecuted instantiation: record.c:reftable_alloc_grow Unexecuted instantiation: stack.c:reftable_alloc_grow Unexecuted instantiation: system.c:reftable_alloc_grow Unexecuted instantiation: table.c:reftable_alloc_grow Unexecuted instantiation: writer.c:reftable_alloc_grow Unexecuted instantiation: basics.c:reftable_alloc_grow Unexecuted instantiation: block.c:reftable_alloc_grow Unexecuted instantiation: blocksource.c:reftable_alloc_grow Unexecuted instantiation: merged.c:reftable_alloc_grow Unexecuted instantiation: pq.c:reftable_alloc_grow Unexecuted instantiation: tree.c:reftable_alloc_grow |
235 | | |
236 | 0 | #define REFTABLE_ALLOC_GROW(x, nr, alloc) ( \ |
237 | 0 | (nr) > (alloc) && ( \ |
238 | 0 | (x) = reftable_alloc_grow((x), (nr), sizeof(*(x)), &(alloc)), \ |
239 | 0 | (nr) > (alloc) \ |
240 | 0 | ) \ |
241 | 0 | ) |
242 | | |
243 | 0 | #define REFTABLE_ALLOC_GROW_OR_NULL(x, nr, alloc) do { \ |
244 | 0 | size_t reftable_alloc_grow_or_null_alloc = alloc; \ |
245 | 0 | if (REFTABLE_ALLOC_GROW((x), (nr), reftable_alloc_grow_or_null_alloc)) { \ |
246 | 0 | REFTABLE_FREE_AND_NULL(x); \ |
247 | 0 | alloc = 0; \ |
248 | 0 | } else { \ |
249 | 0 | alloc = reftable_alloc_grow_or_null_alloc; \ |
250 | 0 | } \ |
251 | 0 | } while (0) |
252 | | |
253 | 0 | #define REFTABLE_FREE_AND_NULL(p) do { reftable_free(p); (p) = NULL; } while (0) |
254 | | |
255 | | #ifndef REFTABLE_ALLOW_BANNED_ALLOCATORS |
256 | | # define REFTABLE_BANNED(func) use_reftable_##func##_instead |
257 | | # undef malloc |
258 | | # define malloc(sz) REFTABLE_BANNED(malloc) |
259 | | # undef realloc |
260 | | # define realloc(ptr, sz) REFTABLE_BANNED(realloc) |
261 | | # undef free |
262 | | # define free(ptr) REFTABLE_BANNED(free) |
263 | | # undef calloc |
264 | | # define calloc(nelem, elsize) REFTABLE_BANNED(calloc) |
265 | | # undef strdup |
266 | | # define strdup(str) REFTABLE_BANNED(strdup) |
267 | | #endif |
268 | | |
269 | 0 | #define REFTABLE_SWAP(a, b) do { \ |
270 | 0 | void *_swap_a_ptr = &(a); \ |
271 | 0 | void *_swap_b_ptr = &(b); \ |
272 | 0 | unsigned char _swap_buffer[sizeof(a) - 2 * sizeof(a) * (sizeof(a) != sizeof(b))]; \ |
273 | 0 | memcpy(_swap_buffer, _swap_a_ptr, sizeof(a)); \ |
274 | 0 | memcpy(_swap_a_ptr, _swap_b_ptr, sizeof(a)); \ |
275 | 0 | memcpy(_swap_b_ptr, _swap_buffer, sizeof(a)); \ |
276 | 0 | } while (0) |
277 | | |
278 | | /* Find the longest shared prefix size of `a` and `b` */ |
279 | | size_t common_prefix_size(struct reftable_buf *a, struct reftable_buf *b); |
280 | | |
281 | | uint32_t hash_size(enum reftable_hash id); |
282 | | |
283 | | /* |
284 | | * Format IDs that identify the hash function used by a reftable. Note that |
285 | | * these constants end up on disk and thus mustn't change. The format IDs are |
286 | | * "sha1" and "s256" in big endian, respectively. |
287 | | */ |
288 | 0 | #define REFTABLE_FORMAT_ID_SHA1 ((uint32_t) 0x73686131) |
289 | 0 | #define REFTABLE_FORMAT_ID_SHA256 ((uint32_t) 0x73323536) |
290 | | |
291 | | #endif |