-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutil.h
116 lines (102 loc) · 3.71 KB
/
util.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/* SPDX-FileCopyrightText: 2024 - 2025 Eli Array Minkoff
*
* SPDX-License-Identifier: GPL-3.0-only
*
* Miscellaneous utility functions used throughout the eambfc codebase. */
#ifndef BFC_UTIL_H
#define BFC_UTIL_H 1
/* C99 */
#include <limits.h>
#include <stdlib.h>
#include <string.h>
/* internal */
#include "attributes.h"
#include "config.h"
#include "err.h"
#include "types.h"
/* Try to `malloc(size)`. On success, pass the returned pointer.
* On failure, call `alloc_err` */
inline malloc_like nonnull_ret void *checked_malloc(size_t size) {
void *ptr = malloc(size);
if (!ptr) alloc_err();
return ptr;
}
/* Try to `realloc(ptr, size)`. On success, pass the returned pointer.
* On failure, call `alloc_err` */
inline nonnull_ret void *checked_realloc(void *ptr, size_t size) {
void *newptr = realloc(ptr, size);
if (!newptr) {
free(ptr);
alloc_err();
}
return newptr;
}
/* return the number of trailing zeroes in val */
const_fn inline u8 trailing_0s(u64 val) {
if (!val) return UINT8_MAX;
u8 counter = 0;
while (!(val & 1)) {
val >>= 1;
counter += 1;
}
return counter;
}
/* return `nbytes`, padded to the next multiple of `BFC_CHUNK_SIZE`. If it is
* already a multiple of `BFC_CHUNK_SIZE`, it is returned as-is, and if the
* padding would exceed `SIZE_MAX`, it returns `SIZE_MAX`. */
const_fn inline size_t chunk_pad(size_t nbytes) {
if (!(nbytes & (BFC_CHUNK_SIZE - 1))) return nbytes;
size_t ret = (nbytes & ~(size_t)(BFC_CHUNK_SIZE - 1)) + BFC_CHUNK_SIZE;
return (ret < nbytes) ? SIZE_MAX : ret;
}
/* Return true if signed `val` fits within specified number of bits */
const_fn inline bool bit_fits(i64 val, u8 bits) {
return val >= -(INT64_C(1) << (bits - 1)) &&
val < (INT64_C(1) << (bits - 1));
}
/* create a new sized_buf with the provided capacity, and an allocated buffer */
inline sized_buf newbuf(size_t sz) {
sized_buf newbuf = {
.buf = checked_malloc(sz),
.sz = 0,
.capacity = sz,
};
return newbuf;
}
/* return the least significant nbits of val sign-extended to 64 bits. */
const_fn inline i64 sign_extend(i64 val, u8 nbits) {
u8 shift_amount = (sizeof(i64) * 8) - nbits;
/* shifting into the sign bit is undefined behavior, so cast it to unsigned,
* then assign it back. */
i64 lshifted = ((u64)val << shift_amount);
return lshifted >> shift_amount;
}
/* Attempts to write `ct` bytes from `buf` to `fd`.
* If all bytes are written, returns `true`, otherwise, it sets `err->id` and
* `err->msg`, zeroing out other fields in `err`, then returns `false`. */
nonnull_args bool write_obj(
int fd, const void *restrict buf, size_t ct, bf_comp_err *restrict outname
);
/* reserve nbytes bytes at the end of dst, and returns a pointer to the
* beginning of them - it's assumed that the caller will populate them, so the
* sized_buf will consider them used */
nonnull_ret void *sb_reserve(sized_buf *sb, size_t nbytes);
/* Appends first bytes_sz of bytes to dst, reallocating dst as needed. */
nonnull_args void append_obj(
sized_buf *restrict dst, const void *restrict bytes, size_t bytes_sz
);
/* append `str` to `dst` with `append_obj`, and adjust `dst->sz` to exclude the
* null terminator */
inline void append_str(sized_buf *restrict dst, const char *restrict str) {
append_obj(dst, str, strlen(str) + 1);
dst->sz--;
}
union read_result {
sized_buf sb;
bf_comp_err err;
};
/* Tries to read `fd` into `result->sb`. If a read fails, returns `false`, and
* sets `result->err` to an error with the `id` and `msg` set. Once no data is
* left to read, it returns `true`. */
nonnull_args bool read_to_sized_buf(int fd, union read_result *result);
#endif /* BFC_UTIL_H */