diff --git a/include/aws/common/linked_list.h b/include/aws/common/linked_list.h index 4f1800b37..38ecebc4d 100644 --- a/include/aws/common/linked_list.h +++ b/include/aws/common/linked_list.h @@ -69,6 +69,23 @@ AWS_STATIC_IMPL const struct aws_linked_list_node *aws_linked_list_end(const str return &list->tail; } +/** + * Returns a pointer for the last element in the list. + * Used to begin iterating the list in reverse. Ex: + * for (i = aws_linked_list_rbegin(list); i != aws_linked_list_rend(list); i = aws_linked_list_prev(i)) {...} + */ +AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_rbegin(const struct aws_linked_list *list) { + return list->tail.prev; +} + +/** + * Returns the pointer to one before the first element in the list. + * Used to end iterating the list in reverse. + */ +AWS_STATIC_IMPL const struct aws_linked_list_node *aws_linked_list_rend(const struct aws_linked_list *list) { + return &list->head; +} + /** * Returns the next element in the list. */ @@ -76,6 +93,13 @@ AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_next(const struct a return node->next; } +/** + * Returns the previous element in the list. + */ +AWS_STATIC_IMPL struct aws_linked_list_node *aws_linked_list_prev(const struct aws_linked_list_node *node) { + return node->prev; +} + /** * Inserts to_add immediately after after. */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1d4ac818d..d4b5bc173 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -81,6 +81,7 @@ add_test_case(priority_queue_remove_interior_sift_down_test) add_test_case(linked_list_push_back_pop_front) add_test_case(linked_list_push_front_pop_back) add_test_case(linked_list_iteration) +add_test_case(linked_list_reverse_iteration) add_test_case(linked_list_swap_contents) add_test_case(hex_encoding_test_case_empty_test) diff --git a/tests/linked_list_test.c b/tests/linked_list_test.c index bf283d01a..d3c93c2c7 100644 --- a/tests/linked_list_test.c +++ b/tests/linked_list_test.c @@ -115,6 +115,7 @@ static int s_test_linked_list_iteration(struct aws_allocator *allocator, void *c aws_linked_list_init(&list); ASSERT_TRUE(aws_linked_list_empty(&list)); + ASSERT_PTR_EQUALS(aws_linked_list_begin(&list), aws_linked_list_end(&list)); struct int_value first = (struct int_value){.value = 1}; struct int_value second = (struct int_value){.value = 2}; @@ -127,6 +128,7 @@ static int s_test_linked_list_iteration(struct aws_allocator *allocator, void *c aws_linked_list_push_back(&list, &fourth.node); ASSERT_FALSE(aws_linked_list_empty(&list)); + ASSERT_FALSE(aws_linked_list_begin(&list) == aws_linked_list_end(&list)); int count = 1; for (struct aws_linked_list_node *iter = aws_linked_list_begin(&list); iter != aws_linked_list_end(&list); @@ -140,6 +142,42 @@ static int s_test_linked_list_iteration(struct aws_allocator *allocator, void *c return 0; } +static int s_test_linked_list_reverse_iteration(struct aws_allocator *allocator, void *ctx) { + (void)allocator; + (void)ctx; + + struct aws_linked_list list; + + aws_linked_list_init(&list); + + ASSERT_TRUE(aws_linked_list_empty(&list)); + ASSERT_PTR_EQUALS(aws_linked_list_rbegin(&list), aws_linked_list_rend(&list)); + + struct int_value first = (struct int_value){.value = 1}; + struct int_value second = (struct int_value){.value = 2}; + struct int_value third = (struct int_value){.value = 3}; + struct int_value fourth = (struct int_value){.value = 4}; + + aws_linked_list_push_back(&list, &first.node); + aws_linked_list_push_back(&list, &second.node); + aws_linked_list_push_back(&list, &third.node); + aws_linked_list_push_back(&list, &fourth.node); + + ASSERT_FALSE(aws_linked_list_empty(&list)); + ASSERT_FALSE(aws_linked_list_rbegin(&list) == aws_linked_list_rend(&list)); + + int count = 4; + for (struct aws_linked_list_node *iter = aws_linked_list_rbegin(&list); iter != aws_linked_list_rend(&list); + iter = aws_linked_list_prev(iter)) { + + int item = AWS_CONTAINER_OF(iter, struct int_value, node)->value; + ASSERT_INT_EQUALS(count, item); + --count; + } + + return 0; +} + static int s_test_linked_list_swap_contents(struct aws_allocator *allocator, void *ctx) { (void)allocator; (void)ctx; @@ -232,4 +270,5 @@ static int s_test_linked_list_swap_contents(struct aws_allocator *allocator, voi AWS_TEST_CASE(linked_list_push_back_pop_front, s_test_linked_list_order_push_back_pop_front) AWS_TEST_CASE(linked_list_push_front_pop_back, s_test_linked_list_order_push_front_pop_back) AWS_TEST_CASE(linked_list_iteration, s_test_linked_list_iteration) +AWS_TEST_CASE(linked_list_reverse_iteration, s_test_linked_list_reverse_iteration) AWS_TEST_CASE(linked_list_swap_contents, s_test_linked_list_swap_contents)