Browse Source

Adds doubly linked list implementation and tests

Signed-off-by: CapXilinx <melik-merkumians@acin.tuwien.ac.at>
CapXilinx 8 years ago
parent
commit
e4cb85705f

+ 1 - 1
source/src/utils/CMakeLists.txt

@@ -2,6 +2,6 @@
 opener_common_includes()
 opener_platform_spec()
 
-set( UTILS_SRC random.c xorshiftrandom.c)
+set( UTILS_SRC random.c xorshiftrandom.c doublylinkedlist.c)
 
 add_library( Utils ${UTILS_SRC} )

+ 109 - 0
source/src/utils/doublylinkedlist.c

@@ -0,0 +1,109 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include "doublylinkedlist.h"
+
+#include "opener_user_conf.h"
+
+void DoublyLinkedListInitialize(DoublyLinkedList *list,
+                                NodeMemoryAllocator allocator,
+                                NodeMemoryDeallocator deallocator) {
+  list->first = NULL;
+  list->last = NULL;
+  list->allocator = allocator;
+  list->deallocator = deallocator;
+}
+
+void DoublyLinkedListDestroy(DoublyLinkedList *list) {
+  DoublyLinkedListNode *iterator = list->first;
+  while(NULL != iterator) {
+    DoublyLinkedListNode *to_delete = iterator;
+    iterator = iterator->next;
+    DoublyLinkedListNodeDestroy(list, &to_delete);
+  }
+
+  list->first = NULL;
+  list->last = NULL;
+  list->allocator = NULL;
+  list->deallocator = NULL;
+}
+
+DoublyLinkedListNode *DoublyLinkedListNodeCreate(
+  void *data,
+  NodeMemoryAllocator const
+  allocator) {
+  DoublyLinkedListNode *new_node = (DoublyLinkedListNode *)allocator();
+  new_node->data = data;
+  return new_node;
+}
+
+void DoublyLinkedListNodeDestroy(DoublyLinkedList *list,
+                                 DoublyLinkedListNode **node) {
+  OPENER_ASSERT(list->deallocator != NULL);
+  list->deallocator(node);
+}
+
+void DoublyLinkedListInsertAtHead(DoublyLinkedList *const list,
+                                  void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                              list->allocator);
+  if(NULL == list->first) {
+    list->first = new_node;
+    list->last = new_node;
+  } else {
+    new_node->next = list->first;
+    list->first->previous = new_node;
+    list->first = new_node;
+  }
+}
+
+void DoublyLinkedListInsertAtTail(DoublyLinkedList *const list,
+                                  void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                              list->allocator);
+  if(NULL == list->last) {
+    list->first = new_node;
+    list->last = new_node;
+  } else {
+    new_node->previous = list->last;
+    list->last->next = new_node;
+    list->last = new_node;
+  }
+}
+
+void DoublyLinkedListInsertBeforeNode(DoublyLinkedList *const list,
+                                      DoublyLinkedListNode *node,
+                                      void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  if(list->first == node) {
+    DoublyLinkedListInsertAtHead(list, data);
+  } else {
+    DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                                list->allocator);
+    new_node->previous = node->previous;
+    new_node->next = node;
+    node->previous = new_node;
+    new_node->previous->next = new_node;
+  }
+}
+
+void DoublyLinkedListInsertAfterNode(DoublyLinkedList *const list,
+                                     DoublyLinkedListNode *node,
+                                     void *data) {
+  OPENER_ASSERT(list->allocator != NULL);
+  if(list->last == node) {
+    DoublyLinkedListInsertAtTail(list, data);
+  } else {
+    DoublyLinkedListNode *new_node = DoublyLinkedListNodeCreate(data,
+                                                                list->allocator);
+    new_node->previous = node;
+    new_node->next = node->next;
+    node->next->previous = new_node;
+    node->next = new_node;
+  }
+}

+ 63 - 0
source/src/utils/doublylinkedlist.h

@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#ifndef SRC_UTILS_DOUBLYLINKEDLIST_H_
+#define SRC_UTILS_DOUBLYLINKEDLIST_H_
+
+/**
+ * @file doublelinkedlist.h
+ *
+ * The public interface for a reference type doubly linked list
+ */
+
+typedef struct doubly_linked_list_node DoublyLinkedListNode;
+
+typedef DoublyLinkedListNode * (*NodeMemoryAllocator)();
+
+typedef void (*NodeMemoryDeallocator)(DoublyLinkedListNode **node);
+
+typedef struct doubly_linked_list_node {
+  DoublyLinkedListNode *previous;
+  DoublyLinkedListNode *next;
+  void *data;
+} DoublyLinkedListNode;
+
+typedef struct {
+  DoublyLinkedListNode *first;
+  DoublyLinkedListNode *last;
+
+  NodeMemoryAllocator allocator;
+  NodeMemoryDeallocator deallocator;
+
+} DoublyLinkedList;
+
+void DoublyLinkedListInitialize(DoublyLinkedList *list,
+                                NodeMemoryAllocator allocator,
+                                NodeMemoryDeallocator deallocator);
+
+void DoublyLinkedListDestroy(DoublyLinkedList *list);
+
+DoublyLinkedListNode *DoublyLinkedListNodeCreate(void *data,
+                                                 NodeMemoryAllocator allocator);
+
+void DoublyLinkedListNodeDestroy(DoublyLinkedList *list,
+                                 DoublyLinkedListNode **node);
+
+void DoublyLinkedListInsertAtHead(DoublyLinkedList *const list,
+                                  void *data);
+
+void DoublyLinkedListInsertAtTail(DoublyLinkedList *const list,
+                                  void *data);
+
+void DoublyLinkedListInsertBeforeNode(DoublyLinkedList *const list,
+                                      DoublyLinkedListNode *node,
+                                      void *data);
+
+void DoublyLinkedListInsertAfterNode(DoublyLinkedList *const list,
+                                     DoublyLinkedListNode *node,
+                                     void *data);
+
+#endif /* SRC_UTILS_DOUBLYLINKEDLIST_H_ */

+ 1 - 0
source/tests/OpENerTests.h

@@ -7,3 +7,4 @@ IMPORT_TEST_GROUP(CipEpath);
 IMPORT_TEST_GROUP(CipElectronicKey);
 IMPORT_TEST_GROUP(CipConnectionManager);
 IMPORT_TEST_GROUP(SocketTimer);
+IMPORT_TEST_GROUP(DoublyLinkedList);

+ 1 - 1
source/tests/utils/CMakeLists.txt

@@ -1,7 +1,7 @@
 
 opener_common_includes()
 
-set( UtilsTestSrc randomTests.cpp xorshiftrandomtests.cpp)
+set( UtilsTestSrc randomTests.cpp xorshiftrandomtests.cpp doublylinkedlistTests.cpp)
 
 include_directories( ${SRC_DIR}/utils )
 

+ 219 - 0
source/tests/utils/doublylinkedlistTests.cpp

@@ -0,0 +1,219 @@
+/*******************************************************************************
+ * Copyright (c) 2017, Rockwell Automation, Inc.
+ * All rights reserved.
+ *
+ ******************************************************************************/
+
+#include <CppUTest/TestHarness.h>
+#include <stdint.h>
+#include <string.h>
+
+extern "C" {
+#include <doublylinkedlist.h>
+}
+
+TEST_GROUP(DoublyLinkedList) {
+
+};
+
+const size_t kNodesAmount = 5;
+
+static DoublyLinkedListNode nodes[kNodesAmount] = { 0 };
+
+DoublyLinkedListNode *CallocAllocator() {
+  return (DoublyLinkedListNode *) calloc( 1, sizeof( DoublyLinkedListNode) );
+}
+
+void CallocDeallocator(DoublyLinkedListNode **node) {
+  free(*node);
+  *node = NULL;
+}
+
+DoublyLinkedListNode *ArrayAllocator() {
+  for(size_t i = 0; i < kNodesAmount; ++i) {
+    if(nodes[i].previous == NULL && nodes[i].next == NULL && nodes[i].data ==
+       NULL) {
+      return &nodes[i];
+    }
+  }
+  return NULL;
+}
+
+void ArrayFree(DoublyLinkedListNode **node) {
+  if(*node != NULL) {
+    memset( *node, 0, sizeof(DoublyLinkedListNode) );
+    *node = NULL;
+  }
+}
+
+TEST(DoublyLinkedList, CallocAllocatorCreateTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          CallocAllocator);
+  CHECK_EQUAL( test_data, *( (int *)node->data ) );
+  CallocDeallocator(&node);
+}
+
+TEST(DoublyLinkedList, CallocFreeTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          CallocAllocator);
+  CallocDeallocator(&node);
+  POINTERS_EQUAL(NULL, node);
+}
+
+TEST(DoublyLinkedList, ArrayAllocatorCreateTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          ArrayAllocator);
+  CHECK_EQUAL( test_data, *( (int *)node->data ) );
+  ArrayFree(&node);
+}
+
+TEST(DoublyLinkedList, ArrayAllocatorDeleteTest) {
+  int test_data = 8;
+  DoublyLinkedListNode *node = DoublyLinkedListNodeCreate(&test_data,
+                                                          ArrayAllocator);
+  DoublyLinkedListNode *assigned_array_slot = node;
+  ArrayFree(&node);
+  CHECK_EQUAL(8, test_data);
+  POINTERS_EQUAL(NULL, assigned_array_slot->data);
+  POINTERS_EQUAL(NULL, assigned_array_slot->previous);
+  POINTERS_EQUAL(NULL, assigned_array_slot->next);
+  POINTERS_EQUAL(NULL, node);
+}
+
+TEST(DoublyLinkedList, InitializeList) {
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  POINTERS_EQUAL(CallocAllocator, list.allocator);
+  POINTERS_EQUAL(CallocDeallocator, list.deallocator);
+}
+
+TEST(DoublyLinkedList, CheckDestroyListCleansInteralVaribles) {
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+  POINTERS_EQUAL(NULL, list.allocator);
+  POINTERS_EQUAL(NULL, list.deallocator);
+}
+
+TEST(DoublyLinkedList, InsertFirstAtHead) {
+  int test_data = 42;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertSecondAtHead) {
+  int test_data = 42;
+  int test_data_2 = 42 * 2;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  CHECK_EQUAL( 84, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, CheckDestroyListRemovesAllNodes) {
+  int test_data = 42;
+  int test_data_2 = 84;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertFirstAtTail) {
+  int test_data = 42;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 42, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertSecondAtTail) {
+  int test_data = 42;
+  int test_data_2 = 84;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtTail(&list, &test_data);
+  DoublyLinkedListInsertAtTail(&list, &test_data_2);
+  CHECK_EQUAL( 42, *(int *)(list.first->data) );
+  CHECK_EQUAL( 84, *(int *)(list.last->data) );
+  DoublyLinkedListDestroy(&list);
+  POINTERS_EQUAL(NULL, list.first);
+  POINTERS_EQUAL(NULL, list.last);
+}
+
+TEST(DoublyLinkedList, InsertAfterNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertAfterNode(&list, list.first, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.first->next->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertAfterLastNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertAfterNode(&list, list.last, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.last->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertBeforeNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertBeforeNode(&list, list.last, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.last->previous->data ) )
+  DoublyLinkedListDestroy(&list);
+}
+
+TEST(DoublyLinkedList, InsertBeforeFirstNode) {
+  int test_data_1 = 2;
+  int test_data_2 = 4;
+  int test_data_3 = 8;
+  DoublyLinkedList list;
+  DoublyLinkedListInitialize(&list, CallocAllocator, CallocDeallocator);
+  DoublyLinkedListInsertAtHead(&list, &test_data_1);
+  DoublyLinkedListInsertAtHead(&list, &test_data_2);
+  DoublyLinkedListInsertBeforeNode(&list, list.first, &test_data_3);
+  CHECK_EQUAL( 8, *( (int *)list.first->data ) )
+  DoublyLinkedListDestroy(&list);
+}