linked-list: Add method to compare two lists of objects for equality
authorTobias Brunner <tobias@strongswan.org>
Fri, 16 Oct 2015 10:12:43 +0000 (12:12 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 8 Mar 2016 09:21:57 +0000 (10:21 +0100)
src/libstrongswan/collections/linked_list.c
src/libstrongswan/collections/linked_list.h
src/libstrongswan/tests/suites/test_linked_list.c

index a176e5a..b8fe815 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2011 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
  * Copyright (C) 2005-2006 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -433,6 +433,56 @@ METHOD(linked_list_t, clone_offset, linked_list_t*,
        return clone;
 }
 
+METHOD(linked_list_t, equals_offset, bool,
+       private_linked_list_t *this, linked_list_t *other_pub, size_t offset)
+{
+       private_linked_list_t *other = (private_linked_list_t*)other_pub;
+       element_t *cur_t, *cur_o;
+
+       if (this->count != other->count)
+       {
+               return FALSE;
+       }
+       cur_t = this->first;
+       cur_o = other->first;
+       while (cur_t && cur_o)
+       {
+               bool (**method)(void*,void*) = cur_t->value + offset;
+               if (!(*method)(cur_t->value, cur_o->value))
+               {
+                       return FALSE;
+               }
+               cur_t = cur_t->next;
+               cur_o = cur_o->next;
+       }
+       return TRUE;
+}
+
+METHOD(linked_list_t, equals_function, bool,
+       private_linked_list_t *this, linked_list_t *other_pub,
+       bool (*fn)(void*,void*))
+{
+       private_linked_list_t *other = (private_linked_list_t*)other_pub;
+       element_t *cur_t, *cur_o;
+
+       if (this->count != other->count)
+       {
+               return FALSE;
+       }
+       cur_t = this->first;
+       cur_o = other->first;
+       while (cur_t && cur_o)
+       {
+               if (!fn(cur_t->value, cur_o->value))
+               {
+                       return FALSE;
+               }
+               cur_t = cur_t->next;
+               cur_o = cur_o->next;
+       }
+       return TRUE;
+}
+
 METHOD(linked_list_t, destroy, void,
        private_linked_list_t *this)
 {
@@ -503,6 +553,8 @@ linked_list_t *linked_list_create()
                        .invoke_offset = (void*)_invoke_offset,
                        .invoke_function = (void*)_invoke_function,
                        .clone_offset = _clone_offset,
+                       .equals_offset = _equals_offset,
+                       .equals_function = _equals_function,
                        .destroy = _destroy,
                        .destroy_offset = _destroy_offset,
                        .destroy_function = _destroy_function,
index abc33c1..5edaa07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2011 Tobias Brunner
+ * Copyright (C) 2007-2015 Tobias Brunner
  * Copyright (C) 2005-2008 Martin Willi
  * Copyright (C) 2005 Jan Hutter
  * Hochschule fuer Technik Rapperswil
@@ -218,6 +218,27 @@ struct linked_list_t {
        linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset);
 
        /**
+        * Compare two lists and their objects for equality using the given equals
+        * method.
+        *
+        * @param other         list to compare
+        * @param offset        offset of the objects equals method
+        * @return                      TRUE if lists and objects are equal, FALSE otherwise
+        */
+       bool (*equals_offset) (linked_list_t *this, linked_list_t *other,
+                                                  size_t offset);
+
+       /**
+        * Compare two lists and their objects for equality using the given function.
+        *
+        * @param other         list to compare
+        * @param function      function to compare the objects
+        * @return                      TRUE if lists and objects are equal, FALSE otherwise
+        */
+       bool (*equals_function) (linked_list_t *this, linked_list_t *other,
+                                                        bool (*)(void*,void*));
+
+       /**
         * Destroys a linked_list object.
         */
        void (*destroy) (linked_list_t *this);
index 922f954..7a16181 100644 (file)
@@ -348,6 +348,91 @@ START_TEST(test_clone_offset)
 }
 END_TEST
 
+
+/*******************************************************************************
+ * equals
+ */
+
+typedef struct equals_t equals_t;
+
+struct equals_t {
+       int val;
+       bool (*equals)(equals_t *a, equals_t *b);
+};
+
+static bool equalsfn(equals_t *a, equals_t *b)
+{
+       return a->val == b->val;
+}
+
+START_TEST(test_equals_offset)
+{
+       linked_list_t *other;
+       equals_t *x, items[] = {
+               { .val = 1, .equals = equalsfn, },
+               { .val = 2, .equals = equalsfn, },
+               { .val = 3, .equals = equalsfn, },
+               { .val = 4, .equals = equalsfn, },
+               { .val = 5, .equals = equalsfn, },
+       };
+       int i;
+
+       for (i = 0; i < countof(items); i++)
+       {
+               list->insert_last(list, &items[i]);
+       }
+       ck_assert(list->equals_offset(list, list, offsetof(equals_t, equals)));
+       other = linked_list_create_from_enumerator(list->create_enumerator(list));
+       ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals)));
+       other->remove_last(other, (void**)&x);
+       ck_assert(!list->equals_offset(list, other, offsetof(equals_t, equals)));
+       list->remove_last(list, (void**)&x);
+       ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals)));
+       other->remove_first(other, (void**)&x);
+       ck_assert(!list->equals_offset(list, other, offsetof(equals_t, equals)));
+       list->remove_first(list, (void**)&x);
+       ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals)));
+       while (list->remove_first(list, (void**)&x) == SUCCESS);
+       while (other->remove_first(other, (void**)&x) == SUCCESS);
+       ck_assert(list->equals_offset(list, other, offsetof(equals_t, equals)));
+       other->destroy(other);
+}
+END_TEST
+
+START_TEST(test_equals_function)
+{
+       linked_list_t *other;
+       equals_t *x, items[] = {
+               { .val = 1, },
+               { .val = 2, },
+               { .val = 3, },
+               { .val = 4, },
+               { .val = 5, },
+       };
+       int i;
+
+       for (i = 0; i < countof(items); i++)
+       {
+               list->insert_last(list, &items[i]);
+       }
+       ck_assert(list->equals_function(list, list, (void*)equalsfn));
+       other = linked_list_create_from_enumerator(list->create_enumerator(list));
+       ck_assert(list->equals_function(list, other, (void*)equalsfn));
+       other->remove_last(other, (void**)&x);
+       ck_assert(!list->equals_function(list, other, (void*)equalsfn));
+       list->remove_last(list, (void**)&x);
+       ck_assert(list->equals_function(list, other, (void*)equalsfn));
+       other->remove_first(other, (void**)&x);
+       ck_assert(!list->equals_function(list, other, (void*)equalsfn));
+       list->remove_first(list, (void**)&x);
+       ck_assert(list->equals_function(list, other, (void*)equalsfn));
+       while (list->remove_first(list, (void**)&x) == SUCCESS);
+       while (other->remove_first(other, (void**)&x) == SUCCESS);
+       ck_assert(list->equals_function(list, other, (void*)equalsfn));
+       other->destroy(other);
+}
+END_TEST
+
 Suite *linked_list_suite_create()
 {
        Suite *s;
@@ -386,5 +471,11 @@ Suite *linked_list_suite_create()
        tcase_add_test(tc, test_clone_offset);
        suite_add_tcase(s, tc);
 
+       tc = tcase_create("equals");
+       tcase_add_checked_fixture(tc, setup_list, teardown_list);
+       tcase_add_test(tc, test_equals_offset);
+       tcase_add_test(tc, test_equals_function);
+       suite_add_tcase(s, tc);
+
        return s;
 }