FreeRDP
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 
32 struct s_wArrayList
33 {
34  size_t capacity;
35  size_t growthFactor;
36  BOOL synchronized;
37 
38  size_t size;
39  void** array;
40  CRITICAL_SECTION lock;
41 
42  wObject object;
43 };
44 
58 size_t ArrayList_Capacity(wArrayList* arrayList)
59 {
60  WINPR_ASSERT(arrayList);
61  return arrayList->capacity;
62 }
63 
68 size_t ArrayList_Count(wArrayList* arrayList)
69 {
70  WINPR_ASSERT(arrayList);
71  return arrayList->size;
72 }
73 
78 size_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 
89 BOOL ArrayList_IsFixedSized(wArrayList* arrayList)
90 {
91  WINPR_ASSERT(arrayList);
92  return FALSE;
93 }
94 
99 BOOL ArrayList_IsReadOnly(wArrayList* arrayList)
100 {
101  WINPR_ASSERT(arrayList);
102  return FALSE;
103 }
104 
109 BOOL ArrayList_IsSynchronized(wArrayList* arrayList)
110 {
111  WINPR_ASSERT(arrayList);
112  return arrayList->synchronized;
113 }
114 
119 static void ArrayList_Lock_Conditional(wArrayList* arrayList)
120 {
121  WINPR_ASSERT(arrayList);
122  if (arrayList->synchronized)
123  EnterCriticalSection(&arrayList->lock);
124 }
125 
126 void ArrayList_Lock(wArrayList* arrayList)
127 {
128  WINPR_ASSERT(arrayList);
129  EnterCriticalSection(&arrayList->lock);
130 }
131 
136 static void ArrayList_Unlock_Conditional(wArrayList* arrayList)
137 {
138  WINPR_ASSERT(arrayList);
139  if (arrayList->synchronized)
140  LeaveCriticalSection(&arrayList->lock);
141 }
142 
143 void ArrayList_Unlock(wArrayList* arrayList)
144 {
145  WINPR_ASSERT(arrayList);
146  LeaveCriticalSection(&arrayList->lock);
147 }
148 
153 void* 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 
170 BOOL 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 
198 static 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(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 }
225 static 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, count))
231  return FALSE;
232 
233  MoveMemory(&arrayList->array[index + count], &arrayList->array[index],
234  (arrayList->size - index) * sizeof(void*));
235  arrayList->size += count;
236  }
237  else if (count < 0)
238  {
239  const size_t off = index + (size_t)(-1 * count);
240  if (off < arrayList->size)
241  {
242  const size_t chunk = arrayList->size - off;
243  MoveMemory(&arrayList->array[index], &arrayList->array[index - count],
244  chunk * sizeof(void*));
245  }
246 
247  arrayList->size += count;
248  }
249 
250  return TRUE;
251 }
252 
257 void ArrayList_Clear(wArrayList* arrayList)
258 {
259  WINPR_ASSERT(arrayList);
260  ArrayList_Lock_Conditional(arrayList);
261 
262  for (size_t index = 0; index < arrayList->size; index++)
263  {
264  if (arrayList->object.fnObjectFree)
265  arrayList->object.fnObjectFree(arrayList->array[index]);
266 
267  arrayList->array[index] = NULL;
268  }
269 
270  arrayList->size = 0;
271 
272  ArrayList_Unlock_Conditional(arrayList);
273 }
274 
279 BOOL ArrayList_Contains(wArrayList* arrayList, const void* obj)
280 {
281  BOOL rc = FALSE;
282 
283  WINPR_ASSERT(arrayList);
284  ArrayList_Lock_Conditional(arrayList);
285 
286  for (size_t index = 0; index < arrayList->size; index++)
287  {
288  rc = arrayList->object.fnObjectEquals(arrayList->array[index], obj);
289 
290  if (rc)
291  break;
292  }
293 
294  ArrayList_Unlock_Conditional(arrayList);
295 
296  return rc;
297 }
298 
299 #if defined(WITH_WINPR_DEPRECATED)
300 int ArrayList_Add(wArrayList* arrayList, const void* obj)
301 {
302  WINPR_ASSERT(arrayList);
303  if (!ArrayList_Append(arrayList, obj))
304  return -1;
305  return (int)ArrayList_Count(arrayList) - 1;
306 }
307 #endif
308 
313 BOOL ArrayList_Append(wArrayList* arrayList, const void* obj)
314 {
315  size_t index = 0;
316  BOOL rc = FALSE;
317 
318  WINPR_ASSERT(arrayList);
319  ArrayList_Lock_Conditional(arrayList);
320 
321  if (!ArrayList_EnsureCapacity(arrayList, 1))
322  goto out;
323 
324  index = arrayList->size++;
325  rc = ArrayList_SetItem(arrayList, index, obj);
326 out:
327 
328  ArrayList_Unlock_Conditional(arrayList);
329 
330  return rc;
331 }
332 
333 /*
334  * Inserts an element into the ArrayList at the specified index.
335  */
336 
337 BOOL ArrayList_Insert(wArrayList* arrayList, size_t index, const void* obj)
338 {
339  BOOL ret = TRUE;
340 
341  WINPR_ASSERT(arrayList);
342  ArrayList_Lock_Conditional(arrayList);
343 
344  if (index < arrayList->size)
345  {
346  if (!ArrayList_Shift(arrayList, index, 1))
347  {
348  ret = FALSE;
349  }
350  else
351  {
352  ArrayList_SetItem(arrayList, index, obj);
353  }
354  }
355 
356  ArrayList_Unlock_Conditional(arrayList);
357 
358  return ret;
359 }
360 
365 BOOL ArrayList_Remove(wArrayList* arrayList, const void* obj)
366 {
367  BOOL found = FALSE;
368  BOOL ret = TRUE;
369 
370  WINPR_ASSERT(arrayList);
371  ArrayList_Lock_Conditional(arrayList);
372 
373  size_t index = 0;
374  for (; index < arrayList->size; index++)
375  {
376  if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
377  {
378  found = TRUE;
379  break;
380  }
381  }
382 
383  if (found)
384  {
385  if (arrayList->object.fnObjectFree)
386  arrayList->object.fnObjectFree(arrayList->array[index]);
387 
388  ret = ArrayList_Shift(arrayList, index, -1);
389  }
390 
391  ArrayList_Unlock_Conditional(arrayList);
392 
393  return ret;
394 }
395 
400 BOOL ArrayList_RemoveAt(wArrayList* arrayList, size_t index)
401 {
402  BOOL ret = TRUE;
403 
404  WINPR_ASSERT(arrayList);
405  ArrayList_Lock_Conditional(arrayList);
406 
407  if (index < arrayList->size)
408  {
409  if (arrayList->object.fnObjectFree)
410  arrayList->object.fnObjectFree(arrayList->array[index]);
411 
412  ret = ArrayList_Shift(arrayList, index, -1);
413  }
414 
415  ArrayList_Unlock_Conditional(arrayList);
416 
417  return ret;
418 }
419 
433 SSIZE_T ArrayList_IndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex, SSIZE_T count)
434 {
435  BOOL found = FALSE;
436 
437  WINPR_ASSERT(arrayList);
438  ArrayList_Lock_Conditional(arrayList);
439 
440  SSIZE_T sindex = startIndex;
441  if (startIndex < 0)
442  sindex = 0;
443 
444  SSIZE_T index = sindex;
445  SSIZE_T cindex = count;
446  if (count < 0)
447  {
448  if (arrayList->size > SSIZE_MAX)
449  goto fail;
450  cindex = (SSIZE_T)arrayList->size;
451  }
452 
453  for (; index < sindex + cindex; index++)
454  {
455  if (arrayList->object.fnObjectEquals(arrayList->array[index], obj))
456  {
457  found = TRUE;
458  break;
459  }
460  }
461 
462 fail:
463  if (!found)
464  index = -1;
465 
466  ArrayList_Unlock_Conditional(arrayList);
467 
468  return index;
469 }
470 
484 SSIZE_T ArrayList_LastIndexOf(wArrayList* arrayList, const void* obj, SSIZE_T startIndex,
485  SSIZE_T count)
486 {
487  SSIZE_T sindex = 0;
488  SSIZE_T cindex = 0;
489  BOOL found = FALSE;
490 
491  WINPR_ASSERT(arrayList);
492  ArrayList_Lock_Conditional(arrayList);
493 
494  sindex = startIndex;
495  if (startIndex < 0)
496  sindex = 0;
497 
498  cindex = count;
499  if (count < 0)
500  {
501  WINPR_ASSERT(arrayList->size <= SSIZE_MAX);
502  cindex = (SSIZE_T)arrayList->size;
503  }
504 
505  SSIZE_T index = sindex + cindex;
506  for (; index > sindex; index--)
507  {
508  if (arrayList->object.fnObjectEquals(arrayList->array[index - 1], obj))
509  {
510  found = TRUE;
511  break;
512  }
513  }
514 
515  if (!found)
516  index = -1;
517 
518  ArrayList_Unlock_Conditional(arrayList);
519 
520  return index;
521 }
522 
523 static BOOL ArrayList_DefaultCompare(const void* objA, const void* objB)
524 {
525  return objA == objB ? TRUE : FALSE;
526 }
527 
528 wObject* ArrayList_Object(wArrayList* arrayList)
529 {
530  WINPR_ASSERT(arrayList);
531  return &arrayList->object;
532 }
533 
534 BOOL ArrayList_ForEach(wArrayList* arrayList, ArrayList_ForEachFkt fkt, ...)
535 {
536  BOOL rc = 0;
537  va_list ap = { 0 };
538  va_start(ap, fkt);
539  rc = ArrayList_ForEachAP(arrayList, fkt, ap);
540  va_end(ap);
541 
542  return rc;
543 }
544 
545 BOOL ArrayList_ForEachAP(wArrayList* arrayList, ArrayList_ForEachFkt fkt, va_list ap)
546 {
547  BOOL rc = FALSE;
548  va_list cap;
549 
550  WINPR_ASSERT(arrayList);
551  WINPR_ASSERT(fkt);
552 
553  ArrayList_Lock_Conditional(arrayList);
554  size_t count = ArrayList_Count(arrayList);
555  for (size_t index = 0; index < count; index++)
556  {
557  BOOL rs = 0;
558  void* obj = ArrayList_GetItem(arrayList, index);
559  va_copy(cap, ap);
560  rs = fkt(obj, index, cap);
561  va_end(cap);
562  if (!rs)
563  goto fail;
564  }
565  rc = TRUE;
566 fail:
567  ArrayList_Unlock_Conditional(arrayList);
568  return rc;
569 }
570 
575 wArrayList* ArrayList_New(BOOL synchronized)
576 {
577  wObject* obj = NULL;
578  wArrayList* arrayList = NULL;
579  arrayList = (wArrayList*)calloc(1, sizeof(wArrayList));
580 
581  if (!arrayList)
582  return NULL;
583 
584  arrayList->synchronized = synchronized;
585  arrayList->growthFactor = 2;
586  obj = ArrayList_Object(arrayList);
587  if (!obj)
588  goto fail;
589  obj->fnObjectEquals = ArrayList_DefaultCompare;
590  if (!ArrayList_EnsureCapacity(arrayList, 32))
591  goto fail;
592 
593  InitializeCriticalSectionAndSpinCount(&arrayList->lock, 4000);
594  return arrayList;
595 fail:
596  WINPR_PRAGMA_DIAG_PUSH
597  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
598  ArrayList_Free(arrayList);
599  WINPR_PRAGMA_DIAG_POP
600  return NULL;
601 }
602 
603 void ArrayList_Free(wArrayList* arrayList)
604 {
605  if (!arrayList)
606  return;
607 
608  ArrayList_Clear(arrayList);
609  DeleteCriticalSection(&arrayList->lock);
610  free(arrayList->array);
611  free(arrayList);
612 }
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57