1 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
2 
3 #include "lib.h"
4 #include "array.h"
5 
6 
7 void *
array_idx_modifiable_i(const struct array * array,unsigned int idx)8 array_idx_modifiable_i(const struct array *array, unsigned int idx)
9 {
10 	i_assert(idx < array->buffer->used / array->element_size);
11 	return PTR_OFFSET(array->buffer->data, idx * array->element_size);
12 }
13 
array_idx_get_space_i(struct array * array,unsigned int idx)14 void *array_idx_get_space_i(struct array *array, unsigned int idx)
15 {
16 	return buffer_get_space_unsafe(array->buffer, idx * array->element_size,
17 				       array->element_size);
18 }
19 
array_idx_set_i(struct array * array,unsigned int idx,const void * data)20 void array_idx_set_i(struct array *array, unsigned int idx, const void *data)
21 {
22 	buffer_write(array->buffer, idx * array->element_size,
23 		     data, array->element_size);
24 }
25 
array_idx_clear_i(struct array * array,unsigned int idx)26 void array_idx_clear_i(struct array *array, unsigned int idx)
27 {
28 	buffer_write_zero(array->buffer, idx * array->element_size,
29 			  array->element_size);
30 }
31 
array_insert_space_i(struct array * array,unsigned int idx)32 void *array_insert_space_i(struct array *array, unsigned int idx)
33 {
34 	void *data;
35 	size_t pos;
36 
37 	pos = idx * array->element_size;
38 	buffer_copy(array->buffer, pos + array->element_size,
39 		    array->buffer, pos, SIZE_MAX);
40 
41 	data = buffer_get_space_unsafe(array->buffer, pos, array->element_size);
42 	memset(data, 0, array->element_size);
43 	return data;
44 }
45 
array_cmp_i(const struct array * array1,const struct array * array2)46 bool array_cmp_i(const struct array *array1, const struct array *array2)
47 {
48 	if (!array_is_created_i(array1) || array1->buffer->used == 0)
49 		return !array_is_created_i(array2) || array2->buffer->used == 0;
50 
51 	if (!array_is_created_i(array2))
52 		return FALSE;
53 
54 	return buffer_cmp(array1->buffer, array2->buffer);
55 }
56 
array_equal_fn_i(const struct array * array1,const struct array * array2,int (* cmp)(const void *,const void *))57 bool array_equal_fn_i(const struct array *array1, const struct array *array2,
58 		      int (*cmp)(const void *, const void*))
59 {
60 	unsigned int count1, count2, i;
61 	size_t size;
62 
63 	if (!array_is_created_i(array1) || array1->buffer->used == 0)
64 		return !array_is_created_i(array2) || array2->buffer->used == 0;
65 
66 	if (!array_is_created_i(array2))
67 		return FALSE;
68 
69 	count1 = array_count_i(array1); count2 = array_count_i(array2);
70 	if (count1 != count2)
71 		return FALSE;
72 
73 	size = array1->element_size;
74 	i_assert(size == array2->element_size);
75 
76 	for (i = 0; i < count1; i++) {
77 		if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
78 			CONST_PTR_OFFSET(array2->buffer->data, i * size)) != 0)
79 			return FALSE;
80 	}
81 	return TRUE;
82 }
83 
array_equal_fn_ctx_i(const struct array * array1,const struct array * array2,int (* cmp)(const void *,const void *,const void *),const void * context)84 bool array_equal_fn_ctx_i(const struct array *array1, const struct array *array2,
85 			  int (*cmp)(const void *, const void *, const void *),
86 			  const void *context)
87 {
88 	unsigned int count1, count2, i;
89 	size_t size;
90 
91 	if (!array_is_created_i(array1) || array1->buffer->used == 0)
92 		return !array_is_created_i(array2) || array2->buffer->used == 0;
93 
94 	if (!array_is_created_i(array2))
95 		return FALSE;
96 
97 	count1 = array_count_i(array1); count2 = array_count_i(array2);
98 	if (count1 != count2)
99 		return FALSE;
100 
101 	size = array1->element_size;
102 	i_assert(size == array2->element_size);
103 
104 	for (i = 0; i < count1; i++) {
105 		if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
106 			CONST_PTR_OFFSET(array2->buffer->data, i * size), context) != 0)
107 			return FALSE;
108 	}
109 	return TRUE;
110 }
111 
array_reverse_i(struct array * array)112 void array_reverse_i(struct array *array)
113 {
114 	const size_t element_size = array->element_size;
115 	unsigned int i, count = array_count_i(array);
116 	size_t size;
117 	void *data, *tmp;
118 
119 	data = buffer_get_modifiable_data(array->buffer, &size);
120 	tmp = t_buffer_get(array->element_size);
121 	for (i = 0; i+1 < count; i++, count--) {
122 		memcpy(tmp, PTR_OFFSET(data, i * element_size), element_size);
123 		memcpy(PTR_OFFSET(data, i * element_size),
124 		       PTR_OFFSET(data, (count-1) * element_size),
125 		       element_size);
126 		memcpy(PTR_OFFSET(data, (count-1) * element_size), tmp,
127 		       element_size);
128 	}
129 }
130 
array_sort_i(struct array * array,int (* cmp)(const void *,const void *))131 void array_sort_i(struct array *array, int (*cmp)(const void *, const void *))
132 {
133 	unsigned int count;
134 
135 	count = array_count_i(array);
136 	if (count == 0)
137 		return;
138 	qsort(buffer_get_modifiable_data(array->buffer, NULL),
139 	      count, array->element_size, cmp);
140 }
141 
array_bsearch_i(struct array * array,const void * key,int (* cmp)(const void *,const void *))142 void *array_bsearch_i(struct array *array, const void *key,
143 		     int (*cmp)(const void *, const void *))
144 {
145 	unsigned int count;
146 
147 	count = array_count_i(array);
148 	return bsearch(key, array->buffer->data,
149 		       count, array->element_size, cmp);
150 }
151 
array_lsearch_i(const struct array * array,const void * key,int (* cmp)(const void *,const void *))152 const void *array_lsearch_i(const struct array *array, const void *key,
153 			    int (*cmp)(const void *, const void *))
154 {
155 	const void * const data = array->buffer->data;
156 	const size_t s = array->element_size;
157 	unsigned int idx;
158 
159 	for (idx = 0; idx < array_count_i(array); idx++) {
160 		if (cmp(key, CONST_PTR_OFFSET(data, idx * s)) == 0) {
161 			return PTR_OFFSET(data, idx * s);
162 		}
163 	}
164 
165 	return NULL;
166 }
167