This commit adds function that allows the appending of one list content to the other. Also, it adds functions which allows list to be sorted.
Signed-off-by: Alex Wang <al...@nicira.com> --- RFC->RFC V2: - Adopt Ben's suggestions. --- lib/list.h | 48 ++++++++++++++++++++++++ tests/library.at | 2 +- tests/test-list.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 1 deletion(-) diff --git a/lib/list.h b/lib/list.h index 7ba1e35..229f1c3 100644 --- a/lib/list.h +++ b/lib/list.h @@ -30,10 +30,12 @@ static inline void list_poison(struct ovs_list *); static inline void list_insert(struct ovs_list *, struct ovs_list *); static inline void list_splice(struct ovs_list *before, struct ovs_list *first, struct ovs_list *last); +static inline void list_join(struct ovs_list *dst, struct ovs_list *src); static inline void list_push_front(struct ovs_list *, struct ovs_list *); static inline void list_push_back(struct ovs_list *, struct ovs_list *); static inline void list_replace(struct ovs_list *, const struct ovs_list *); static inline void list_moved(struct ovs_list *, const struct ovs_list *orig); +static inline void list_swap(struct ovs_list *, struct ovs_list *); static inline void list_move(struct ovs_list *dst, struct ovs_list *src); /* List removal. */ @@ -44,6 +46,8 @@ static inline struct ovs_list *list_pop_back(struct ovs_list *); /* List elements. */ static inline struct ovs_list *list_front(const struct ovs_list *); static inline struct ovs_list *list_back(const struct ovs_list *); +static inline struct ovs_list *list_at_position(const struct ovs_list *, + size_t n); /* List properties. */ static inline size_t list_size(const struct ovs_list *); @@ -104,6 +108,14 @@ list_insert(struct ovs_list *before, struct ovs_list *elem) before->prev = elem; } +/* Appends 'src''s content to the end of 'dst'. After 'list_join', 'src' + * becomes an empty list. */ +static inline void +list_join(struct ovs_list *dst, struct ovs_list *src) +{ + list_splice(dst, src->next, src); +} + /* Removes elements 'first' though 'last' (exclusive) from their current list, then inserts them just before 'before'. */ static inline void @@ -152,6 +164,25 @@ list_replace(struct ovs_list *element, const struct ovs_list *position) element->prev->next = element; } +/* Exchanges the positions of A and B, which may be in the same list + * or different lists. */ +static inline void +list_swap(struct ovs_list *a, struct ovs_list *b) +{ + if (a != b) { + if (a->next != b) { + struct ovs_list *a_next = list_remove(a); + struct ovs_list *b_next = list_remove(b); + + list_insert(b_next, a); + list_insert(a_next, b); + } else { + list_remove(b); + list_insert(a, b); + } + } +} + /* Adjusts pointers around 'list' to compensate for 'list' having been moved * around in memory (e.g. as a consequence of realloc()), with original * location 'orig'. @@ -236,6 +267,23 @@ list_back(const struct ovs_list *list_) return list->prev; } +/* Returns the element at position 'n', assumes the first element is + * at index 0. The 'list_' must contain at least 'n' elements. */ +static inline struct ovs_list * +list_at_position(const struct ovs_list *list_, size_t n) +{ + struct ovs_list *list = CONST_CAST(struct ovs_list *, list_); + struct ovs_list *ret; + size_t cnt = 0; + + for (ret = list->next; ret != list; ret = ret->next) { + if (cnt++ == n) { + return ret; + } + } + OVS_NOT_REACHED(); +} + /* Returns the number of elements in 'list'. Runs in O(n) in the number of elements. */ static inline size_t diff --git a/tests/library.at b/tests/library.at index 9bd6d81..cb1f858 100644 --- a/tests/library.at +++ b/tests/library.at @@ -38,7 +38,7 @@ AT_CHECK([ovstest test-atomic]) AT_CLEANUP AT_SETUP([test linked lists]) -AT_CHECK([ovstest test-list], [0], [... +AT_CHECK([ovstest test-list], [0], [....... ]) AT_CLEANUP diff --git a/tests/test-list.c b/tests/test-list.c index 9b6b0bd..5c16990 100644 --- a/tests/test-list.c +++ b/tests/test-list.c @@ -20,6 +20,7 @@ #include <config.h> #undef NDEBUG #include "list.h" +#include "sort.h" #include <assert.h> #include <string.h> #include "ovstest.h" @@ -185,6 +186,107 @@ test_list_for_each_pop(void) } static void +test_list_swap_elem(void) +{ + enum { MAX_ELEMS = 100 }; + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + size_t n = MAX_ELEMS; + struct ovs_list list; + + make_list(&list, elements, values, n); + elements[1].value = 50; + elements[50].value = 1; + list_swap(&elements[1].node, &elements[50].node); + elements[9].value = 10; + elements[10].value = 9; + list_swap(&elements[9].node, &elements[10].node); + elements[19].value = 20; + elements[20].value = 19; + list_swap(&elements[20].node, &elements[19].node); + list_swap(&elements[29].node, &elements[29].node); + check_list(&list, values, n); +} + +static void +test_list_at_position(void) +{ + enum { MAX_ELEMS = 10 }; + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + size_t n = MAX_ELEMS; + struct ovs_list list; + + make_list(&list, elements, values, n); + for (n = 0; n < MAX_ELEMS; n++) { + struct ovs_list *node = list_at_position(&list, n); + + ovs_assert(node == &elements[n].node); + } +} + +static int +test_list_compare(size_t a, size_t b, void *aux) +{ + struct ovs_list *list = aux; + struct element *elem1, *elem2; + + elem1 = CONTAINER_OF(list_at_position(list, a), struct element, node); + elem2 = CONTAINER_OF(list_at_position(list, b), struct element, node); + + return elem1->value - elem2->value; +} + +static void +test_list_swap(size_t a, size_t b, void *aux) +{ + struct ovs_list *list = aux; + + list_swap(list_at_position(list, a), list_at_position(list, b)); +} + +static void +test_list_sort(void) +{ + enum { MAX_ELEMS = 10 }; + struct element elements[MAX_ELEMS]; + int values[MAX_ELEMS]; + size_t n = MAX_ELEMS; + struct ovs_list list; + + make_list(&list, elements, values, n); + for (n = 0; n < MAX_ELEMS; n++) { + elements[n].value = MAX_ELEMS - 1 - n; + } + /* Sorts the list in ascending order of priority. */ + sort(n, test_list_compare, test_list_swap, &list); + check_list(&list, values, n); +} + +static void +test_list_join(void) +{ + enum { MAX_ELEMS = 10 }; + struct element elements_1[MAX_ELEMS]; + struct element elements_2[MAX_ELEMS]; + int values[2*MAX_ELEMS]; + size_t n = MAX_ELEMS; + struct ovs_list list_dst, list_src; + + make_list(&list_dst, elements_1, values, n); + make_list(&list_src, elements_2, values, n); + /* Makes 'elements_2' contains values {MAX_ELEMS..2*MAX_ELEMS-1}. */ + for (n = MAX_ELEMS; n < 2*MAX_ELEMS; n++) { + elements_2[n-MAX_ELEMS].value += MAX_ELEMS; + values[n] = n; + } + + list_join(&list_dst, &list_src); + assert(list_is_empty(&list_src)); + check_list(&list_dst, values, 2*MAX_ELEMS); +} + +static void run_test(void (*function)(void)) { function(); @@ -197,6 +299,10 @@ test_list_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) run_test(test_list_construction); run_test(test_list_for_each_safe); run_test(test_list_for_each_pop); + run_test(test_list_swap_elem); + run_test(test_list_at_position); + run_test(test_list_sort); + run_test(test_list_join); printf("\n"); } -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev