smartlist_core.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2019, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file smartlist_core.c
  7. * \brief Implements the core functionality of a smartlist (a resizeable
  8. * dynamic array). For more functionality and helper functions, see the
  9. * container library.
  10. **/
  11. #include "lib/err/torerr.h"
  12. #include "lib/malloc/malloc.h"
  13. #include "lib/smartlist_core/smartlist_core.h"
  14. #include <stdlib.h>
  15. #include <string.h>
  16. /** All newly allocated smartlists have this capacity. */
  17. #define SMARTLIST_DEFAULT_CAPACITY 16
  18. /** Allocate and return an empty smartlist.
  19. */
  20. MOCK_IMPL(smartlist_t *,
  21. smartlist_new,(void))
  22. {
  23. smartlist_t *sl = tor_malloc(sizeof(smartlist_t));
  24. sl->num_used = 0;
  25. sl->capacity = SMARTLIST_DEFAULT_CAPACITY;
  26. sl->list = tor_calloc(sizeof(void *), sl->capacity);
  27. return sl;
  28. }
  29. /** Deallocate a smartlist. Does not release storage associated with the
  30. * list's elements.
  31. */
  32. MOCK_IMPL(void,
  33. smartlist_free_,(smartlist_t *sl))
  34. {
  35. if (!sl)
  36. return;
  37. tor_free(sl->list);
  38. tor_free(sl);
  39. }
  40. /** Remove all elements from the list.
  41. */
  42. void
  43. smartlist_clear(smartlist_t *sl)
  44. {
  45. memset(sl->list, 0, sizeof(void *) * sl->num_used);
  46. sl->num_used = 0;
  47. }
  48. #if SIZE_MAX < INT_MAX
  49. #error "We don't support systems where size_t is smaller than int."
  50. #endif
  51. /** Make sure that <b>sl</b> can hold at least <b>size</b> entries. */
  52. static inline void
  53. smartlist_ensure_capacity(smartlist_t *sl, size_t size)
  54. {
  55. /* Set MAX_CAPACITY to MIN(INT_MAX, SIZE_MAX / sizeof(void*)) */
  56. #if (SIZE_MAX/SIZEOF_VOID_P) > INT_MAX
  57. #define MAX_CAPACITY (INT_MAX)
  58. #else
  59. #define MAX_CAPACITY (int)((SIZE_MAX / (sizeof(void*))))
  60. #endif
  61. raw_assert(size <= MAX_CAPACITY);
  62. if (size > (size_t) sl->capacity) {
  63. size_t higher = (size_t) sl->capacity;
  64. if (PREDICT_UNLIKELY(size > MAX_CAPACITY/2)) {
  65. higher = MAX_CAPACITY;
  66. } else {
  67. while (size > higher)
  68. higher *= 2;
  69. }
  70. sl->list = tor_reallocarray(sl->list, sizeof(void *),
  71. ((size_t)higher));
  72. memset(sl->list + sl->capacity, 0,
  73. sizeof(void *) * (higher - sl->capacity));
  74. sl->capacity = (int) higher;
  75. }
  76. #undef ASSERT_CAPACITY
  77. #undef MAX_CAPACITY
  78. }
  79. /** Expand <b>sl</b> so that its length is at least <b>new_size</b>,
  80. * filling in previously unused entries with NULL>
  81. *
  82. * Do nothing if <b>sl</b> already had at least <b>new_size</b> elements.
  83. */
  84. void
  85. smartlist_grow(smartlist_t *sl, size_t new_size)
  86. {
  87. smartlist_ensure_capacity(sl, new_size);
  88. if (new_size > (size_t)sl->num_used) {
  89. /* This memset() should be a no-op: everything else in the smartlist code
  90. * tries to make sure that unused entries are always NULL. Still, that is
  91. * meant as a safety mechanism, so let's clear the memory here.
  92. */
  93. memset(sl->list + sl->num_used, 0,
  94. sizeof(void *) * (new_size - sl->num_used));
  95. /* This cast is safe, since we already asserted that we were below
  96. * MAX_CAPACITY in smartlist_ensure_capacity(). */
  97. sl->num_used = (int)new_size;
  98. }
  99. }
  100. /** Append element to the end of the list. */
  101. void
  102. smartlist_add(smartlist_t *sl, void *element)
  103. {
  104. smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
  105. sl->list[sl->num_used++] = element;
  106. }
  107. /** Append each element from S2 to the end of S1. */
  108. void
  109. smartlist_add_all(smartlist_t *s1, const smartlist_t *s2)
  110. {
  111. size_t new_size = (size_t)s1->num_used + (size_t)s2->num_used;
  112. raw_assert(new_size >= (size_t) s1->num_used); /* check for overflow. */
  113. smartlist_ensure_capacity(s1, new_size);
  114. memcpy(s1->list + s1->num_used, s2->list, s2->num_used*sizeof(void*));
  115. raw_assert(new_size <= INT_MAX); /* redundant. */
  116. s1->num_used = (int) new_size;
  117. }
  118. /** Append a copy of string to sl */
  119. void
  120. smartlist_add_strdup(struct smartlist_t *sl, const char *string)
  121. {
  122. char *copy;
  123. copy = tor_strdup(string);
  124. smartlist_add(sl, copy);
  125. }
  126. /** Remove all elements E from sl such that E==element. Preserve
  127. * the order of any elements before E, but elements after E can be
  128. * rearranged.
  129. */
  130. void
  131. smartlist_remove(smartlist_t *sl, const void *element)
  132. {
  133. int i;
  134. if (element == NULL)
  135. return;
  136. for (i=0; i < sl->num_used; i++)
  137. if (sl->list[i] == element) {
  138. sl->list[i] = sl->list[--sl->num_used]; /* swap with the end */
  139. i--; /* so we process the new i'th element */
  140. sl->list[sl->num_used] = NULL;
  141. }
  142. }
  143. /** As <b>smartlist_remove</b>, but do not change the order of
  144. * any elements not removed */
  145. void
  146. smartlist_remove_keeporder(smartlist_t *sl, const void *element)
  147. {
  148. int i, j, num_used_orig = sl->num_used;
  149. if (element == NULL)
  150. return;
  151. for (i=j=0; j < num_used_orig; ++j) {
  152. if (sl->list[j] == element) {
  153. --sl->num_used;
  154. } else {
  155. sl->list[i++] = sl->list[j];
  156. }
  157. }
  158. }
  159. /** If <b>sl</b> is nonempty, remove and return the final element. Otherwise,
  160. * return NULL. */
  161. void *
  162. smartlist_pop_last(smartlist_t *sl)
  163. {
  164. raw_assert(sl);
  165. if (sl->num_used) {
  166. void *tmp = sl->list[--sl->num_used];
  167. sl->list[sl->num_used] = NULL;
  168. return tmp;
  169. } else
  170. return NULL;
  171. }
  172. /** Return true iff some element E of sl has E==element.
  173. */
  174. int
  175. smartlist_contains(const smartlist_t *sl, const void *element)
  176. {
  177. int i;
  178. for (i=0; i < sl->num_used; i++)
  179. if (sl->list[i] == element)
  180. return 1;
  181. return 0;
  182. }
  183. /** Remove the <b>idx</b>th element of sl; if idx is not the last
  184. * element, swap the last element of sl into the <b>idx</b>th space.
  185. */
  186. void
  187. smartlist_del(smartlist_t *sl, int idx)
  188. {
  189. raw_assert(sl);
  190. raw_assert(idx>=0);
  191. raw_assert(idx < sl->num_used);
  192. sl->list[idx] = sl->list[--sl->num_used];
  193. sl->list[sl->num_used] = NULL;
  194. }
  195. /** Remove the <b>idx</b>th element of sl; if idx is not the last element,
  196. * moving all subsequent elements back one space. Return the old value
  197. * of the <b>idx</b>th element.
  198. */
  199. void
  200. smartlist_del_keeporder(smartlist_t *sl, int idx)
  201. {
  202. raw_assert(sl);
  203. raw_assert(idx>=0);
  204. raw_assert(idx < sl->num_used);
  205. --sl->num_used;
  206. if (idx < sl->num_used)
  207. memmove(sl->list+idx, sl->list+idx+1, sizeof(void*)*(sl->num_used-idx));
  208. sl->list[sl->num_used] = NULL;
  209. }
  210. /** Insert the value <b>val</b> as the new <b>idx</b>th element of
  211. * <b>sl</b>, moving all items previously at <b>idx</b> or later
  212. * forward one space.
  213. */
  214. void
  215. smartlist_insert(smartlist_t *sl, int idx, void *val)
  216. {
  217. raw_assert(sl);
  218. raw_assert(idx>=0);
  219. raw_assert(idx <= sl->num_used);
  220. if (idx == sl->num_used) {
  221. smartlist_add(sl, val);
  222. } else {
  223. smartlist_ensure_capacity(sl, ((size_t) sl->num_used)+1);
  224. /* Move other elements away */
  225. if (idx < sl->num_used)
  226. memmove(sl->list + idx + 1, sl->list + idx,
  227. sizeof(void*)*(sl->num_used-idx));
  228. sl->num_used++;
  229. sl->list[idx] = val;
  230. }
  231. }