FreeRDP
Loading...
Searching...
No Matches
ArrayList.c
1
20#include <winpr/config.h>
21
22#include <stdarg.h>
23
24#include <winpr/crt.h>
25#include <winpr/assert.h>
26#include <winpr/collections.h>
27
28#if defined(_WIN32) && (_MSC_VER < 1800) && !defined(__MINGW32__)
29#define va_copy(dest, src) (dest = src)
30#endif
31
32struct s_wArrayList
33{
34 size_t capacity;
35 size_t growthFactor;
36 BOOL synchronized;
37
38 size_t size;
39 void** array;
41
42 wObject object;
43};
44
58size_t ArrayList_Capacity(wArrayList* arrayList)
59{
60 WINPR_ASSERT(arrayList);
61 return arrayList->capacity;
62}
63
68size_t ArrayList_Count(wArrayList* arrayList)
69{
70 WINPR_ASSERT(arrayList);
71 return arrayList->size;
72}
73
78size_t ArrayList_Items(wArrayList* arrayList, ULONG_PTR** ppItems)
79{
80 WINPR_ASSERT(arrayList);
81 *ppItems = (ULONG_PTR*)arrayList->array;
82 return arrayList->size;
83}
84
89BOOL ArrayList_IsFixedSized(WINPR_ATTR_UNUSED wArrayList* arrayList)
90{
91 WINPR_ASSERT(arrayList);
92 return FALSE;
93}
94
99BOOL ArrayList_IsReadOnly(WINPR_ATTR_UNUSED wArrayList* arrayList)
100{
101 WINPR_ASSERT(arrayList);
102 return FALSE;
103}
104
109BOOL ArrayList_IsSynchronized(wArrayList* arrayList)
110{
111 WINPR_ASSERT(arrayList);
112 return arrayList->synchronized;
113}
114
119static void ArrayList_Lock_Conditional(wArrayList* arrayList)
120{
121 WINPR_ASSERT(arrayList);
122 if (arrayList->synchronized)
123 EnterCriticalSection(&arrayList->lock);
124}
125
126void ArrayList_Lock(wArrayList* arrayList)
127{
128 WINPR_ASSERT(arrayList);
129 EnterCriticalSection(&arrayList->lock);
130}
131
136static void ArrayList_Unlock_Conditional(wArrayList* arrayList)
137{
138 WINPR_ASSERT(arrayList);
139 if (arrayList->synchronized)
140 LeaveCriticalSection(&arrayList->lock);
141}
142
143void ArrayList_Unlock(wArrayList* arrayList)
144{
145 WINPR_ASSERT(arrayList);
146 LeaveCriticalSection(&arrayList->lock);
147}
148
153void* ArrayList_GetItem(wArrayList* arrayList, size_t index)
154{
155 void* obj = NULL;
156
157 WINPR_ASSERT(arrayList);
158 if (index < arrayList->size)
159 {
160 obj = arrayList->array[index];
161 }
162
163 return obj;
164}
165
170BOOL ArrayList_SetItem(wArrayList* arrayList, size_t index, const void* obj)
171{
172 WINPR_ASSERT(arrayList);
173 if (index >= arrayList->size)
174 return FALSE;
175
176 if (arrayList->object.fnObjectNew)
177 {
178 arrayList->array[index] = arrayList->object.fnObjectNew(obj);
179 if (obj && !arrayList->array[index])
180 return FALSE;
181 }
182 else
183 {
184 union
185 {
186 const void* cpv;
187 void* pv;
188 } cnv;
189 cnv.cpv = obj;
190 arrayList->array[index] = cnv.pv;
191 }
192 return TRUE;
193}
194
198static BOOL ArrayList_EnsureCapacity(wArrayList* arrayList, size_t count)
199{
200 WINPR_ASSERT(arrayList);
201 WINPR_ASSERT(count > 0);
202
203 if (arrayList->size + count > arrayList->capacity)
204 {
205 void** newArray = NULL;
206 size_t newCapacity = arrayList->capacity * arrayList->growthFactor;
207 if (newCapacity < arrayList->size + count)
208 newCapacity = arrayList->size + count;
209
210 newArray = (void**)realloc((void*)arrayList->array, sizeof(void*) * newCapacity);
211
212 if (!newArray)
213 return FALSE;
214
215 arrayList->array = newArray;
216 arrayList->capacity = newCapacity;
217 }
218
219 return TRUE;
220}
225static BOOL ArrayList_Shift(wArrayList* arrayList, size_t index, SSIZE_T count)
226{
227 WINPR_ASSERT(arrayList);
228 if (count > 0)
229 {
230 if (!ArrayList_EnsureCapacity(arrayList, (size_t)count))
231 return FALSE;
232
233 MoveMemory((void*)&arrayList->array[index + (size_t)count], (void*)&arrayList->array[index],
234 (arrayList->size - index) * sizeof(void*));
235 arrayList->size += (size_t)count;
236 }
237 else if (count < 0)
238 {
239 const size_t scount = WINPR_ASSERTING_INT_CAST(size_t, -count);
240 const size_t off = index + scount;
241 if (off < arrayList->size)
242 {
243 const size_t chunk = arrayList->size - off;
244 MoveMemory((void*)&arrayList->array[index], (void*)&arrayList->array[off],
245 chunk * sizeof(void*));
246 }
247
248 arrayList->size -= scount;
249 }
250
251 return TRUE;
252}
253
258void ArrayList_Clear(wArrayList* arrayList)
259{
260 WINPR_ASSERT(arrayList);
261 ArrayList_Lock_Conditional(arrayList);
262
263 for (size_t index = 0; index < arrayList->size; index++)
264 {
265 if (arrayList->object.fnObjectFree)
266 arrayList->object.fnObjectFree(arrayList->array[index]);
267
268 arrayList->array[index] = NULL;
269 }
270
271 arrayList->size = 0;
272
273 ArrayList_Unlock_Conditional(arrayList);
274}
275
280BOOL ArrayList_Contains(wArrayList* arrayList, const void* obj)
281{
282 BOOL rc = FALSE;
283
284 WINPR_ASSERT(arrayList);
285 ArrayList_Lock_Conditional(arrayList);
286
287 for (size_t index = 0; index < arrayList->size; index++)
288 {
289 rc = arrayList->object.fnObjectEquals(arrayList->array[index], obj);
290
291 if (rc)
292 break;
293 }
294
295 ArrayList_Unlock_Conditional(arrayList);
296
297 return rc;
298}
299
300#if defined(WITH_WINPR_DEPRECATED)
301int ArrayList_Add(wArrayList* arrayList, const void* obj)
302{
303 WINPR_ASSERT(arrayList);
304 if (!ArrayList_Append(arrayList, obj))
305 return -1;
306 return (int)ArrayList_Count(arrayList) - 1;
307}
308#endif
309
314BOOL ArrayList_Append(wArrayList* arrayList, const void* obj)
315{
316 size_t index = 0;
317 BOOL rc = FALSE;
318
319 WINPR_ASSERT(arrayList);
320 ArrayList_Lock_Conditional(arrayList);
321
322 if (!ArrayList_EnsureCapacity(arrayList, 1))
323 goto out;
324
325 index = arrayList->size++;
326 rc = ArrayList_SetItem(arrayList, index, obj);
327out:
328
329 ArrayList_Unlock_Conditional(arrayList);
330
331 return rc;
332}
333
334/*
335 * Inserts an element into the ArrayList at the specified index.
336 */
337
338BOOL ArrayList_Insert(wArrayList* arrayList, size_t index, const void* obj)
339{
340 BOOL ret = TRUE;
341
342 WINPR_ASSERT(arrayList);
343 ArrayList_Lock_Conditional(arrayList);
344
345 if (index < arrayList->size)
346 {
347 if (!ArrayList_Shift(arrayList, index, 1))
348 {
349 ret = FALSE;
350 }
351 else
352 {
353 ArrayList_SetItem(arrayList, index, obj);
354 }
355 }
356
357 ArrayList_Unlock_Conditional(arrayList);
358
359 return ret;
360}
361
366BOOL ArrayList_Remove(wArrayList* arrayList, const void* obj)
367{
368 BOOL found = FALSE;
369 BOOL ret = TRUE;
370
371 WINPR_ASSERT(arrayList);
372 ArrayList_Lock_Conditional(arrayList);
373
374 size_t index = 0;
375 for (; index < arrayList->size; index++)
376 {
377 if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
378 {
379 found = TRUE;
380 break;
381 }
382 }
383
384 if (found)
385 {
386 if (arrayList->object.fnObjectFree)
387 arrayList->object.fnObjectFree(arrayList->array[index]);
388
389 ret = ArrayList_Shift(arrayList, index, -1);
390 }
391
392 ArrayList_Unlock_Conditional(arrayList);
393
394 return ret;
395}
396
401BOOL ArrayList_RemoveAt(wArrayList* arrayList, size_t index)
402{
403 BOOL ret = TRUE;
404
405 WINPR_ASSERT(arrayList);
406 ArrayList_Lock_Conditional(arrayList);
407
408 if (index < arrayList->size)
409 {
410 if (arrayList->object.fnObjectFree)
411 arrayList->object.fnObjectFree(arrayList->array[index]);
412
413 ret = ArrayList_Shift(arrayList, index, -1);
414 }
415
416 ArrayList_Unlock_Conditional(arrayList);
417
418 return ret;
419}
420
434SSIZE_T ArrayList_IndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex, SSIZE_T count)
435{
436 BOOL found = FALSE;
437
438 WINPR_ASSERT(arrayList);
439 ArrayList_Lock_Conditional(arrayList);
440
441 SSIZE_T sindex = startIndex;
442 if (startIndex < 0)
443 sindex = 0;
444
445 SSIZE_T index = sindex;
446 SSIZE_T cindex = count;
447 if (count < 0)
448 {
449 if (arrayList->size > SSIZE_MAX)
450 goto fail;
451 cindex = (SSIZE_T)arrayList->size;
452 }
453
454 for (; index < sindex + cindex; index++)
455 {
456 if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
457 {
458 found = TRUE;
459 break;
460 }
461 }
462
463fail:
464 if (!found)
465 index = -1;
466
467 ArrayList_Unlock_Conditional(arrayList);
468
469 return index;
470}
471
485SSIZE_T ArrayList_LastIndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex,
486 SSIZE_T count)
487{
488 SSIZE_T sindex = 0;
489 SSIZE_T cindex = 0;
490 BOOL found = FALSE;
491
492 WINPR_ASSERT(arrayList);
493 ArrayList_Lock_Conditional(arrayList);
494
495 sindex = startIndex;
496 if (startIndex < 0)
497 sindex = 0;
498
499 cindex = count;
500 if (count < 0)
501 {
502 WINPR_ASSERT(arrayList->size <= SSIZE_MAX);
503 cindex = (SSIZE_T)arrayList->size;
504 }
505
506 SSIZE_T index = sindex + cindex;
507 for (; index > sindex; index--)
508 {
509 if (arrayList->object.fnObjectEquals(arrayList->array[index - 1], obj))
510 {
511 found = TRUE;
512 break;
513 }
514 }
515
516 if (!found)
517 index = -1;
518
519 ArrayList_Unlock_Conditional(arrayList);
520
521 return index;
522}
523
524static BOOL ArrayList_DefaultCompare(const void* objA, const void* objB)
525{
526 return objA == objB ? TRUE : FALSE;
527}
528
529wObject* ArrayList_Object(wArrayList* arrayList)
530{
531 WINPR_ASSERT(arrayList);
532 return &arrayList->object;
533}
534
535BOOL ArrayList_ForEach(wArrayList* arrayList, ArrayList_ForEachFkt fkt, ...)
536{
537 BOOL rc = 0;
538 va_list ap = { 0 };
539 va_start(ap, fkt);
540 rc = ArrayList_ForEachAP(arrayList, fkt, ap);
541 va_end(ap);
542
543 return rc;
544}
545
546BOOL ArrayList_ForEachAP(wArrayList* arrayList, ArrayList_ForEachFkt fkt, va_list ap)
547{
548 BOOL rc = FALSE;
549 va_list cap;
550
551 WINPR_ASSERT(arrayList);
552 WINPR_ASSERT(fkt);
553
554 ArrayList_Lock_Conditional(arrayList);
555 size_t count = ArrayList_Count(arrayList);
556 for (size_t index = 0; index < count; index++)
557 {
558 BOOL rs = 0;
559 void* obj = ArrayList_GetItem(arrayList, index);
560 va_copy(cap, ap);
561 rs = fkt(obj, index, cap);
562 va_end(cap);
563 if (!rs)
564 goto fail;
565 }
566 rc = TRUE;
567fail:
568 ArrayList_Unlock_Conditional(arrayList);
569 return rc;
570}
571
576wArrayList* ArrayList_New(BOOL synchronized)
577{
578 wObject* obj = NULL;
579 wArrayList* arrayList = NULL;
580 arrayList = (wArrayList*)calloc(1, sizeof(wArrayList));
581
582 if (!arrayList)
583 return NULL;
584
585 arrayList->synchronized = synchronized;
586 arrayList->growthFactor = 2;
587 obj = ArrayList_Object(arrayList);
588 if (!obj)
589 goto fail;
590 obj->fnObjectEquals = ArrayList_DefaultCompare;
591 if (!ArrayList_EnsureCapacity(arrayList, 32))
592 goto fail;
593
594 InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000);
595 return arrayList;
596fail:
597 WINPR_PRAGMA_DIAG_PUSH
598 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
599 ArrayList_Free(arrayList);
600 WINPR_PRAGMA_DIAG_POP
601 return NULL;
602}
603
604void ArrayList_Free(wArrayList* arrayList)
605{
606 if (!arrayList)
607 return;
608
609 ArrayList_Clear(arrayList);
610 DeleteCriticalSection(&arrayList->lock);
611 free((void*)arrayList->array);
612 free(arrayList);
613}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57