xref: /linux/fs/bcachefs/darray.h (revision ff0905bbf991f4337b5ebc19c0d43525ebb0d96b)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _BCACHEFS_DARRAY_H
3 #define _BCACHEFS_DARRAY_H
4 
5 /*
6  * Dynamic arrays:
7  *
8  * Inspired by CCAN's darray
9  */
10 
11 #include <linux/cleanup.h>
12 #include <linux/slab.h>
13 
14 #define DARRAY_PREALLOCATED(_type, _nr)					\
15 struct {								\
16 	size_t nr, size;						\
17 	_type *data;							\
18 	_type preallocated[_nr];					\
19 }
20 
21 #define DARRAY(_type) DARRAY_PREALLOCATED(_type, 0)
22 
23 typedef DARRAY(char)	darray_char;
24 typedef DARRAY(char *)	darray_str;
25 typedef DARRAY(const char *) darray_const_str;
26 
27 typedef DARRAY(u8)	darray_u8;
28 typedef DARRAY(u16)	darray_u16;
29 typedef DARRAY(u32)	darray_u32;
30 typedef DARRAY(u64)	darray_u64;
31 
32 typedef DARRAY(s8)	darray_s8;
33 typedef DARRAY(s16)	darray_s16;
34 typedef DARRAY(s32)	darray_s32;
35 typedef DARRAY(s64)	darray_s64;
36 
37 int __bch2_darray_resize_noprof(darray_char *, size_t, size_t, gfp_t);
38 
39 #define __bch2_darray_resize(...)	alloc_hooks(__bch2_darray_resize_noprof(__VA_ARGS__))
40 
41 #define __darray_resize(_d, _element_size, _new_size, _gfp)		\
42 	(unlikely((_new_size) > (_d)->size)				\
43 	 ? __bch2_darray_resize((_d), (_element_size), (_new_size), (_gfp))\
44 	 : 0)
45 
46 #define darray_resize_gfp(_d, _new_size, _gfp)				\
47 	__darray_resize((darray_char *) (_d), sizeof((_d)->data[0]), (_new_size), _gfp)
48 
49 #define darray_resize(_d, _new_size)					\
50 	darray_resize_gfp(_d, _new_size, GFP_KERNEL)
51 
52 #define darray_make_room_gfp(_d, _more, _gfp)				\
53 	darray_resize_gfp((_d), (_d)->nr + (_more), _gfp)
54 
55 #define darray_make_room(_d, _more)					\
56 	darray_make_room_gfp(_d, _more, GFP_KERNEL)
57 
58 #define darray_room(_d)		((_d).size - (_d).nr)
59 
60 #define darray_top(_d)		((_d).data[(_d).nr])
61 
62 #define darray_push_gfp(_d, _item, _gfp)				\
63 ({									\
64 	int _ret = darray_make_room_gfp((_d), 1, _gfp);			\
65 									\
66 	if (!_ret)							\
67 		(_d)->data[(_d)->nr++] = (_item);			\
68 	_ret;								\
69 })
70 
71 #define darray_push(_d, _item)	darray_push_gfp(_d, _item, GFP_KERNEL)
72 
73 #define darray_pop(_d)		((_d)->data[--(_d)->nr])
74 
75 #define darray_first(_d)	((_d).data[0])
76 #define darray_last(_d)		((_d).data[(_d).nr - 1])
77 
78 #define darray_insert_item(_d, pos, _item)				\
79 ({									\
80 	size_t _pos = (pos);						\
81 	int _ret = darray_make_room((_d), 1);				\
82 									\
83 	if (!_ret)							\
84 		array_insert_item((_d)->data, (_d)->nr, _pos, (_item));	\
85 	_ret;								\
86 })
87 
88 #define darray_remove_item(_d, _pos)					\
89 	array_remove_item((_d)->data, (_d)->nr, (_pos) - (_d)->data)
90 
91 #define darray_find_p(_d, _i, cond)					\
92 ({									\
93 	typeof((_d).data) _ret = NULL;					\
94 									\
95 	darray_for_each(_d, _i)						\
96 		if (cond) {						\
97 			_ret = _i;					\
98 			break;						\
99 		}							\
100 	_ret;								\
101 })
102 
103 #define darray_find(_d, _item)	darray_find_p(_d, _i, *_i == _item)
104 
105 /* Iteration: */
106 
107 #define __darray_for_each(_d, _i)					\
108 	for ((_i) = (_d).data; _i < (_d).data + (_d).nr; _i++)
109 
110 #define darray_for_each(_d, _i)						\
111 	for (typeof(&(_d).data[0]) _i = (_d).data; _i < (_d).data + (_d).nr; _i++)
112 
113 #define darray_for_each_reverse(_d, _i)					\
114 	for (typeof(&(_d).data[0]) _i = (_d).data + (_d).nr - 1; _i >= (_d).data && (_d).nr; --_i)
115 
116 /* Init/exit */
117 
118 #define darray_init(_d)							\
119 do {									\
120 	(_d)->nr = 0;							\
121 	(_d)->size = ARRAY_SIZE((_d)->preallocated);			\
122 	(_d)->data = (_d)->size ? (_d)->preallocated : NULL;		\
123 } while (0)
124 
125 #define darray_exit(_d)							\
126 do {									\
127 	if (!ARRAY_SIZE((_d)->preallocated) ||				\
128 	    (_d)->data != (_d)->preallocated)				\
129 		kvfree((_d)->data);					\
130 	darray_init(_d);						\
131 } while (0)
132 
133 #define DEFINE_DARRAY_CLASS(_type)					\
134 DEFINE_CLASS(_type, _type, darray_exit(&(_T)), (_type) {}, void)
135 
136 #define DEFINE_DARRAY(_type)						\
137 typedef DARRAY(_type)	darray_##_type;					\
138 DEFINE_DARRAY_CLASS(darray_##_type)
139 
140 #define DEFINE_DARRAY_NAMED(_name, _type)				\
141 typedef DARRAY(_type)	_name;						\
142 DEFINE_DARRAY_CLASS(_name)
143 
144 DEFINE_DARRAY_CLASS(darray_char);
145 DEFINE_DARRAY_CLASS(darray_str)
146 DEFINE_DARRAY_CLASS(darray_const_str)
147 
148 DEFINE_DARRAY_CLASS(darray_u8)
149 DEFINE_DARRAY_CLASS(darray_u16)
150 DEFINE_DARRAY_CLASS(darray_u32)
151 DEFINE_DARRAY_CLASS(darray_u64)
152 
153 DEFINE_DARRAY_CLASS(darray_s8)
154 DEFINE_DARRAY_CLASS(darray_s16)
155 DEFINE_DARRAY_CLASS(darray_s32)
156 DEFINE_DARRAY_CLASS(darray_s64)
157 
158 #endif /* _BCACHEFS_DARRAY_H */
159