Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/aws/common/array_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ void aws_array_list_swap(struct aws_array_list *AWS_RESTRICT list, size_t a, siz
AWS_COMMON_API
void aws_array_list_sort(struct aws_array_list *AWS_RESTRICT list, aws_array_list_comparator_fn *compare_fn);

/**
* Randomly shuffles the elements of the array list in place using the Fisher-Yates algorithm.
* Uses aws_device_random for cryptographic-quality randomness.
* Returns AWS_OP_SUCCESS, or an error code if the random source is unavailable.
*/
AWS_COMMON_API
int aws_array_list_shuffle(struct aws_array_list *AWS_RESTRICT list);

AWS_EXTERN_C_END
#ifndef AWS_NO_STATIC_IMPL
# include <aws/common/array_list.inl>
Expand Down
19 changes: 19 additions & 0 deletions source/array_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include <aws/common/array_list.h>
#include <aws/common/device_random.h>
#include <aws/common/private/array_list.h>

#include <stdlib.h> /* qsort */
Expand Down Expand Up @@ -217,3 +218,21 @@ void aws_array_list_sort(struct aws_array_list *AWS_RESTRICT list, aws_array_lis
}
AWS_POSTCONDITION(aws_array_list_is_valid(list));
}

int aws_array_list_shuffle(struct aws_array_list *AWS_RESTRICT list) {
AWS_PRECONDITION(aws_array_list_is_valid(list));
size_t len = aws_array_list_length(list);
if (len <= 1) {
return AWS_OP_SUCCESS;
}
for (size_t i = len - 1; i > 0; --i) {
uint64_t rand_val = 0;
if (aws_device_random_u64(&rand_val)) {
return aws_raise_error(aws_last_error());
}
size_t j = (size_t)(rand_val % (i + 1));
aws_array_list_swap(list, i, j);
}
AWS_POSTCONDITION(aws_array_list_is_valid(list));
return AWS_OP_SUCCESS;
}
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ add_test_case(array_list_not_enough_space_test)
add_test_case(array_list_not_enough_space_test_failure)
add_test_case(array_list_of_strings_sort)
add_test_case(array_list_empty_sort)
add_test_case(array_list_shuffle)
add_test_case(array_list_shuffle_empty)
add_test_case(priority_queue_push_pop_order_test)
add_test_case(priority_queue_random_values_test)
add_test_case(priority_queue_size_and_capacity_test)
Expand Down
51 changes: 51 additions & 0 deletions tests/array_list_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1056,3 +1056,54 @@ static int s_array_list_empty_sort_fn(struct aws_allocator *allocator, void *ctx
}

AWS_TEST_CASE(array_list_empty_sort, s_array_list_empty_sort_fn)

static int s_array_list_shuffle_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
struct aws_array_list list;
const size_t count = 20;
ASSERT_SUCCESS(aws_array_list_init_dynamic(&list, allocator, count, sizeof(uint32_t)));

for (uint32_t i = 0; i < count; ++i) {
ASSERT_SUCCESS(aws_array_list_push_back(&list, &i));
}

ASSERT_SUCCESS(aws_array_list_shuffle(&list));

/* Verify it's a valid permutation: all values 0..count-1 present exactly once */
bool seen[20] = {false};
bool is_sequential = true;
for (size_t i = 0; i < count; ++i) {
uint32_t val = 0;
aws_array_list_get_at(&list, &val, i);
ASSERT_TRUE(val < count);
ASSERT_FALSE(seen[val]);
seen[val] = true;
if (val != (uint32_t)i) {
is_sequential = false;
}
}
/* With 20 elements, probability of identity permutation is 1/20! ~ 0 */
ASSERT_FALSE(is_sequential);

aws_array_list_clean_up(&list);
return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(array_list_shuffle, s_array_list_shuffle_fn)

static int s_array_list_shuffle_empty_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;
struct aws_array_list list;
ASSERT_SUCCESS(aws_array_list_init_dynamic(&list, allocator, 0, sizeof(uint32_t)));
ASSERT_SUCCESS(aws_array_list_shuffle(&list));

uint32_t val = 42;
ASSERT_SUCCESS(aws_array_list_push_back(&list, &val));
ASSERT_SUCCESS(aws_array_list_shuffle(&list));
uint32_t result = 0;
aws_array_list_get_at(&list, &result, 0);
ASSERT_UINT_EQUALS(42, result);

aws_array_list_clean_up(&list);
return AWS_OP_SUCCESS;
}
AWS_TEST_CASE(array_list_shuffle_empty, s_array_list_shuffle_empty_fn)