| 1 | /* @title: Allocation Macros */ |
| 2 | #pragma once |
| 3 | #include <compiler/core.h> |
| 4 | #include <compiler/diagnostic.h> |
| 5 | #include <compiler/intrinsic.h> |
| 6 | |
| 7 | #define alloc_params_with_defaults(_flags, _behavior, ...) \ |
| 8 | cc_wno_override_init_expr( \ |
| 9 | struct alloc_params, \ |
| 10 | ((struct alloc_params) {.flags = (_flags), \ |
| 11 | .behavior = (_behavior), \ |
| 12 | .priority = ALLOC_PRIORITY_DEFAULT, \ |
| 13 | ##__VA_ARGS__})) |
| 14 | |
| 15 | #define vfree_1(ptr) vfree_2((ptr), ALLOC_BEHAVIOR_DEFAULT) |
| 16 | #define vfree_2(ptr, bh) vfree_full((ptr), (bh)) |
| 17 | |
| 18 | #define vfree(...) PP_CALL(vfree, __VA_ARGS__) |
| 19 | |
| 20 | #define valloc(size, ...) \ |
| 21 | valloc_full((size), alloc_params_with_defaults(ALLOC_FLAGS_DEFAULT, \ |
| 22 | ALLOC_BEHAVIOR_DEFAULT, \ |
| 23 | ##__VA_ARGS__)) |
| 24 | |
| 25 | #define valloc_aligned(size, align, ...) \ |
| 26 | valloc_aligned_full((size), (align), \ |
| 27 | alloc_params_with_defaults(ALLOC_FLAGS_DEFAULT, \ |
| 28 | ALLOC_BEHAVIOR_DEFAULT, \ |
| 29 | ##__VA_ARGS__)) |
| 30 | |
| 31 | /* struct foo *f = vnew(f, ALLOC_ZERO) */ |
| 32 | #define VNEW_PTR(p) typeof(&*(p)) |
| 33 | #define VNEW_CHECK(p) \ |
| 34 | static_assert( \ |
| 35 | __builtin_types_compatible_p(__typeof_unqual__(p), typeof(&*(p))), \ |
| 36 | "vnew: target must be a pointer lvalue, not an array"); \ |
| 37 | static_assert(!cc_generic((p), void * : 1, const void * : 1, \ |
| 38 | volatile void * : 1, const volatile void * : 1, \ |
| 39 | default : 0), \ |
| 40 | "vnew: void pointer target, use valloc() with a size") |
| 41 | |
| 42 | #define vnew(p, ...) \ |
| 43 | ({ \ |
| 44 | VNEW_CHECK(p); \ |
| 45 | (VNEW_PTR(p)) valloc(sizeof(*(p)), ##__VA_ARGS__); \ |
| 46 | }) |
| 47 | |
| 48 | /* struct foo *arr = vnews(arr, count, ALLOC_ZERO); */ |
| 49 | #define vnews(p, n, ...) \ |
| 50 | ({ \ |
| 51 | VNEW_CHECK(p); \ |
| 52 | size_t _vn_bytes_; \ |
| 53 | ci_mul_overflow((n), sizeof(*(p)), &_vn_bytes_) \ |
| 54 | ? (VNEW_PTR(p)) NULL \ |
| 55 | : (VNEW_PTR(p)) valloc(_vn_bytes_, ##__VA_ARGS__); \ |
| 56 | }) |
| 57 | |
| 58 | #if cn_has_builtin(__builtin_counted_by_ref) |
| 59 | #define VNEW_FLEX_COUNTER(q, member) \ |
| 60 | _Generic(__builtin_counted_by_ref((q)->member), \ |
| 61 | void *: &(size_t) {0}, \ |
| 62 | default: __builtin_counted_by_ref((q)->member)) |
| 63 | #else |
| 64 | #define VNEW_FLEX_COUNTER(q, member) (&(size_t) {0}) |
| 65 | #endif |
| 66 | |
| 67 | /* struct pkt { uint32_t len; uint8_t data[] cc_counted_by(len); }; |
| 68 | * struct pkt *pkt = vnew_flex(pkt, data, len, ALLOC_ZERO); |
| 69 | * |
| 70 | * pkt->len = len when data is counted_by or NULL if len doesn't fit it */ |
| 71 | #define vnew_flex(p, member, n, ...) \ |
| 72 | ({ \ |
| 73 | VNEW_CHECK(p); \ |
| 74 | static_assert( \ |
| 75 | !__builtin_types_compatible_p(__typeof_unqual__((p)->member), \ |
| 76 | typeof(&(p)->member[0])), \ |
| 77 | "vnew_flex: member must be an array, not a pointer"); \ |
| 78 | size_t _vf_tail_, _vf_bytes_; \ |
| 79 | __typeof_unqual__(*VNEW_FLEX_COUNTER(p, member)) _vf_count_; \ |
| 80 | VNEW_PTR(p) _vf_q_ = NULL; \ |
| 81 | if (!ci_add_overflow((n), 0, &_vf_count_) && \ |
| 82 | !ci_mul_overflow((n), sizeof((p)->member[0]), &_vf_tail_) && \ |
| 83 | !ci_add_overflow(sizeof(*(p)), _vf_tail_, &_vf_bytes_)) { \ |
| 84 | _vf_q_ = (VNEW_PTR(p)) valloc(_vf_bytes_, ##__VA_ARGS__); \ |
| 85 | if (_vf_q_) \ |
| 86 | *VNEW_FLEX_COUNTER(_vf_q_, member) = _vf_count_; \ |
| 87 | } \ |
| 88 | _vf_q_; \ |
| 89 | }) |
| 90 | |
| 91 | #define vfree_aligned_1(ptr) vfree_aligned_2((ptr), ALLOC_BEHAVIOR_DEFAULT) |
| 92 | #define vfree_aligned_2(ptr, bh) vfree_aligned_full((ptr), (bh)) |
| 93 | #define vfree_aligned(...) PP_CALL(vfree_aligned, __VA_ARGS__) |
| 94 | |
| 95 | #define vrealloc(ptr, size, ...) \ |
| 96 | vrealloc_full((ptr), (size), \ |
| 97 | alloc_params_with_defaults(ALLOC_FLAGS_DEFAULT, \ |
| 98 | ALLOC_BEHAVIOR_DEFAULT, \ |
| 99 | ##__VA_ARGS__)) |
| 100 | |
| 101 | /* void **grown = vrenews(node->pages, needed); */ |
| 102 | #define vrenews(old, n, ...) \ |
| 103 | ({ \ |
| 104 | VNEW_CHECK(old); \ |
| 105 | VNEW_PTR(old) _vr_old_ = (old); \ |
| 106 | size_t _vr_bytes_; \ |
| 107 | ci_mul_overflow((n), sizeof(*_vr_old_), &_vr_bytes_) \ |
| 108 | ? (VNEW_PTR(old)) NULL \ |
| 109 | : (VNEW_PTR(old)) vrealloc(_vr_old_, _vr_bytes_, ##__VA_ARGS__); \ |
| 110 | }) |
| 111 | |