1 | // Copyright (c) Microsoft. All rights reserved.
|
---|
2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
---|
3 |
|
---|
4 | #include <stdlib.h>
|
---|
5 | #include "azure_c_shared_utility/gballoc.h"
|
---|
6 | #include "azure_c_shared_utility/vector.h"
|
---|
7 | #include "azure_c_shared_utility/optimize_size.h"
|
---|
8 | #include "azure_c_shared_utility/xlogging.h"
|
---|
9 |
|
---|
10 | #include "azure_c_shared_utility/vector_types_internal.h"
|
---|
11 |
|
---|
12 | IMPLEMENT_MOCKABLE_FUNCTION(, VECTOR_HANDLE, VECTOR_create, size_t, elementSize)
|
---|
13 | {
|
---|
14 | VECTOR_HANDLE result;
|
---|
15 |
|
---|
16 | /* Codes_SRS_VECTOR_10_002: [VECTOR_create shall fail and return NULL if elementsize is 0.] */
|
---|
17 | if (elementSize == 0)
|
---|
18 | {
|
---|
19 | LogError("invalid elementSize(%zd).", elementSize);
|
---|
20 | result = NULL;
|
---|
21 | }
|
---|
22 | else
|
---|
23 | {
|
---|
24 | result = (VECTOR*)malloc(sizeof(VECTOR));
|
---|
25 | /* Codes_SRS_VECTOR_10_002 : [VECTOR_create shall fail and return NULL if malloc fails.] */
|
---|
26 | if (result == NULL)
|
---|
27 | {
|
---|
28 | LogError("malloc failed.");
|
---|
29 | }
|
---|
30 | else
|
---|
31 | {
|
---|
32 | /* Codes_SRS_VECTOR_10_001: [VECTOR_create shall allocate a VECTOR_HANDLE that will contain an empty vector.The size of each element is given with the parameter elementSize.] */
|
---|
33 | result->storage = NULL;
|
---|
34 | result->count = 0;
|
---|
35 | result->elementSize = elementSize;
|
---|
36 | }
|
---|
37 | }
|
---|
38 | return result;
|
---|
39 | }
|
---|
40 |
|
---|
41 | IMPLEMENT_MOCKABLE_FUNCTION(, void, VECTOR_destroy, VECTOR_HANDLE, handle)
|
---|
42 | {
|
---|
43 | /* Codes_SRS_VECTOR_10_009: [VECTOR_destroy shall return if the given handle is NULL.] */
|
---|
44 | if (handle == NULL)
|
---|
45 | {
|
---|
46 | LogError("invalid argument handle(NULL).");
|
---|
47 | }
|
---|
48 | else
|
---|
49 | {
|
---|
50 | /* Codes_SRS_VECTOR_10_008: [VECTOR_destroy shall free the given handle and its internal storage.] */
|
---|
51 | free(handle->storage);
|
---|
52 | free(handle);
|
---|
53 | }
|
---|
54 | }
|
---|
55 |
|
---|
56 | IMPLEMENT_MOCKABLE_FUNCTION(, VECTOR_HANDLE, VECTOR_move, VECTOR_HANDLE, handle)
|
---|
57 | {
|
---|
58 | VECTOR_HANDLE result;
|
---|
59 | if (handle == NULL)
|
---|
60 | {
|
---|
61 | /* Codes_SRS_VECTOR_10_005: [VECTOR_move shall fail and return NULL if the given handle is NULL.] */
|
---|
62 | LogError("invalid argument - handle(NULL).");
|
---|
63 | result = NULL;
|
---|
64 | }
|
---|
65 | else
|
---|
66 | {
|
---|
67 | result = (VECTOR*)malloc(sizeof(VECTOR));
|
---|
68 | if (result == NULL)
|
---|
69 | {
|
---|
70 | /* Codes_SRS_VECTOR_10_006: [VECTOR_move shall fail and return NULL if malloc fails.] */
|
---|
71 | LogError("malloc failed.");
|
---|
72 | }
|
---|
73 | else
|
---|
74 | {
|
---|
75 | /* Codes_SRS_VECTOR_10_004: [VECTOR_move shall allocate a VECTOR_HANDLE and move the data to it from the given handle.] */
|
---|
76 | result->count = handle->count;
|
---|
77 | result->elementSize = handle->elementSize;
|
---|
78 | result->storage = handle->storage;
|
---|
79 |
|
---|
80 | handle->storage = NULL;
|
---|
81 | handle->count = 0;
|
---|
82 | }
|
---|
83 | }
|
---|
84 | return result;
|
---|
85 | }
|
---|
86 |
|
---|
87 | /* insertion */
|
---|
88 |
|
---|
89 | IMPLEMENT_MOCKABLE_FUNCTION(, int, VECTOR_push_back, VECTOR_HANDLE, handle, const void*, elements, size_t, numElements)
|
---|
90 | {
|
---|
91 | int result;
|
---|
92 | if (handle == NULL || elements == NULL || numElements == 0)
|
---|
93 | {
|
---|
94 | /* Codes_SRS_VECTOR_10_011: [VECTOR_push_back shall fail and return non-zero if handle is NULL.] */
|
---|
95 | /* Codes_SRS_VECTOR_10_034: [VECTOR_push_back shall fail and return non-zero if elements is NULL.] */
|
---|
96 | /* Codes_SRS_VECTOR_10_035: [VECTOR_push_back shall fail and return non-zero if numElements is 0.] */
|
---|
97 | LogError("invalid argument - handle(%p), elements(%p), numElements(%zd).", handle, elements, numElements);
|
---|
98 | result = MU_FAILURE;
|
---|
99 | }
|
---|
100 | else
|
---|
101 | {
|
---|
102 | size_t curSize = handle->elementSize * handle->count;
|
---|
103 | size_t appendSize = handle->elementSize * numElements;
|
---|
104 |
|
---|
105 | void* temp = realloc(handle->storage, curSize + appendSize);
|
---|
106 | if (temp == NULL)
|
---|
107 | {
|
---|
108 | /* Codes_SRS_VECTOR_10_012: [VECTOR_push_back shall fail and return non-zero if memory allocation fails.] */
|
---|
109 | LogError("realloc failed.");
|
---|
110 | result = MU_FAILURE;
|
---|
111 | }
|
---|
112 | else
|
---|
113 | {
|
---|
114 | /* Codes_SRS_VECTOR_10_013: [VECTOR_push_back shall append the given elements and return 0 indicating success.] */
|
---|
115 | (void)memcpy((unsigned char*)temp + curSize, elements, appendSize);
|
---|
116 | handle->storage = temp;
|
---|
117 | handle->count += numElements;
|
---|
118 | result = 0;
|
---|
119 | }
|
---|
120 | }
|
---|
121 | return result;
|
---|
122 | }
|
---|
123 |
|
---|
124 | /* removal */
|
---|
125 |
|
---|
126 | IMPLEMENT_MOCKABLE_FUNCTION(, void, VECTOR_erase, VECTOR_HANDLE, handle, void*, elements, size_t, numElements)
|
---|
127 | {
|
---|
128 | if (handle == NULL || elements == NULL || numElements == 0)
|
---|
129 | {
|
---|
130 | /* Codes_SRS_VECTOR_10_015: [VECTOR_erase shall return if handle is NULL.] */
|
---|
131 | /* Codes_SRS_VECTOR_10_038: [VECTOR_erase shall return if elements is NULL.] */
|
---|
132 | /* Codes_SRS_VECTOR_10_039: [VECTOR_erase shall return if numElements is 0.] */
|
---|
133 | LogError("invalid argument - handle(%p), elements(%p), numElements(%zd).", handle, elements, numElements);
|
---|
134 | }
|
---|
135 | else
|
---|
136 | {
|
---|
137 | if (elements < handle->storage)
|
---|
138 | {
|
---|
139 | /* Codes_SRS_VECTOR_10_040: [VECTOR_erase shall return if elements is out of bound.] */
|
---|
140 | LogError("invalid argument elements(%p) is not a member of this object.", elements);
|
---|
141 | }
|
---|
142 | else
|
---|
143 | {
|
---|
144 | ptrdiff_t diff = ((unsigned char*)elements) - ((unsigned char*)handle->storage);
|
---|
145 | if ((diff % handle->elementSize) != 0)
|
---|
146 | {
|
---|
147 | /* Codes_SRS_VECTOR_10_041: [VECTOR_erase shall return if elements is misaligned.] */
|
---|
148 | LogError("invalid argument - elements(%p) is misaligned", elements);
|
---|
149 | }
|
---|
150 | else
|
---|
151 | {
|
---|
152 | /* Compute the arguments needed for memmove. */
|
---|
153 | unsigned char* src = (unsigned char*)elements + (handle->elementSize * numElements);
|
---|
154 | unsigned char* srcEnd = (unsigned char*)handle->storage + (handle->elementSize * handle->count);
|
---|
155 | if (src > srcEnd)
|
---|
156 | {
|
---|
157 | /* Codes_SRS_VECTOR_10_040: [VECTOR_erase shall return if elements is out of bound.] */
|
---|
158 | LogError("invalid argument - numElements(%zd) is out of bound.", numElements);
|
---|
159 | }
|
---|
160 | else
|
---|
161 | {
|
---|
162 | /* Codes_SRS_VECTOR_10_014: [VECTOR_erase shall remove the 'numElements' starting at 'elements' and reduce its internal storage.] */
|
---|
163 | handle->count -= numElements;
|
---|
164 | if (handle->count == 0)
|
---|
165 | {
|
---|
166 | free(handle->storage);
|
---|
167 | handle->storage = NULL;
|
---|
168 | }
|
---|
169 | else
|
---|
170 | {
|
---|
171 | void* tmp;
|
---|
172 | (void)memmove(elements, src, srcEnd - src);
|
---|
173 | tmp = realloc(handle->storage, (handle->elementSize * handle->count));
|
---|
174 | if (tmp == NULL)
|
---|
175 | {
|
---|
176 | LogInfo("realloc failed. Keeping original internal storage pointer.");
|
---|
177 | }
|
---|
178 | else
|
---|
179 | {
|
---|
180 | handle->storage = tmp;
|
---|
181 | }
|
---|
182 | }
|
---|
183 | }
|
---|
184 | }
|
---|
185 | }
|
---|
186 | }
|
---|
187 | }
|
---|
188 |
|
---|
189 | IMPLEMENT_MOCKABLE_FUNCTION(, void, VECTOR_clear, VECTOR_HANDLE, handle)
|
---|
190 | {
|
---|
191 | /* Codes_SRS_VECTOR_10_017: [VECTOR_clear shall if the object is NULL or empty.] */
|
---|
192 | if (handle == NULL)
|
---|
193 | {
|
---|
194 | LogError("invalid argument handle(NULL).");
|
---|
195 | }
|
---|
196 | else
|
---|
197 | {
|
---|
198 | /* Codes_SRS_VECTOR_10_016: [VECTOR_clear shall remove all elements from the object and release internal storage.] */
|
---|
199 | free(handle->storage);
|
---|
200 | handle->storage = NULL;
|
---|
201 | handle->count = 0;
|
---|
202 | }
|
---|
203 | }
|
---|
204 |
|
---|
205 | /* access */
|
---|
206 |
|
---|
207 | IMPLEMENT_MOCKABLE_FUNCTION(, void*, VECTOR_element, VECTOR_HANDLE, handle, size_t, index)
|
---|
208 | {
|
---|
209 | void* result;
|
---|
210 | if (handle == NULL)
|
---|
211 | {
|
---|
212 | /* Codes_SRS_VECTOR_10_019: [VECTOR_element shall fail and return NULL if handle is NULL.] */
|
---|
213 | LogError("invalid argument handle(NULL).");
|
---|
214 | result = NULL;
|
---|
215 | }
|
---|
216 | else
|
---|
217 | {
|
---|
218 | if (index >= handle->count)
|
---|
219 | {
|
---|
220 | /* Codes_SRS_VECTOR_10_020: [VECTOR_element shall fail and return NULL if the given index is out of range.] */
|
---|
221 | LogError("invalid argument - index(%zd); should be >= 0 and < %zd.", index, handle->count);
|
---|
222 | result = NULL;
|
---|
223 | }
|
---|
224 | else
|
---|
225 | {
|
---|
226 | /* Codes_SRS_VECTOR_10_018: [VECTOR_element shall return the element at the given index.] */
|
---|
227 | result = (unsigned char*)handle->storage + (handle->elementSize * index);
|
---|
228 | }
|
---|
229 | }
|
---|
230 | return result;
|
---|
231 | }
|
---|
232 |
|
---|
233 | IMPLEMENT_MOCKABLE_FUNCTION(, void*, VECTOR_front, VECTOR_HANDLE, handle)
|
---|
234 | {
|
---|
235 | void* result;
|
---|
236 | if (handle == NULL)
|
---|
237 | {
|
---|
238 | /* Codes_SRS_VECTOR_10_022: [VECTOR_front shall fail and return NULL if handle is NULL.] */
|
---|
239 | LogError("invalid argument handle (NULL).");
|
---|
240 | result = NULL;
|
---|
241 | }
|
---|
242 | else
|
---|
243 | {
|
---|
244 | if (handle->count == 0)
|
---|
245 | {
|
---|
246 | /* Codes_SRS_VECTOR_10_028: [VECTOR_front shall return NULL if the vector is empty.] */
|
---|
247 | LogError("vector is empty.");
|
---|
248 | result = NULL;
|
---|
249 | }
|
---|
250 | else
|
---|
251 | {
|
---|
252 | /* Codes_SRS_VECTOR_10_021: [VECTOR_front shall return a pointer to the element at index 0.] */
|
---|
253 | result = handle->storage;
|
---|
254 | }
|
---|
255 | }
|
---|
256 | return result;
|
---|
257 | }
|
---|
258 |
|
---|
259 | IMPLEMENT_MOCKABLE_FUNCTION(, void*, VECTOR_back, VECTOR_HANDLE, handle)
|
---|
260 | {
|
---|
261 | void* result;
|
---|
262 | if (handle == NULL)
|
---|
263 | {
|
---|
264 | /* Codes_SRS_VECTOR_10_024: [VECTOR_back shall fail and return NULL if handle is NULL.] */
|
---|
265 | LogError("invalid argument handle (NULL).");
|
---|
266 | result = NULL;
|
---|
267 | }
|
---|
268 | else
|
---|
269 | {
|
---|
270 | if (handle->count == 0)
|
---|
271 | {
|
---|
272 | /* Codes_SRS_VECTOR_10_029: [VECTOR_back shall return NULL if the vector is empty.] */
|
---|
273 | LogError("vector is empty.");
|
---|
274 | result = NULL;
|
---|
275 | }
|
---|
276 | else
|
---|
277 | {
|
---|
278 | /* Codes_SRS_VECTOR_10_023: [VECTOR_front shall return the last element of the vector.] */
|
---|
279 | result = (unsigned char*)handle->storage + (handle->elementSize * (handle->count - 1));
|
---|
280 | }
|
---|
281 | }
|
---|
282 | return result;
|
---|
283 | }
|
---|
284 |
|
---|
285 | IMPLEMENT_MOCKABLE_FUNCTION(, void*, VECTOR_find_if, VECTOR_HANDLE, handle, PREDICATE_FUNCTION, pred, const void*, value)
|
---|
286 | {
|
---|
287 | void* result;
|
---|
288 | if (handle == NULL || pred == NULL)
|
---|
289 | {
|
---|
290 | /* Codes_SRS_VECTOR_10_030: [VECTOR_find_if shall fail and return NULL if handle is NULL.] */
|
---|
291 | /* Codes_SRS_VECTOR_10_036: [VECTOR_find_if shall fail and return NULL if pred is NULL.] */
|
---|
292 | LogError("invalid argument - handle(%p), pred(%p)", handle, pred);
|
---|
293 | result = NULL;
|
---|
294 | }
|
---|
295 | else
|
---|
296 | {
|
---|
297 | size_t i;
|
---|
298 | for (i = 0; i < handle->count; ++i)
|
---|
299 | {
|
---|
300 | if (true == pred((unsigned char*)handle->storage + (handle->elementSize * i), value))
|
---|
301 | {
|
---|
302 | /* Codes_SRS_VECTOR_10_031: [VECTOR_find_if shall return the first element in the vector that matches pred.] */
|
---|
303 | break;
|
---|
304 | }
|
---|
305 | }
|
---|
306 |
|
---|
307 | if (i == handle->count)
|
---|
308 | {
|
---|
309 | /* Codes_SRS_VECTOR_10_032: [VECTOR_find_if shall return NULL if no matching element is found.] */
|
---|
310 | result = NULL;
|
---|
311 | }
|
---|
312 | else
|
---|
313 | {
|
---|
314 | /* Codes_SRS_VECTOR_10_031: [VECTOR_find_if shall return the first element in the vector that matches pred.]*/
|
---|
315 | result = (unsigned char*)handle->storage + (handle->elementSize * i);
|
---|
316 | }
|
---|
317 | }
|
---|
318 | return result;
|
---|
319 | }
|
---|
320 |
|
---|
321 | /* capacity */
|
---|
322 |
|
---|
323 | IMPLEMENT_MOCKABLE_FUNCTION(, size_t, VECTOR_size, VECTOR_HANDLE, handle)
|
---|
324 | {
|
---|
325 | size_t result;
|
---|
326 | if (handle == NULL)
|
---|
327 | {
|
---|
328 | /* Codes_SRS_VECTOR_10_026: [**VECTOR_size shall return 0 if the given handle is NULL.] */
|
---|
329 | LogError("invalid argument handle(NULL).");
|
---|
330 | result = 0;
|
---|
331 | }
|
---|
332 | else
|
---|
333 | {
|
---|
334 | /* Codes_SRS_VECTOR_10_025: [VECTOR_size shall return the number of elements stored with the given handle.] */
|
---|
335 | result = handle->count;
|
---|
336 | }
|
---|
337 | return result;
|
---|
338 | }
|
---|