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((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 }
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, (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 
258 void 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 
280 BOOL 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)
301 int 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 
314 BOOL 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);
327 out:
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 
338 BOOL 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 
366 BOOL 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 
401 BOOL 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 
434 SSIZE_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 
463 fail:
464  if (!found)
465  index = -1;
466 
467  ArrayList_Unlock_Conditional(arrayList);
468 
469  return index;
470 }
471 
485 SSIZE_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 
524 static BOOL ArrayList_DefaultCompare(const void* objA, const void* objB)
525 {
526  return objA == objB ? TRUE : FALSE;
527 }
528 
529 wObject* ArrayList_Object(wArrayList* arrayList)
530 {
531  WINPR_ASSERT(arrayList);
532  return &arrayList->object;
533 }
534 
535 BOOL 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 
546 BOOL 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;
567 fail:
568  ArrayList_Unlock_Conditional(arrayList);
569  return rc;
570 }
571 
576 wArrayList* 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;
596 fail:
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 
604 void 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