s2n_set.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License").
  5. * You may not use this file except in compliance with the License.
  6. * A copy of the License is located at
  7. *
  8. * http://aws.amazon.com/apache2.0
  9. *
  10. * or in the "license" file accompanying this file. This file is distributed
  11. * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
  12. * express or implied. See the License for the specific language governing
  13. * permissions and limitations under the License.
  14. */
  15. #include "utils/s2n_set.h"
  16. #include "utils/s2n_array.h"
  17. #include "utils/s2n_blob.h"
  18. #include "utils/s2n_mem.h"
  19. #include "utils/s2n_result.h"
  20. #include "utils/s2n_safety.h"
  21. #define S2N_INITIAL_SET_SIZE 16
  22. S2N_RESULT s2n_set_validate(const struct s2n_set *set)
  23. {
  24. RESULT_ENSURE_REF(set);
  25. RESULT_GUARD(s2n_array_validate(set->data));
  26. return S2N_RESULT_OK;
  27. }
  28. /* Sets "out" to the index at which the element should be inserted.
  29. * Returns an error if the element already exists */
  30. static S2N_RESULT s2n_set_binary_search(struct s2n_set *set, void *element, uint32_t *out)
  31. {
  32. RESULT_GUARD(s2n_set_validate(set));
  33. RESULT_ENSURE(S2N_MEM_IS_READABLE(element, set->data->element_size), S2N_ERR_NULL);
  34. RESULT_ENSURE_REF(out);
  35. struct s2n_array *array = set->data;
  36. int (*comparator)(const void *, const void *) = set->comparator;
  37. uint32_t len = 0;
  38. RESULT_GUARD(s2n_array_num_elements(array, &len));
  39. if (len == 0) {
  40. *out = 0;
  41. return S2N_RESULT_OK;
  42. }
  43. /* Use 64 bit ints to avoid possibility of overflow */
  44. int64_t low = 0;
  45. int64_t top = len - 1;
  46. while (low <= top) {
  47. int64_t mid = low + ((top - low) / 2);
  48. void *array_element = NULL;
  49. RESULT_GUARD(s2n_array_get(array, mid, &array_element));
  50. int m = comparator(array_element, element);
  51. /* the element is already in the set */
  52. if (m == 0) {
  53. RESULT_BAIL(S2N_ERR_SET_DUPLICATE_VALUE);
  54. }
  55. if (m > 0) {
  56. top = mid - 1;
  57. } else {
  58. low = mid + 1;
  59. }
  60. }
  61. *out = low;
  62. return S2N_RESULT_OK;
  63. }
  64. struct s2n_set *s2n_set_new(uint32_t element_size, int (*comparator)(const void *, const void *))
  65. {
  66. PTR_ENSURE_REF(comparator);
  67. struct s2n_blob mem = { 0 };
  68. PTR_GUARD_POSIX(s2n_alloc(&mem, sizeof(struct s2n_set)));
  69. struct s2n_set *set = (void *) mem.data;
  70. *set = (struct s2n_set){ .data = s2n_array_new(element_size), .comparator = comparator };
  71. if (set->data == NULL) {
  72. PTR_GUARD_POSIX(s2n_free(&mem));
  73. return NULL;
  74. }
  75. return set;
  76. }
  77. S2N_RESULT s2n_set_add(struct s2n_set *set, void *element)
  78. {
  79. RESULT_GUARD(s2n_set_validate(set));
  80. uint32_t idx = 0;
  81. RESULT_GUARD(s2n_set_binary_search(set, element, &idx));
  82. RESULT_GUARD(s2n_array_insert_and_copy(set->data, idx, element));
  83. return S2N_RESULT_OK;
  84. }
  85. S2N_RESULT s2n_set_get(struct s2n_set *set, uint32_t idx, void **element)
  86. {
  87. RESULT_GUARD(s2n_set_validate(set));
  88. RESULT_ENSURE_REF(element);
  89. RESULT_GUARD(s2n_array_get(set->data, idx, element));
  90. return S2N_RESULT_OK;
  91. }
  92. S2N_RESULT s2n_set_remove(struct s2n_set *set, uint32_t idx)
  93. {
  94. RESULT_GUARD(s2n_set_validate(set));
  95. RESULT_GUARD(s2n_array_remove(set->data, idx));
  96. return S2N_RESULT_OK;
  97. }
  98. S2N_RESULT s2n_set_free_p(struct s2n_set **pset)
  99. {
  100. RESULT_ENSURE_REF(pset);
  101. struct s2n_set *set = *pset;
  102. RESULT_ENSURE_REF(set);
  103. RESULT_GUARD(s2n_array_free(set->data));
  104. /* And finally the set object. */
  105. RESULT_GUARD_POSIX(s2n_free_object((uint8_t **) pset, sizeof(struct s2n_set)));
  106. return S2N_RESULT_OK;
  107. }
  108. S2N_RESULT s2n_set_free(struct s2n_set *set)
  109. {
  110. RESULT_ENSURE_REF(set);
  111. return s2n_set_free_p(&set);
  112. }
  113. S2N_RESULT s2n_set_len(struct s2n_set *set, uint32_t *len)
  114. {
  115. RESULT_GUARD(s2n_set_validate(set));
  116. RESULT_GUARD(s2n_array_num_elements(set->data, len));
  117. return S2N_RESULT_OK;
  118. }