1 /* vifm
2  * Copyright (C) 2015 xaizek.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18 
19 #ifndef VIFM__UTILS__DARRAY_H__
20 #define VIFM__UTILS__DARRAY_H__
21 
22 /* Simple macros that wrap common operations on dynamic arrays. */
23 
24 #include <assert.h> /* assert() */
25 #include <stddef.h> /* ptrdiff_t size_t */
26 #include <stdlib.h> /* free() */
27 #include <string.h> /* memcpy() */
28 
29 #include "../compat/reallocarray.h"
30 
31 /* Instantiates additional data for dynamic array implementation.  Usage
32  * example:
33  *   static int *array;
34  *   static DA_INSTANCE(array); */
35 #define DA_INSTANCE(da) DA_INSTANCE_FIELD(da) = 0U
36 
37 /* DA_INSTANCE equivalent for structures. */
38 #define DA_INSTANCE_FIELD(da) size_t da##_count__
39 
40 /* Obtains lvalue of array size, its type is size_t. */
41 #define DA_SIZE(da) *(&da##_count__)
42 
43 /* Extends array capacity (not size) by at least one more element.  Returns
44  * pointer to the element or NULL on memory allocation error.  Once element data
45  * is successfully initialized DA_COMMIT should be used to update size. */
46 #define DA_EXTEND(da) \
47 	({ \
48 		typeof(da) last = NULL; \
49 		void *const ptr = reallocarray(da, da##_count__ + 1U, sizeof(*da)); \
50 		if(ptr != NULL) \
51 		{ \
52 			da = ptr; \
53 			last = &da[da##_count__]; \
54 		} \
55 		last; \
56 	})
57 
58 /* Increments array size, to be used in pair with DA_EXTEND.  Usage example:
59  *   char **const string = DA_EXTEND(strings);
60  *   if(string != NULL)
61  *   {
62  *     *string = strdup(str);
63  *     if(*string != NULL)
64  *     {
65  *       DA_COMMIT(strings);
66  *     }
67  *   } */
68 #define DA_COMMIT(a) do { ++a##_count__; } while(0)
69 
70 /* Removes item specified by pointer. */
71 #define DA_REMOVE(da, item) \
72 	do \
73 	{ \
74 		const typeof(da) it = item; \
75 		size_t i; \
76 		assert(it >= da && "Wrong item pointer."); \
77 		assert(it - da < (ptrdiff_t)da##_count__ && "Wrong item pointer."); \
78 		for(i = it - da + 1U; i < da##_count__; ++i) \
79 		{ \
80 			memcpy(&da[i - 1], &da[i], sizeof(*da)); \
81 		} \
82 		if(--da##_count__ == 0) \
83 		{ \
84 			free(da); \
85 			da = NULL; \
86 		} \
87 	} \
88 	while(0)
89 
90 /* Removes all elements starting from and including the item. */
91 #define DA_REMOVE_AFTER(da, item) \
92 	do \
93 	{ \
94 		const typeof(da) it = item; \
95 		assert(it >= da && "Wrong item pointer."); \
96 		assert(it - da <= (ptrdiff_t)da##_count__ && "Wrong item pointer."); \
97 		da##_count__ = it - da; \
98 		if(da##_count__ == 0) \
99 		{ \
100 			free(da); \
101 			da = NULL; \
102 		} \
103 	} \
104 	while(0)
105 
106 /* Empties the array freeing allocated memory. */
107 #define DA_REMOVE_ALL(da) \
108 	do \
109 	{ \
110 		da##_count__ = 0; \
111 		free(da); \
112 		da = NULL; \
113 	} \
114 	while(0)
115 
116 #endif /* VIFM__UTILS__DARRAY_H__ */
117 
118 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
119 /* vim: set cinoptions+=t0 filetype=c : */
120