array_list.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <aws/common/array_list.h>
  6. #include <aws/common/private/array_list.h>
  7. #include <stdlib.h> /* qsort */
  8. int aws_array_list_calc_necessary_size(struct aws_array_list *AWS_RESTRICT list, size_t index, size_t *necessary_size) {
  9. AWS_PRECONDITION(aws_array_list_is_valid(list));
  10. size_t index_inc = 0;
  11. if (aws_add_size_checked(index, 1, &index_inc)) {
  12. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  13. return AWS_OP_ERR;
  14. }
  15. if (aws_mul_size_checked(index_inc, list->item_size, necessary_size)) {
  16. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  17. return AWS_OP_ERR;
  18. }
  19. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  20. return AWS_OP_SUCCESS;
  21. }
  22. int aws_array_list_shrink_to_fit(struct aws_array_list *AWS_RESTRICT list) {
  23. AWS_PRECONDITION(aws_array_list_is_valid(list));
  24. if (list->alloc) {
  25. size_t ideal_size;
  26. if (aws_mul_size_checked(list->length, list->item_size, &ideal_size)) {
  27. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  28. return AWS_OP_ERR;
  29. }
  30. if (ideal_size < list->current_size) {
  31. void *raw_data = NULL;
  32. if (ideal_size > 0) {
  33. raw_data = aws_mem_acquire(list->alloc, ideal_size);
  34. if (!raw_data) {
  35. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  36. return AWS_OP_ERR;
  37. }
  38. memcpy(raw_data, list->data, ideal_size);
  39. aws_mem_release(list->alloc, list->data);
  40. }
  41. list->data = raw_data;
  42. list->current_size = ideal_size;
  43. }
  44. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  45. return AWS_OP_SUCCESS;
  46. }
  47. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  48. return aws_raise_error(AWS_ERROR_LIST_STATIC_MODE_CANT_SHRINK);
  49. }
  50. int aws_array_list_copy(const struct aws_array_list *AWS_RESTRICT from, struct aws_array_list *AWS_RESTRICT to) {
  51. AWS_FATAL_PRECONDITION(from->item_size == to->item_size);
  52. AWS_FATAL_PRECONDITION(from->data);
  53. AWS_PRECONDITION(aws_array_list_is_valid(from));
  54. AWS_PRECONDITION(aws_array_list_is_valid(to));
  55. size_t copy_size;
  56. if (aws_mul_size_checked(from->length, from->item_size, &copy_size)) {
  57. AWS_POSTCONDITION(aws_array_list_is_valid(from));
  58. AWS_POSTCONDITION(aws_array_list_is_valid(to));
  59. return AWS_OP_ERR;
  60. }
  61. if (to->current_size >= copy_size) {
  62. if (copy_size > 0) {
  63. memcpy(to->data, from->data, copy_size);
  64. }
  65. to->length = from->length;
  66. AWS_POSTCONDITION(aws_array_list_is_valid(from));
  67. AWS_POSTCONDITION(aws_array_list_is_valid(to));
  68. return AWS_OP_SUCCESS;
  69. }
  70. /* if to is in dynamic mode, we can just reallocate it and copy */
  71. if (to->alloc != NULL) {
  72. void *tmp = aws_mem_acquire(to->alloc, copy_size);
  73. if (!tmp) {
  74. AWS_POSTCONDITION(aws_array_list_is_valid(from));
  75. AWS_POSTCONDITION(aws_array_list_is_valid(to));
  76. return AWS_OP_ERR;
  77. }
  78. memcpy(tmp, from->data, copy_size);
  79. if (to->data) {
  80. aws_mem_release(to->alloc, to->data);
  81. }
  82. to->data = tmp;
  83. to->length = from->length;
  84. to->current_size = copy_size;
  85. AWS_POSTCONDITION(aws_array_list_is_valid(from));
  86. AWS_POSTCONDITION(aws_array_list_is_valid(to));
  87. return AWS_OP_SUCCESS;
  88. }
  89. return aws_raise_error(AWS_ERROR_DEST_COPY_TOO_SMALL);
  90. }
  91. int aws_array_list_ensure_capacity(struct aws_array_list *AWS_RESTRICT list, size_t index) {
  92. AWS_PRECONDITION(aws_array_list_is_valid(list));
  93. size_t necessary_size;
  94. if (aws_array_list_calc_necessary_size(list, index, &necessary_size)) {
  95. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  96. return AWS_OP_ERR;
  97. }
  98. if (list->current_size < necessary_size) {
  99. if (!list->alloc) {
  100. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  101. return aws_raise_error(AWS_ERROR_INVALID_INDEX);
  102. }
  103. /* this will double capacity if the index isn't bigger than what the
  104. * next allocation would be, but allocates the exact requested size if
  105. * it is. This is largely because we don't have a good way to predict
  106. * the usage pattern to make a smart decision about it. However, if the
  107. * user
  108. * is doing this in an iterative fashion, necessary_size will never be
  109. * used.*/
  110. size_t next_allocation_size = list->current_size << 1;
  111. size_t new_size = next_allocation_size > necessary_size ? next_allocation_size : necessary_size;
  112. if (new_size < list->current_size) {
  113. /* this means new_size overflowed. The only way this happens is on a
  114. * 32-bit system where size_t is 32 bits, in which case we're out of
  115. * addressable memory anyways, or we're on a 64 bit system and we're
  116. * most certainly out of addressable memory. But since we're simply
  117. * going to fail fast and say, sorry can't do it, we'll just tell
  118. * the user they can't grow the list anymore. */
  119. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  120. return aws_raise_error(AWS_ERROR_LIST_EXCEEDS_MAX_SIZE);
  121. }
  122. void *temp = aws_mem_acquire(list->alloc, new_size);
  123. if (!temp) {
  124. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  125. return AWS_OP_ERR;
  126. }
  127. if (list->data) {
  128. memcpy(temp, list->data, list->current_size);
  129. #ifdef DEBUG_BUILD
  130. memset(
  131. (void *)((uint8_t *)temp + list->current_size),
  132. AWS_ARRAY_LIST_DEBUG_FILL,
  133. new_size - list->current_size);
  134. #endif
  135. aws_mem_release(list->alloc, list->data);
  136. }
  137. list->data = temp;
  138. list->current_size = new_size;
  139. }
  140. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  141. return AWS_OP_SUCCESS;
  142. }
  143. static void aws_array_list_mem_swap(void *AWS_RESTRICT item1, void *AWS_RESTRICT item2, size_t item_size) {
  144. enum { SLICE = 128 };
  145. AWS_FATAL_PRECONDITION(item1);
  146. AWS_FATAL_PRECONDITION(item2);
  147. /* copy SLICE sized bytes at a time */
  148. size_t slice_count = item_size / SLICE;
  149. uint8_t temp[SLICE];
  150. for (size_t i = 0; i < slice_count; i++) {
  151. memcpy((void *)temp, (void *)item1, SLICE);
  152. memcpy((void *)item1, (void *)item2, SLICE);
  153. memcpy((void *)item2, (void *)temp, SLICE);
  154. item1 = (uint8_t *)item1 + SLICE;
  155. item2 = (uint8_t *)item2 + SLICE;
  156. }
  157. size_t remainder = item_size & (SLICE - 1); /* item_size % SLICE */
  158. memcpy((void *)temp, (void *)item1, remainder);
  159. memcpy((void *)item1, (void *)item2, remainder);
  160. memcpy((void *)item2, (void *)temp, remainder);
  161. }
  162. void aws_array_list_swap(struct aws_array_list *AWS_RESTRICT list, size_t a, size_t b) {
  163. AWS_FATAL_PRECONDITION(a < list->length);
  164. AWS_FATAL_PRECONDITION(b < list->length);
  165. AWS_PRECONDITION(aws_array_list_is_valid(list));
  166. if (a == b) {
  167. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  168. return;
  169. }
  170. void *item1 = NULL;
  171. void *item2 = NULL;
  172. aws_array_list_get_at_ptr(list, &item1, a);
  173. aws_array_list_get_at_ptr(list, &item2, b);
  174. aws_array_list_mem_swap(item1, item2, list->item_size);
  175. AWS_POSTCONDITION(aws_array_list_is_valid(list));
  176. }