1#pragma once
2
3#include <uacpi/types.h>
4#include <uacpi/internal/stdlib.h>
5#include <uacpi/kernel_api.h>
6
7#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE(name, type, inline_capacity) \
8 struct name { \
9 type inline_storage[inline_capacity]; \
10 type *dynamic_storage; \
11 uacpi_size dynamic_capacity; \
12 uacpi_size size_including_inline; \
13 }; \
14
15#define DYNAMIC_ARRAY_SIZE(arr) ((arr)->size_including_inline)
16
17#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE_EXPORTS(name, type, prefix) \
18 prefix uacpi_size name##_inline_capacity(struct name *arr); \
19 prefix type *name##_at(struct name *arr, uacpi_size idx); \
20 prefix type *name##_alloc(struct name *arr); \
21 prefix type *name##_calloc(struct name *arr); \
22 prefix void name##_pop(struct name *arr); \
23 prefix uacpi_size name##_size(struct name *arr); \
24 prefix type *name##_last(struct name *arr) \
25 prefix void name##_clear(struct name *arr);
26
27#define DYNAMIC_ARRAY_WITH_INLINE_STORAGE_IMPL(name, type, prefix) \
28 UACPI_MAYBE_UNUSED \
29 prefix uacpi_size name##_inline_capacity(struct name *arr) \
30 { \
31 return sizeof(arr->inline_storage) / sizeof(arr->inline_storage[0]); \
32 } \
33 \
34 prefix type *name##_at(struct name *arr, uacpi_size idx) \
35 { \
36 if (idx >= arr->size_including_inline) \
37 return UACPI_NULL; \
38 \
39 if (idx < name##_inline_capacity(arr)) \
40 return &arr->inline_storage[idx]; \
41 \
42 return &arr->dynamic_storage[idx - name##_inline_capacity(arr)]; \
43 } \
44 \
45 UACPI_MAYBE_UNUSED \
46 prefix type *name##_alloc(struct name *arr) \
47 { \
48 uacpi_size inline_cap; \
49 type *out_ptr; \
50 \
51 inline_cap = name##_inline_capacity(arr); \
52 \
53 if (arr->size_including_inline >= inline_cap) { \
54 uacpi_size dynamic_size; \
55 \
56 dynamic_size = arr->size_including_inline - inline_cap; \
57 if (dynamic_size == arr->dynamic_capacity) { \
58 uacpi_size bytes, type_size; \
59 void *new_buf; \
60 \
61 type_size = sizeof(*arr->dynamic_storage); \
62 bytes = arr->dynamic_capacity * type_size; \
63 bytes += type_size; \
64 \
65 new_buf = uacpi_kernel_alloc(bytes); \
66 if (!new_buf) \
67 return NULL; \
68 arr->dynamic_capacity = bytes / type_size; \
69 \
70 if (arr->dynamic_storage) { \
71 uacpi_memcpy(new_buf, arr->dynamic_storage, \
72 dynamic_size * type_size); \
73 } \
74 uacpi_free(arr->dynamic_storage, dynamic_size * type_size); \
75 arr->dynamic_storage = new_buf; \
76 } \
77 \
78 out_ptr = &arr->dynamic_storage[dynamic_size]; \
79 goto ret; \
80 } \
81 \
82 \
83 out_ptr = &arr->inline_storage[arr->size_including_inline]; \
84 \
85 ret: \
86 arr->size_including_inline++; \
87 return out_ptr; \
88 } \
89 \
90 UACPI_MAYBE_UNUSED \
91 prefix type *name##_calloc(struct name *arr) \
92 { \
93 type *ret; \
94 \
95 ret = name##_alloc(arr); \
96 if (ret) \
97 uacpi_memzero(ret, sizeof(*ret)); \
98 \
99 return ret; \
100 } \
101 \
102 UACPI_MAYBE_UNUSED \
103 prefix void name##_pop(struct name *arr) \
104 { \
105 if (arr->size_including_inline == 0) \
106 return; \
107 \
108 arr->size_including_inline--; \
109 } \
110 \
111 UACPI_MAYBE_UNUSED \
112 prefix uacpi_size name##_size(struct name *arr) \
113 { \
114 return arr->size_including_inline; \
115 } \
116 \
117 UACPI_MAYBE_UNUSED \
118 prefix type *name##_last(struct name *arr) \
119 { \
120 return name##_at(arr, arr->size_including_inline - 1); \
121 } \
122 \
123 prefix void name##_clear(struct name *arr) \
124 { \
125 uacpi_free( \
126 arr->dynamic_storage, \
127 arr->dynamic_capacity * sizeof(*arr->dynamic_storage) \
128 ); \
129 arr->size_including_inline = 0; \
130 arr->dynamic_capacity = 0; \
131 }
132