Merge pull request #226 from g-oikonomou/contrib/data-structures

Add libraries and example for common data structures
This commit is contained in:
Simon Duquennoy 2017-12-14 10:14:24 +01:00 committed by GitHub
commit c41d32d3eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2937 additions and 0 deletions

View File

@ -31,3 +31,4 @@ env:
- TEST_NAME='compile-nxp-ports'
- TEST_NAME='doxygen'
- TEST_NAME='compile-tools'
- TEST_NAME='native-runs'

View File

@ -0,0 +1,7 @@
CONTIKI_PROJECT = data-structures
all: $(CONTIKI_PROJECT)
CONTIKI = ../../..
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,383 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/stack.h"
#include "lib/queue.h"
#include "lib/circular-list.h"
#include "lib/dbl-list.h"
#include "lib/dbl-circ-list.h"
#include "lib/random.h"
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/*---------------------------------------------------------------------------*/
PROCESS(data_structure_process, "Data structure process");
AUTOSTART_PROCESSES(&data_structure_process);
/*---------------------------------------------------------------------------*/
STACK(demo_stack);
QUEUE(demo_queue);
CIRCULAR_LIST(demo_cll);
DBL_LIST(demo_dbl);
DBL_CIRC_LIST(demo_dblcl);
/*---------------------------------------------------------------------------*/
typedef struct demo_struct_s {
struct demo_struct_s *next;
struct demo_struct_s *previous;
unsigned short value;
} demo_struct_t;
/*---------------------------------------------------------------------------*/
#define DATA_STRUCTURE_DEMO_ELEMENT_COUNT 4
static demo_struct_t elements[DATA_STRUCTURE_DEMO_ELEMENT_COUNT];
/*---------------------------------------------------------------------------*/
static void
dbl_circ_list_print(dbl_circ_list_t dblcl)
{
demo_struct_t *this = *dblcl;
if(*dblcl == NULL) {
printf("Length=0\n");
return;
}
do {
printf("<--(0x%04x)--0x%04x--(0x%04x)-->", this->previous->value,
this->value, this->next->value);
this = this->next;
} while(this != *dblcl);
printf(" (Length=%lu)\n", dbl_circ_list_length(dblcl));
}
/*---------------------------------------------------------------------------*/
static void
demonstrate_dbl_circ_list(void)
{
int i;
demo_struct_t *this;
dbl_circ_list_init(demo_dblcl);
printf("============================\n");
printf("Circular, doubly-linked list\n");
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
elements[i].previous = NULL;
}
/* Add elements */
dbl_circ_list_add_tail(demo_dblcl, &elements[0]);
printf("Add tail : 0x%04x | ", elements[0].value);
dbl_circ_list_print(demo_dblcl);
dbl_circ_list_add_after(demo_dblcl, &elements[0], &elements[1]);
printf("Add after : 0x%04x | ", elements[1].value);
dbl_circ_list_print(demo_dblcl);
dbl_circ_list_add_head(demo_dblcl, &elements[2]);
printf("Add head : 0x%04x | ", elements[2].value);
dbl_circ_list_print(demo_dblcl);
dbl_circ_list_add_before(demo_dblcl, &elements[2], &elements[3]);
printf("Add before: 0x%04x | ", elements[3].value);
dbl_circ_list_print(demo_dblcl);
/* Remove head */
this = dbl_circ_list_head(demo_dblcl);
printf("Rm head: (0x%04x) | ", this->value);
dbl_circ_list_remove(demo_dblcl, this);
dbl_circ_list_print(demo_dblcl);
/* Remove currently second element */
this = ((demo_struct_t *)dbl_circ_list_head(demo_dblcl))->next;
printf("Rm 2nd : (0x%04x) | ", this->value);
dbl_circ_list_remove(demo_dblcl, this);
dbl_circ_list_print(demo_dblcl);
/* Remove tail */
this = dbl_circ_list_tail(demo_dblcl);
printf("Rm tail: (0x%04x) | ", this->value);
dbl_circ_list_remove(demo_dblcl, this);
dbl_circ_list_print(demo_dblcl);
/* Remove last remaining element */
this = dbl_circ_list_tail(demo_dblcl);
printf("Rm last: (0x%04x) | ", this->value);
dbl_circ_list_remove(demo_dblcl, this);
dbl_circ_list_print(demo_dblcl);
printf("Circular, doubly-linked list is%s empty\n",
dbl_circ_list_is_empty(demo_dblcl) ? "" : " not");
}
/*---------------------------------------------------------------------------*/
static void
dbl_list_print(dbl_list_t dll)
{
demo_struct_t *this;
for(this = *dll; this != NULL; this = this->next) {
printf("<--(");
if(this->previous == NULL) {
printf(" null ");
} else {
printf("0x%04x", this->previous->value);
}
printf(")--0x%04x--(", this->value);
if(this->next == NULL) {
printf(" null ");
} else {
printf("0x%04x", this->next->value);
}
printf(")-->");
}
printf(" (Length=%lu)\n", dbl_list_length(dll));
}
/*---------------------------------------------------------------------------*/
static void
demonstrate_dbl_list(void)
{
int i;
demo_struct_t *this;
dbl_list_init(demo_dbl);
printf("==================\n");
printf("Doubly-linked list\n");
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
elements[i].previous = NULL;
}
/* Add elements */
dbl_list_add_tail(demo_dbl, &elements[0]);
printf("Add tail : 0x%04x | ", elements[0].value);
dbl_list_print(demo_dbl);
dbl_list_add_after(demo_dbl, &elements[0], &elements[1]);
printf("Add after : 0x%04x | ", elements[1].value);
dbl_list_print(demo_dbl);
dbl_list_add_head(demo_dbl, &elements[2]);
printf("Add head : 0x%04x | ", elements[2].value);
dbl_list_print(demo_dbl);
dbl_list_add_before(demo_dbl, &elements[2], &elements[3]);
printf("Add before: 0x%04x | ", elements[3].value);
dbl_list_print(demo_dbl);
/* Remove head */
this = dbl_list_head(demo_dbl);
printf("Rm head: (0x%04x) | ", this->value);
dbl_list_remove(demo_dbl, this);
dbl_list_print(demo_dbl);
/* Remove currently second element */
this = ((demo_struct_t *)dbl_list_head(demo_dbl))->next;
printf("Rm 2nd : (0x%04x) | ", this->value);
dbl_list_remove(demo_dbl, this);
dbl_list_print(demo_dbl);
/* Remove tail */
this = dbl_list_tail(demo_dbl);
printf("Rm tail: (0x%04x) | ", this->value);
dbl_list_remove(demo_dbl, this);
dbl_list_print(demo_dbl);
/* Remove last remaining element */
this = dbl_list_tail(demo_dbl);
printf("Rm last: (0x%04x) | ", this->value);
dbl_list_remove(demo_dbl, this);
dbl_list_print(demo_dbl);
printf("Doubly-linked list is%s empty\n",
dbl_list_is_empty(demo_dbl) ? "" : " not");
}
/*---------------------------------------------------------------------------*/
static void
circular_list_print(circular_list_t cl)
{
demo_struct_t *this = *cl;
if(*cl == NULL) {
printf("Length=0\n");
return;
}
do {
printf("0x%04x-->", this->value);
this = this->next;
} while(this != *cl);
printf("0x%04x (Length=%lu)\n", this->value, circular_list_length(cl));
}
/*---------------------------------------------------------------------------*/
static void
demonstrate_circular_list(void)
{
int i;
circular_list_init(demo_cll);
printf("============================\n");
printf("Circular, singly-linked list\n");
/* Add elements */
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
circular_list_add(demo_cll, &elements[i]);
printf("Add: 0x%04x | ", elements[i].value);
circular_list_print(demo_cll);
}
/* Remove head */
circular_list_remove(demo_cll, circular_list_head(demo_cll));
printf("Remove head | ");
circular_list_print(demo_cll);
/* Remove currently second element */
circular_list_remove(demo_cll,
((demo_struct_t *)circular_list_head(demo_cll))->next);
printf("Remove 2nd | ");
circular_list_print(demo_cll);
/* Remove tail */
circular_list_remove(demo_cll, circular_list_tail(demo_cll));
printf("Remove tail | ");
circular_list_print(demo_cll);
/* Remove last remaining element */
circular_list_remove(demo_cll, circular_list_tail(demo_cll));
printf("Remove last | ");
circular_list_print(demo_cll);
printf("Circular list is%s empty\n",
circular_list_is_empty(demo_cll) ? "" : " not");
}
/*---------------------------------------------------------------------------*/
static void
demonstrate_stack(void)
{
int i;
demo_struct_t *this;
printf("=====\n");
printf("Stack\n");
stack_init(demo_stack);
/* Add elements */
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
stack_push(demo_stack, &elements[i]);
printf("Push: 0x%04x\n", elements[i].value);
}
printf("Peek: 0x%04x\n",
((demo_struct_t *)stack_peek(demo_stack))->value);
for(i = 0; i <= DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
this = stack_pop(demo_stack);
printf("Pop: ");
if(this == NULL) {
printf("(stack underflow)\n");
} else {
printf("0x%04x\n", this->value);
}
}
printf("Stack is%s empty\n",
stack_is_empty(demo_stack) ? "" : " not");
}
/*---------------------------------------------------------------------------*/
static void
demonstrate_queue(void)
{
int i;
demo_struct_t *this;
printf("=====\n");
printf("Queue\n");
queue_init(demo_queue);
/* Add elements */
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
queue_enqueue(demo_queue, &elements[i]);
printf("Enqueue: 0x%04x\n", elements[i].value);
}
printf("Peek: 0x%04x\n",
((demo_struct_t *)queue_peek(demo_queue))->value);
for(i = 0; i <= DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
this = queue_dequeue(demo_queue);
printf("Dequeue: ");
if(this == NULL) {
printf("(queue underflow)\n");
} else {
printf("0x%04lx\n", (unsigned long)this->value);
}
}
printf("Queue is%s empty\n",
queue_is_empty(demo_queue) ? "" : " not");
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(data_structure_process, ev, data)
{
int i;
PROCESS_BEGIN();
/* Generate some elements */
printf("Elements: [");
for(i = 0; i < DATA_STRUCTURE_DEMO_ELEMENT_COUNT; i++) {
elements[i].next = NULL;
elements[i].value = random_rand();
printf(" 0x%04x", elements[i].value);
}
printf(" ]\n");
demonstrate_stack();
demonstrate_queue();
demonstrate_circular_list();
demonstrate_dbl_list();
demonstrate_dbl_circ_list();
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

157
os/lib/circular-list.c Normal file
View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup circular-singly-linked-list
* @{
*
* \file
* Implementation of circular singly linked lists
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/circular-list.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
struct cl {
struct cl *next;
};
/*---------------------------------------------------------------------------*/
void
circular_list_init(circular_list_t cl)
{
*cl = NULL;
}
/*---------------------------------------------------------------------------*/
void *
circular_list_head(circular_list_t cl)
{
return *cl;
}
/*---------------------------------------------------------------------------*/
void *
circular_list_tail(circular_list_t cl)
{
struct cl *this;
if(*cl == NULL) {
return NULL;
}
for(this = *cl; this->next != *cl; this = this->next);
return this;
}
/*---------------------------------------------------------------------------*/
void
circular_list_remove(circular_list_t cl, void *element)
{
struct cl *this, *previous;
if(*cl == NULL) {
return;
}
/*
* We start traversing from the second element.
* The head will be visited last. We always update the list's head after
* removal, just in case we have just removed the head.
*/
previous = *cl;
this = previous->next;
do {
if(this == element) {
previous->next = this->next;
*cl = this->next == this ? NULL : previous;
return;
}
previous = this;
this = this->next;
} while(this != ((struct cl *)*cl)->next);
}
/*---------------------------------------------------------------------------*/
void
circular_list_add(circular_list_t cl, void *element)
{
struct cl *head;
if(element == NULL) {
return;
}
/* Don't add twice */
circular_list_remove(cl, element);
head = *cl;
if(head == NULL) {
/* If the list was empty, we update the new element to point to itself */
((struct cl *)element)->next = element;
} else {
/* If the list exists, we add the new element between the current head and
* the previously second element. */
((struct cl *)element)->next = head->next;
head->next = element;
}
/* In all cases, the new element becomes the list's new head */
*cl = element;
}
/*---------------------------------------------------------------------------*/
unsigned long
circular_list_length(circular_list_t cl)
{
unsigned long len = 1;
struct cl *this;
if(circular_list_is_empty(cl)) {
return 0;
}
for(this = *cl; this->next != *cl; this = this->next) {
len++;
}
return len;
}
/*---------------------------------------------------------------------------*/
bool
circular_list_is_empty(circular_list_t cl)
{
return *cl == NULL ? true : false;
}
/*---------------------------------------------------------------------------*/
/** @} */

155
os/lib/circular-list.h Normal file
View File

@ -0,0 +1,155 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/** \addtogroup data
* @{
*
* \defgroup circular-singly-linked-list Circular, singly-linked list
*
* This library provides functions for the creation and manipulation of
* circular, singly-linked lists.
*
* A circular, singly-linked list is declared using the CIRCULAR_LIST macro.
* Elements must be allocated by the calling code and must be of a C struct
* datatype. In this struct, the first field must be a pointer called \e next.
* This field will be used by the library to maintain the list. Application
* code must not modify this field directly.
*
* Functions that modify the list (add / remove) will, in the general case,
* update the list's head and item order. If you call one of these functions
* as part of a list traversal, it is advised to stop / restart traversing
* after the respective function returns.
* @{
*/
/*---------------------------------------------------------------------------*/
#ifndef CIRCULAR_LIST_H_
#define CIRCULAR_LIST_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
/**
* \brief Define a circular, singly-linked list.
*
* This macro defines a circular, singly-linked list.
*
* The datatype for elements must be a C struct. The struct's first member must
* be a pointer called \e next. This is used internally by the library to
* maintain data structure integrity and must not be modified directly by
* application code.
*
* \param name The name of the circular, singly-linked list.
*/
#define CIRCULAR_LIST(name) \
static void *name##_circular_list = NULL; \
static circular_list_t name = (circular_list_t)&name##_circular_list
/*---------------------------------------------------------------------------*/
/**
* \brief The circular, singly-linked list datatype
*/
typedef void **circular_list_t;
/*---------------------------------------------------------------------------*/
/**
* \brief Initialise a circular, singly-linked list.
* \param cl The circular, singly-linked list.
*/
void circular_list_init(circular_list_t cl);
/**
* \brief Return the tail of a circular, singly-linked list.
* \param cl The circular, singly-linked list.
* \return A pointer to the list's head, or NULL if the list is empty
*/
void *circular_list_head(circular_list_t cl);
/**
* \brief Return the tail of a circular, singly-linked list.
* \param cl The circular, singly-linked list.
* \return A pointer to the list's tail, or NULL if the list is empty
*/
void *circular_list_tail(circular_list_t cl);
/**
* \brief Add an element to a circular, singly-linked list.
* \param cl The circular, singly-linked list.
* \param element A pointer to the element to be added.
*
* The caller should make no assumptions as to the position in the list of the
* new element.
*
* After this function returns, the list's head is not guaranteed to be the
* same as it was before the addition.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void circular_list_add(circular_list_t cl, void *element);
/**
* \brief Remove an element from a circular, singly-linked list.
* \param cl The circular, singly-linked list.
* \param element A pointer to the element to be removed.
*
* After this function returns, the list's head is not guaranteed to be the
* same as it was before the addition.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void circular_list_remove(circular_list_t cl, void *element);
/**
* \brief Get the length of a circular, singly-linked list.
* \param cl The circular, singly-linked list.
* \return The number of elements in the list
*/
unsigned long circular_list_length(circular_list_t cl);
/**
* \brief Determine whether a circular, singly-linked list is empty.
* \param cl The circular, singly-linked list.
* \retval true The list is empty
* \retval false The list is not empty
*/
bool circular_list_is_empty(circular_list_t cl);
/*---------------------------------------------------------------------------*/
#endif /* CIRCULAR_LIST_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

227
os/lib/dbl-circ-list.c Normal file
View File

@ -0,0 +1,227 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup doubly-linked-circular-list
* @{
*
* \file
* Implementation of circular, doubly-linked lists
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/dbl-circ-list.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
struct dblcl {
struct dblcl *next;
struct dblcl *previous;
};
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_init(dbl_circ_list_t dblcl)
{
*dblcl = NULL;
}
/*---------------------------------------------------------------------------*/
void *
dbl_circ_list_head(dbl_circ_list_t dblcl)
{
return *dblcl;
}
/*---------------------------------------------------------------------------*/
void *
dbl_circ_list_tail(dbl_circ_list_t dblcl)
{
struct dblcl *this;
if(*dblcl == NULL) {
return NULL;
}
for(this = *dblcl; this->next != *dblcl; this = this->next);
return this;
}
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_remove(dbl_circ_list_t dblcl, void *element)
{
struct dblcl *this;
if(*dblcl == NULL || element == NULL) {
return;
}
this = *dblcl;
do {
if(this == element) {
this->previous->next = this->next;
this->next->previous = this->previous;
/* We need to update the head of the list if we removed the head */
if(*dblcl == element) {
*dblcl = this->next == this ? NULL : this->next;
}
this->next = NULL;
this->previous = NULL;
return;
}
this = this->next;
} while(this != *dblcl);
}
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_add_head(dbl_circ_list_t dblcl, void *element)
{
struct dblcl *head;
if(element == NULL) {
return;
}
/* Don't add twice */
dbl_circ_list_remove(dblcl, element);
head = dbl_circ_list_head(dblcl);
if(head == NULL) {
/* If the list was empty */
((struct dblcl *)element)->next = element;
((struct dblcl *)element)->previous = element;
} else {
/* If the list was not empty */
((struct dblcl *)element)->next = head;
((struct dblcl *)element)->previous = head->previous;
head->previous->next = element;
head->previous = element;
}
*dblcl = element;
}
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_add_tail(dbl_circ_list_t dblcl, void *element)
{
struct dblcl *tail;
if(element == NULL) {
return;
}
/* Don't add twice */
dbl_circ_list_remove(dblcl, element);
tail = dbl_circ_list_tail(dblcl);
if(tail == NULL) {
/* If the list was empty */
((struct dblcl *)element)->next = element;
((struct dblcl *)element)->previous = element;
*dblcl = element;
} else {
/* If the list was not empty */
((struct dblcl *)element)->next = *dblcl;
((struct dblcl *)element)->previous = tail;
tail->next->previous = element;
tail->next = element;
}
}
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_add_after(dbl_circ_list_t dblcl, void *existing, void *element)
{
if(element == NULL || existing == NULL) {
return;
}
/* Don't add twice */
dbl_circ_list_remove(dblcl, element);
((struct dblcl *)element)->next = ((struct dblcl *)existing)->next;
((struct dblcl *)element)->previous = existing;
((struct dblcl *)existing)->next->previous = element;
((struct dblcl *)existing)->next = element;
}
/*---------------------------------------------------------------------------*/
void
dbl_circ_list_add_before(dbl_circ_list_t dblcl, void *existing, void *element)
{
if(element == NULL || existing == NULL) {
return;
}
/* Don't add twice */
dbl_circ_list_remove(dblcl, element);
((struct dblcl *)element)->next = existing;
((struct dblcl *)element)->previous = ((struct dblcl *)existing)->previous;
((struct dblcl *)existing)->previous->next = element;
((struct dblcl *)existing)->previous = element;
/* If we added before the list's head, we must update the head */
if(*dblcl == existing) {
*dblcl = element;
}
}
/*---------------------------------------------------------------------------*/
unsigned long
dbl_circ_list_length(dbl_circ_list_t dblcl)
{
unsigned long len = 1;
struct dblcl *this;
if(*dblcl == NULL) {
return 0;
}
for(this = *dblcl; this->next != *dblcl; this = this->next) {
len++;
}
return len;
}
/*---------------------------------------------------------------------------*/
bool
dbl_circ_list_is_empty(dbl_circ_list_t dblcl)
{
return *dblcl == NULL ? true : false;
}
/*---------------------------------------------------------------------------*/
/** @} */

193
os/lib/dbl-circ-list.h Normal file
View File

@ -0,0 +1,193 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/** \addtogroup data
* @{
*
* \defgroup doubly-linked-circular-list Circular, doubly-linked list
*
* This library provides functions for the creation and manipulation of
* circular, doubly-linked lists.
*
* A circular, doubly-linked list is declared using the DBL_CIRC_LIST macro.
* Elements must be allocated by the calling code and must be of a C struct
* datatype. In this struct, the first field must be a pointer called \e next.
* The second field must be a pointer called \e previous.
* These fields will be used by the library to maintain the list. Application
* code must not modify these fields directly.
*
* Functions that modify the list (add / remove) will, in the general case,
* update the list's head and item order. If you call one of these functions
* as part of a list traversal, it is advised to stop / restart traversing
* after the respective function returns.
* @{
*/
/*---------------------------------------------------------------------------*/
#ifndef DBL_CIRC_LIST_H_
#define DBL_CIRC_LIST_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
/**
* \brief Define a circular, doubly-linked list.
*
* This macro defines a circular, doubly-linked list.
*
* The datatype for elements must be a C struct.
* The struct's first member must be a pointer called \e next.
* The second field must be a pointer called \e previous.
* These fields will be used by the library to maintain the list. Application
* code must not modify these fields directly.
*
* \param name The name of the circular, doubly-linked list.
*/
#define DBL_CIRC_LIST(name) \
static void *name##_dbl_circ_list = NULL; \
static dbl_list_t name = (dbl_circ_list_t)&name##_dbl_circ_list
/*---------------------------------------------------------------------------*/
/**
* \brief The doubly-linked list datatype
*/
typedef void **dbl_circ_list_t;
/*---------------------------------------------------------------------------*/
/**
* \brief Initialise a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
*/
void dbl_circ_list_init(dbl_circ_list_t dblcl);
/**
* \brief Return the tail of a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \return A pointer to the list's head, or NULL if the list is empty
*/
void *dbl_circ_list_head(dbl_circ_list_t dblcl);
/**
* \brief Return the tail of a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \return A pointer to the list's tail, or NULL if the list is empty
*/
void *dbl_circ_list_tail(dbl_circ_list_t dblcl);
/**
* \brief Add an element to the head of a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \param element A pointer to the element to be added.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_circ_list_add_head(dbl_circ_list_t dblcl, void *element);
/**
* \brief Add an element to the tail of a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \param element A pointer to the element to be added.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_circ_list_add_tail(dbl_circ_list_t dblcl, void *element);
/**
* \brief Add an element to a circular, doubly linked list after an existing element.
* \param dblcl The circular, doubly-linked list.
* \param existing A pointer to the existing element.
* \param element A pointer to the element to be added.
*
* This function will add \e element after \e existing
*
* The function will not verify that \e existing is already part of the list.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_circ_list_add_after(dbl_circ_list_t dblcl, void *existing,
void *element);
/**
* \brief Add an element to a circular, doubly linked list before an existing element.
* \param dblcl The circular, doubly-linked list.
* \param existing A pointer to the existing element.
* \param element A pointer to the element to be added.
*
* This function will add \e element before \e existing
*
* The function will not verify that \e existing is already part of the list.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_circ_list_add_before(dbl_circ_list_t dblcl, void *existing,
void *element);
/**
* \brief Remove an element from a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \param element A pointer to the element to be removed.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_circ_list_remove(dbl_circ_list_t dblcl, void *element);
/**
* \brief Get the length of a circular, doubly-linked list.
* \param dblcl The circular, doubly-linked list.
* \return The number of elements in the list
*/
unsigned long dbl_circ_list_length(dbl_circ_list_t dblcl);
/**
* \brief Determine whether a circular, doubly-linked list is empty.
* \param dblcl The circular, doubly-linked list.
* \retval true The list is empty
* \retval false The list is not empty
*/
bool dbl_circ_list_is_empty(dbl_circ_list_t dblcl);
/*---------------------------------------------------------------------------*/
#endif /* DBL_CIRC_LIST_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

226
os/lib/dbl-list.c Normal file
View File

@ -0,0 +1,226 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup doubly-linked-list
* @{
*
* \file
* Implementation of doubly-linked lists
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/dbl-list.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
struct dll {
struct dll *next;
struct dll *previous;
};
/*---------------------------------------------------------------------------*/
void
dbl_list_init(dbl_list_t dll)
{
*dll = NULL;
}
/*---------------------------------------------------------------------------*/
void *
dbl_list_head(dbl_list_t dll)
{
return *dll;
}
/*---------------------------------------------------------------------------*/
void *
dbl_list_tail(dbl_list_t dll)
{
struct dll *this;
if(*dll == NULL) {
return NULL;
}
for(this = *dll; this->next != NULL; this = this->next);
return this;
}
/*---------------------------------------------------------------------------*/
void
dbl_list_remove(dbl_list_t dll, void *element)
{
struct dll *this, *previous, *next;
if(*dll == NULL || element == NULL) {
return;
}
for(this = *dll; this != NULL; this = this->next) {
if(this == element) {
previous = this->previous;
next = this->next;
if(previous) {
previous->next = this->next;
}
if(next) {
next->previous = this->previous;
}
if(*dll == this) {
*dll = next;
}
return;
}
}
}
/*---------------------------------------------------------------------------*/
void
dbl_list_add_head(dbl_list_t dll, void *element)
{
struct dll *head;
if(element == NULL) {
return;
}
/* Don't add twice */
dbl_list_remove(dll, element);
head = dbl_list_head(dll);
((struct dll *)element)->previous = NULL;
((struct dll *)element)->next = head;
if(head) {
/* If the list was not empty, update ->previous on the old head */
head->previous = element;
}
*dll = element;
}
/*---------------------------------------------------------------------------*/
void
dbl_list_add_tail(dbl_list_t dll, void *element)
{
struct dll *tail;
if(element == NULL) {
return;
}
/* Don't add twice */
dbl_list_remove(dll, element);
tail = dbl_list_tail(dll);
if(tail == NULL) {
/* The list was empty */
*dll = element;
} else {
tail->next = element;
}
((struct dll *)element)->previous = tail;
((struct dll *)element)->next = NULL;
}
/*---------------------------------------------------------------------------*/
void
dbl_list_add_after(dbl_list_t dll, void *existing, void *element)
{
if(element == NULL || existing == NULL) {
return;
}
/* Don't add twice */
dbl_list_remove(dll, element);
((struct dll *)element)->next = ((struct dll *)existing)->next;
((struct dll *)element)->previous = existing;
if(((struct dll *)existing)->next) {
((struct dll *)existing)->next->previous = element;
}
((struct dll *)existing)->next = element;
}
/*---------------------------------------------------------------------------*/
void
dbl_list_add_before(dbl_list_t dll, void *existing, void *element)
{
if(element == NULL || existing == NULL) {
return;
}
/* Don't add twice */
dbl_list_remove(dll, element);
((struct dll *)element)->next = existing;
((struct dll *)element)->previous = ((struct dll *)existing)->previous;
if(((struct dll *)existing)->previous) {
((struct dll *)existing)->previous->next = element;
}
((struct dll *)existing)->previous = element;
/* If we added before the list's head, we must update the head */
if(*dll == existing) {
*dll = element;
}
}
/*---------------------------------------------------------------------------*/
unsigned long
dbl_list_length(dbl_list_t dll)
{
unsigned long len = 0;
struct dll *this;
if(*dll == NULL) {
return 0;
}
for(this = *dll; this != NULL; this = this->next) {
len++;
}
return len;
}
/*---------------------------------------------------------------------------*/
bool
dbl_list_is_empty(dbl_list_t dll)
{
return *dll == NULL ? true : false;
}
/*---------------------------------------------------------------------------*/
/** @} */

191
os/lib/dbl-list.h Normal file
View File

@ -0,0 +1,191 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/** \addtogroup data
* @{
*
* \defgroup doubly-linked-list Doubly-linked list
*
* This library provides functions for the creation and manipulation of
* doubly-linked lists.
*
* A doubly-linked list is declared using the DBL_LIST macro.
* Elements must be allocated by the calling code and must be of a C struct
* datatype. In this struct, the first field must be a pointer called \e next.
* The second field must be a pointer called \e previous.
* These fields will be used by the library to maintain the list. Application
* code must not modify these fields directly.
*
* Functions that modify the list (add / remove) will, in the general case,
* update the list's head and item order. If you call one of these functions
* as part of a list traversal, it is advised to stop / restart traversing
* after the respective function returns.
* @{
*/
/*---------------------------------------------------------------------------*/
#ifndef DBL_LIST_H_
#define DBL_LIST_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
/**
* \brief Define a doubly-linked list.
*
* This macro defines a doubly-linked list.
*
* The datatype for elements must be a C struct.
* The struct's first member must be a pointer called \e next.
* The second field must be a pointer called \e previous.
* These fields will be used by the library to maintain the list. Application
* code must not modify these fields directly.
*
* \param name The name of the doubly-linked list.
*/
#define DBL_LIST(name) \
static void *name##_dbl_list = NULL; \
static dbl_list_t name = (dbl_list_t)&name##_dbl_list
/*---------------------------------------------------------------------------*/
/**
* \brief The doubly-linked list datatype
*/
typedef void **dbl_list_t;
/*---------------------------------------------------------------------------*/
/**
* \brief Initialise a doubly-linked list.
* \param dll The doubly-linked list.
*/
void dbl_list_init(dbl_list_t dll);
/**
* \brief Return the tail of a doubly-linked list.
* \param dll The doubly-linked list.
* \return A pointer to the list's head, or NULL if the list is empty
*/
void *dbl_list_head(dbl_list_t dll);
/**
* \brief Return the tail of a doubly-linked list.
* \param dll The doubly-linked list.
* \return A pointer to the list's tail, or NULL if the list is empty
*/
void *dbl_list_tail(dbl_list_t dll);
/**
* \brief Add an element to the head of a doubly-linked list.
* \param dll The doubly-linked list.
* \param element A pointer to the element to be added.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_list_add_head(dbl_list_t dll, void *element);
/**
* \brief Add an element to the tail of a doubly-linked list.
* \param dll The doubly-linked list.
* \param element A pointer to the element to be added.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_list_add_tail(dbl_list_t dll, void *element);
/**
* \brief Add an element to a doubly linked list after an existing element.
* \param dll The doubly-linked list.
* \param existing A pointer to the existing element.
* \param element A pointer to the element to be added.
*
* This function will add \e element after \e existing
*
* The function will not verify that \e existing is already part of the list.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_list_add_after(dbl_list_t dll, void *existing, void *element);
/**
* \brief Add an element to a doubly linked list before an existing element.
* \param dll The doubly-linked list.
* \param existing A pointer to the existing element.
* \param element A pointer to the element to be added.
*
* This function will add \e element before \e existing
*
* The function will not verify that \e existing is already part of the list.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_list_add_before(dbl_list_t dll, void *existing, void *element);
/**
* \brief Remove an element from a doubly-linked list.
* \param dll The doubly-linked list.
* \param element A pointer to the element to be removed.
*
* Calling this function will update the list's head and item order. If you
* call this function as part of a list traversal, it is advised to stop
* traversing after this function returns.
*/
void dbl_list_remove(dbl_list_t dll, void *element);
/**
* \brief Get the length of a doubly-linked list.
* \param dll The doubly-linked list.
* \return The number of elements in the list
*/
unsigned long dbl_list_length(dbl_list_t dll);
/**
* \brief Determine whether a doubly-linked list is empty.
* \param dll The doubly-linked list.
* \retval true The list is empty
* \retval false The list is not empty
*/
bool dbl_list_is_empty(dbl_list_t dll);
/*---------------------------------------------------------------------------*/
#endif /* DBL_LIST_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

143
os/lib/queue.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup data
* @{
*
* \defgroup queue Queue library
*
* This library provides functions for the creation and manipulation of
* queues. The library is implemented as a wrapper around the list library.
*
* A queue is declared using the QUEUE macro. Queue elements must be
* allocated by the calling code and must be of a C struct datatype. In this
* struct, the first field must be a pointer called \e next. This field will
* be used by the library to maintain the queue. Application code must not
* modify this field directly.
* @{
*/
/*---------------------------------------------------------------------------*/
#ifndef QUEUE_H_
#define QUEUE_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/list.h"
#include <stdbool.h>
/*---------------------------------------------------------------------------*/
/**
* \brief The queue data type
*/
typedef list_t queue_t;
/*---------------------------------------------------------------------------*/
/**
* \brief Define a queue.
*
* This macro defines a queue.
*
* The datatype for elements must be a C struct. The struct's first member must
* be a pointer called \e next. This is used internally by the library to
* maintain data structure integrity and must not be modified directly by
* application code.
*
* \param name The name of the queue.
*/
#define QUEUE(name) LIST(name)
/*---------------------------------------------------------------------------*/
struct queue {
struct queue *next;
};
/*---------------------------------------------------------------------------*/
/**
* \brief Initialise a queue
* \param queue The queue
*/
static inline void
queue_init(queue_t queue)
{
list_init(queue);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Adds an element to the tail of the queue
* \param queue The queue
* \param element A pointer to the element to be added
*/
static inline void
queue_enqueue(queue_t queue, void *element)
{
list_add(queue, element);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Removes the element at the front of the queue
* \param queue The queue
* \return A pointer to the element removed
*
* If this function returns NULL if the queue was empty (queue underflow)
*/
static inline void *
queue_dequeue(queue_t queue)
{
return list_pop(queue);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Returns the front element of the queue, without removing it
* \param queue The queue
* \return A pointer to the element at the front of the queue
*/
static inline void *
queue_peek(queue_t queue)
{
return list_head(queue);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Check if a queue is empty
* \param queue The queue
* \retval true The queue is empty
* \retval false The queue has at least one element
*/
static inline bool
queue_is_empty(queue_t queue)
{
return *queue == NULL ? true : false;
}
/*---------------------------------------------------------------------------*/
#endif /* QUEUE_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

143
os/lib/stack.h Normal file
View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* Copyright (c) 2017, James Pope
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup data
* @{
*
* \defgroup stack-data-structure Stack library
*
* This library provides functions for the creation and manipulation of
* stacks. The library is implemented as a wrapper around the list library.
*
* A stack is declared using the STACK macro. Stack elements must be
* allocated by the calling code and must be of a C struct datatype. In this
* struct, the first field must be a pointer called \e next. This field will
* be used by the library to maintain the stack. Application code must not
* modify this field directly.
* @{
*/
/*---------------------------------------------------------------------------*/
#ifndef STACK_H_
#define STACK_H_
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/list.h"
#include <stdbool.h>
/*---------------------------------------------------------------------------*/
/**
* \brief The stack data type
*/
typedef list_t stack_t;
/*---------------------------------------------------------------------------*/
/**
* \brief Define a stack.
*
* This macro defines a stack.
*
* The datatype for elements must be a C struct. The struct's first member must
* be a pointer called \e next. This is used internally by the library to
* maintain data structure integrity and must not be modified directly by
* application code.
*
* \param name The name of the stack.
*/
#define STACK(name) LIST(name)
/*---------------------------------------------------------------------------*/
struct stack {
struct stack *next;
};
/*---------------------------------------------------------------------------*/
/**
* \brief Initialise a stack
* \param stack The stack
*/
static inline void
stack_init(stack_t stack)
{
list_init(stack);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Adds an element to the top of the stack
* \param stack The stack
* \param element A pointer to the element to be added
*/
static inline void
stack_push(stack_t stack, void *element)
{
list_push(stack, element);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Removes the top element from the stack
* \param stack The stack
* \return A pointer to the element popped
*
* If this function returns NULL if the stack was empty (stack underflow)
*/
static inline void *
stack_pop(stack_t stack)
{
return list_pop(stack);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Returns the top element of the stack, without popping it
* \param stack The stack
* \return A pointer to the element at the top of the stack
*/
static inline void *
stack_peek(stack_t stack)
{
return list_head(stack);
}
/*---------------------------------------------------------------------------*/
/**
* \brief Check if a stack is empty
* \param stack The stack
* \retval true The stack is empty
* \retval false The stack has at least one element
*/
static inline bool
stack_is_empty(stack_t stack)
{
return *stack == NULL ? true : false;
}
/*---------------------------------------------------------------------------*/
#endif /* STACK_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

View File

@ -10,6 +10,8 @@ multicast/sky \
libs/logging/native \
libs/energest/native \
libs/energest/sky \
libs/data-structures/native \
libs/data-structures/sky \
rpl-udp/sky \
rpl-border-router/native \
rpl-border-router/sky \

View File

@ -34,6 +34,7 @@ platform-specific/nrf52dk/coap-demo/nrf52dk:coap-client:SERVER_IPV6_ADDR=ffff \
platform-specific/nrf52dk/mqtt-demo/nrf52dk \
platform-specific/nrf52dk/blink-hello/nrf52dk \
platform-specific/nrf52dk/timer-test/nrf52dk \
libs/data-structures/nrf52dk \
libs/logging/nrf52dk
TOOLS=

View File

@ -26,6 +26,7 @@ http-socket/zoul \
libs/timers/zoul \
libs/energest/zoul \
libs/trickle-library/zoul \
libs/data-structures/zoul \
nullnet/zoul \
slip-radio/zoul \
storage/cfs-coffee/openmote-cc2538 \

View File

@ -0,0 +1,98 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>data-structures-sky</title>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>100.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.SkyMoteType
<identifier>sky1</identifier>
<description>Sky Mote Type #sky1</description>
<source EXPORT="discard">[CONTIKI_DIR]/tests/07-simulation-base/code-data-structures/test-data-structures.c</source>
<commands EXPORT="discard">make test-data-structures.sky TARGET=sky</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/tests/07-simulation-base/code-data-structures/test-data-structures.sky</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.SkyTemperature</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>3.086692968239446</x>
<y>5.726233183606267</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>sky1</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>280</width>
<z>2</z>
<height>160</height>
<location_x>400</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
<formatted_time />
<coloring />
</plugin_config>
<width>586</width>
<z>1</z>
<height>666</height>
<location_x>400</location_x>
<location_y>160</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.ScriptRunner
<plugin_config>
<scriptfile>[CONFIG_DIR]/js/data-structures.js</scriptfile>
<active>true</active>
</plugin_config>
<width>600</width>
<z>0</z>
<height>700</height>
<location_x>5</location_x>
<location_y>1</location_y>
</plugin>
</simconf>

View File

@ -0,0 +1,9 @@
all: test-data-structures
MODULES += os/services/unit-test
MAKE_MAC = MAKE_MAC_NULLMAC
MAKE_NET = MAKE_NET_NULLNET
CONTIKI = ../../..
include $(CONTIKI)/Makefile.include

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2017, Yasuyuki Tanaka
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
#define UNIT_TEST_PRINT_FUNCTION print_test_report
#endif /* PROJECT_CONF_H_ */

View File

@ -0,0 +1,897 @@
/*
* Copyright (c) 2017, George Oikonomou - http://www.spd.gr
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "lib/stack.h"
#include "lib/queue.h"
#include "lib/circular-list.h"
#include "lib/dbl-list.h"
#include "lib/dbl-circ-list.h"
#include "lib/random.h"
#include "services/unit-test/unit-test.h"
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
/*---------------------------------------------------------------------------*/
PROCESS(data_structure_test_process, "Data structure process");
AUTOSTART_PROCESSES(&data_structure_test_process);
/*---------------------------------------------------------------------------*/
typedef struct demo_struct_s {
struct demo_struct_s *next;
struct demo_struct_s *previous;
} demo_struct_t;
/*---------------------------------------------------------------------------*/
#define ELEMENT_COUNT 10
static demo_struct_t elements[ELEMENT_COUNT];
/*---------------------------------------------------------------------------*/
void
print_test_report(const unit_test_t *utp)
{
printf("=check-me= ");
if(utp->result == unit_test_failure) {
printf("FAILED - %s: exit at L%u\n", utp->descr, utp->exit_line);
} else {
printf("SUCCEEDED - %s\n", utp->descr);
}
}
/*---------------------------------------------------------------------------*/
UNIT_TEST_REGISTER(test_stack, "Stack Push/Pop");
UNIT_TEST(test_stack)
{
STACK(stack);
UNIT_TEST_BEGIN();
memset(elements, 0, sizeof(elements));
stack_init(stack);
/* Starts from empty */
UNIT_TEST_ASSERT(stack_is_empty(stack) == true);
UNIT_TEST_ASSERT(stack_peek(stack) == NULL);
UNIT_TEST_ASSERT(stack_pop(stack) == NULL);
/*
* Push two elements. Peek and pop should be the last one. Stack should be
* non-empty after the pop
*/
stack_push(stack, &elements[0]);
stack_push(stack, &elements[1]);
UNIT_TEST_ASSERT(stack_peek(stack) == &elements[1]);
UNIT_TEST_ASSERT(stack_pop(stack) == &elements[1]);
UNIT_TEST_ASSERT(stack_peek(stack) == &elements[0]);
UNIT_TEST_ASSERT(stack_is_empty(stack) == false);
UNIT_TEST_ASSERT(stack_pop(stack) == &elements[0]);
/* Ends empty */
UNIT_TEST_ASSERT(stack_is_empty(stack) == true);
UNIT_TEST_ASSERT(stack_peek(stack) == NULL);
UNIT_TEST_ASSERT(stack_pop(stack) == NULL);
UNIT_TEST_END();
}
/*---------------------------------------------------------------------------*/
UNIT_TEST_REGISTER(test_queue, "Queue Enqueue/Dequeue");
UNIT_TEST(test_queue)
{
QUEUE(queue);
UNIT_TEST_BEGIN();
memset(elements, 0, sizeof(elements));
queue_init(queue);
/* Starts from empty */
UNIT_TEST_ASSERT(queue_is_empty(queue) == true);
UNIT_TEST_ASSERT(queue_peek(queue) == NULL);
UNIT_TEST_ASSERT(queue_dequeue(queue) == NULL);
/* Enqueue three elements. They should come out in the same order */
queue_enqueue(queue, &elements[0]);
queue_enqueue(queue, &elements[1]);
queue_enqueue(queue, &elements[2]);
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[0]);
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[1]);
UNIT_TEST_ASSERT(queue_dequeue(queue) == &elements[2]);
/* Should be empty */
UNIT_TEST_ASSERT(queue_is_empty(queue) == true);
UNIT_TEST_ASSERT(queue_peek(queue) == NULL);
UNIT_TEST_ASSERT(queue_dequeue(queue) == NULL);
UNIT_TEST_END();
}
/*---------------------------------------------------------------------------*/
UNIT_TEST_REGISTER(test_csll, "Circular, singly-linked list");
UNIT_TEST(test_csll)
{
demo_struct_t *head, *tail;
CIRCULAR_LIST(csll);
UNIT_TEST_BEGIN();
memset(elements, 0, sizeof(elements));
circular_list_init(csll);
/* Starts from empty */
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
/* Add one element. Should point to itself and act as head and tail */
circular_list_add(csll, &elements[0]);
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == false);
UNIT_TEST_ASSERT(circular_list_length(csll) == 1);
UNIT_TEST_ASSERT(circular_list_head(csll) == &elements[0]);
UNIT_TEST_ASSERT(circular_list_tail(csll) == &elements[0]);
UNIT_TEST_ASSERT(elements[0].next == &elements[0]);
/* Add a second element. The two should point to each-other */
circular_list_add(csll, &elements[1]);
UNIT_TEST_ASSERT(elements[0].next == &elements[1]);
UNIT_TEST_ASSERT(elements[1].next == &elements[0]);
/*
* Add a third element and check that head->next->next points to tail.
* Check that tail->next points to the head
*/
circular_list_add(csll, &elements[2]);
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
/* Re-add an existing element. Check the list's integrity */
circular_list_add(csll, &elements[1]);
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == false);
UNIT_TEST_ASSERT(circular_list_length(csll) == 3);
UNIT_TEST_ASSERT(head->next->next->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
/* Add another two elements, then start testing removal */
circular_list_add(csll, &elements[3]);
circular_list_add(csll, &elements[4]);
/* Remove an item in the middle and test list integrity */
head = circular_list_head(csll);
circular_list_remove(csll, head->next->next);
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(circular_list_length(csll) == 4);
UNIT_TEST_ASSERT(head->next->next->next->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next->next->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
/* Remove the head and test list integrity */
circular_list_remove(csll, circular_list_head(csll));
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(circular_list_length(csll) == 3);
UNIT_TEST_ASSERT(head->next->next->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
/* Remove the tail and test list integrity */
circular_list_remove(csll, circular_list_tail(csll));
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(circular_list_length(csll) == 2);
UNIT_TEST_ASSERT(head->next->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
/*
* Remove the tail
* Only one item left: Make sure the head and tail are the same and point to
* each other
*/
circular_list_remove(csll, circular_list_tail(csll));
head = circular_list_head(csll);
tail = circular_list_tail(csll);
UNIT_TEST_ASSERT(circular_list_length(csll) == 1);
UNIT_TEST_ASSERT(head == tail);
UNIT_TEST_ASSERT(head->next->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next == circular_list_head(csll));
UNIT_TEST_ASSERT(head->next == circular_list_tail(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_head(csll));
UNIT_TEST_ASSERT(tail->next == circular_list_tail(csll));
/* Remove the last element by removing the head */
circular_list_remove(csll, circular_list_head(csll));
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
/* Remove the last element by removing the tail */
circular_list_add(csll, &elements[0]);
circular_list_remove(csll, circular_list_tail(csll));
UNIT_TEST_ASSERT(circular_list_is_empty(csll) == true);
UNIT_TEST_ASSERT(circular_list_length(csll) == 0);
UNIT_TEST_ASSERT(circular_list_head(csll) == NULL);
UNIT_TEST_ASSERT(circular_list_tail(csll) == NULL);
UNIT_TEST_END();
}
/*---------------------------------------------------------------------------*/
UNIT_TEST_REGISTER(test_dll, "Doubly-linked list");
UNIT_TEST(test_dll)
{
demo_struct_t *head, *tail;
CIRCULAR_LIST(dll);
UNIT_TEST_BEGIN();
memset(elements, 0, sizeof(elements));
/* Starts from empty */
dbl_list_init(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == true);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 0);
UNIT_TEST_ASSERT(dbl_list_head(dll) == NULL);
UNIT_TEST_ASSERT(dbl_list_tail(dll) == NULL);
/*
* Add an item by adding to the head.
* Head and tail should point to NULL in both directions
*/
dbl_list_add_head(dll, &elements[0]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
UNIT_TEST_ASSERT(head == &elements[0]);
UNIT_TEST_ASSERT(tail == &elements[0]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == NULL);
UNIT_TEST_ASSERT(tail->previous == NULL);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add an item by adding to the tail.
* Head and tail should point to NULL in both directions
*/
dbl_list_remove(dll, dbl_list_head(dll));
dbl_list_add_tail(dll, &elements[1]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
UNIT_TEST_ASSERT(head == &elements[1]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == NULL);
UNIT_TEST_ASSERT(tail->previous == NULL);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add a second item to head. Head points forward to tail.
* Tail points backwards to head.
*/
dbl_list_add_head(dll, &elements[2]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 2);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == tail);
UNIT_TEST_ASSERT(tail->previous == head);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add before head.
* NULL <-- 3 --> 2 --> 1 --> NULL
*/
dbl_list_add_before(dll, dbl_list_head(dll), &elements[3]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 3);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[2]);
UNIT_TEST_ASSERT(head->next->next == tail);
UNIT_TEST_ASSERT(head->next->next->next == NULL);
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
UNIT_TEST_ASSERT(tail->previous->previous == &elements[3]);
UNIT_TEST_ASSERT(tail->previous->previous->previous == NULL);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add after head.
* NULL <-- 3 --> 4 --> 2 --> 1 --> NULL
*/
dbl_list_add_after(dll, dbl_list_head(dll), &elements[4]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 4);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[4]);
UNIT_TEST_ASSERT(head->next->next == &elements[2]);
UNIT_TEST_ASSERT(head->next->next->next == tail);
UNIT_TEST_ASSERT(head->next->next->next->next == NULL);
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
UNIT_TEST_ASSERT(tail->previous->previous == &elements[4]);
UNIT_TEST_ASSERT(tail->previous->previous->previous == &elements[3]);
UNIT_TEST_ASSERT(tail->previous->previous->previous->previous == NULL);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add at 3rd position by adding after 2nd
* NULL <-- 3 --> 4 --> 5 --> 2 --> 1 --> NULL
*/
dbl_list_add_after(dll, &elements[4], &elements[5]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 5);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[4]);
UNIT_TEST_ASSERT(head->next->next == &elements[5]);
UNIT_TEST_ASSERT(tail->previous->previous == &elements[5]);
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
UNIT_TEST_ASSERT(elements[5].next == &elements[2]);
UNIT_TEST_ASSERT(elements[5].previous == &elements[4]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add at 3rd position by adding before 3rd
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 1 --> NULL
*/
dbl_list_add_before(dll, &elements[5], &elements[6]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 6);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[4]);
UNIT_TEST_ASSERT(head->next->next == &elements[6]);
UNIT_TEST_ASSERT(tail->previous->previous == &elements[5]);
UNIT_TEST_ASSERT(elements[6].next == &elements[5]);
UNIT_TEST_ASSERT(elements[6].previous == &elements[4]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add before tail
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 7 --> 1 --> NULL
*/
dbl_list_add_before(dll, dbl_list_tail(dll), &elements[7]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 7);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(tail->previous == &elements[7]);
UNIT_TEST_ASSERT(elements[7].next == &elements[1]);
UNIT_TEST_ASSERT(elements[7].previous == &elements[2]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Add after tail
* NULL <-- 3 --> 4 --> 6 --> 5 --> 2 --> 7 --> 1 --> 8 --> NULL
*/
dbl_list_add_after(dll, dbl_list_tail(dll), &elements[8]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 8);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(tail->previous == &elements[1]);
UNIT_TEST_ASSERT(elements[8].next == NULL);
UNIT_TEST_ASSERT(elements[8].previous == &elements[1]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Find and remove element 5
* NULL <-- 3 --> 4 --> 6 --> 2 --> 7 --> 1 --> 8 --> NULL
*/
dbl_list_remove(dll, &elements[5]);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 7);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(elements[6].next == &elements[2]);
UNIT_TEST_ASSERT(elements[2].previous == &elements[6]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Remove before tail
* NULL <-- 3 --> 4 --> 6 --> 2 --> 7 --> 8 --> NULL
*/
dbl_list_remove(dll, ((demo_struct_t *)dbl_list_tail(dll))->previous);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 6);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(elements[7].next == tail);
UNIT_TEST_ASSERT(tail->previous == &elements[7]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Remove after head
* NULL <-- 3 --> 6 --> 2 --> 7 --> 8 --> NULL
*/
dbl_list_remove(dll, ((demo_struct_t *)dbl_list_head(dll))->next);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 5);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[6]);
UNIT_TEST_ASSERT(elements[6].previous == head);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Find element 2 and remove whatever is after it
* NULL <-- 3 --> 6 --> 2 --> 8 --> NULL
*/
dbl_list_remove(dll, elements[2].next);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 4);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(elements[2].next == tail);
UNIT_TEST_ASSERT(tail->previous == &elements[2]);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Find element 2 and remove whatever is before it
* NULL <-- 3 --> 2 --> 8 --> NULL
*/
dbl_list_remove(dll, elements[2].previous);
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 3);
UNIT_TEST_ASSERT(head == &elements[3]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == &elements[2]);
UNIT_TEST_ASSERT(elements[2].previous == head);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Remove head
* NULL <-- 2 --> 8 --> NULL
*/
dbl_list_remove(dll, dbl_list_head(dll));
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 2);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == tail);
UNIT_TEST_ASSERT(tail->previous == head);
UNIT_TEST_ASSERT(tail->next == NULL);
/*
* Remove tail
* NULL <-- 8 --> NULL
*/
dbl_list_remove(dll, dbl_list_head(dll));
head = dbl_list_head(dll);
tail = dbl_list_tail(dll);
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == false);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 1);
UNIT_TEST_ASSERT(head == &elements[8]);
UNIT_TEST_ASSERT(tail == &elements[8]);
UNIT_TEST_ASSERT(head->previous == NULL);
UNIT_TEST_ASSERT(head->next == NULL);
UNIT_TEST_ASSERT(tail->previous == NULL);
UNIT_TEST_ASSERT(tail->next == NULL);
/* Remove the last element */
dbl_list_remove(dll, dbl_list_head(dll));
UNIT_TEST_ASSERT(dbl_list_is_empty(dll) == true);
UNIT_TEST_ASSERT(dbl_list_length(dll) == 0);
UNIT_TEST_ASSERT(dbl_list_head(dll) == NULL);
UNIT_TEST_ASSERT(dbl_list_tail(dll) == NULL);
UNIT_TEST_END();
}
/*---------------------------------------------------------------------------*/
UNIT_TEST_REGISTER(test_cdll, "Circular, doubly-linked list");
UNIT_TEST(test_cdll)
{
demo_struct_t *head, *tail;
CIRCULAR_LIST(cdll);
UNIT_TEST_BEGIN();
memset(elements, 0, sizeof(elements));
/* Starts from empty */
dbl_circ_list_init(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == true);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 0);
UNIT_TEST_ASSERT(dbl_circ_list_head(cdll) == NULL);
UNIT_TEST_ASSERT(dbl_circ_list_tail(cdll) == NULL);
/*
* Add an item by adding to the head.
* Head and tail should be the same element and should point to itself in
* both directions
*/
dbl_circ_list_add_head(cdll, &elements[0]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 1);
UNIT_TEST_ASSERT(head == &elements[0]);
UNIT_TEST_ASSERT(tail == &elements[0]);
UNIT_TEST_ASSERT(head->previous == head);
UNIT_TEST_ASSERT(head->next == head);
UNIT_TEST_ASSERT(tail->previous == tail);
UNIT_TEST_ASSERT(tail->next == tail);
/*
* Add an item by adding to the tail.
* (tail) <--> 0 <--> 1 <--> (head)
* Head should point to tail in both directions
*/
dbl_circ_list_add_tail(cdll, &elements[1]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 2);
UNIT_TEST_ASSERT(head == &elements[0]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->next == tail);
UNIT_TEST_ASSERT(tail->previous == head);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
/*
* Add before head.
* (tail) <--> 2 <--> 0 <--> 1 <--> (head)
*/
dbl_circ_list_add_before(cdll, dbl_circ_list_head(cdll), &elements[2]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 3);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[2].previous == tail);
UNIT_TEST_ASSERT(elements[2].next == &elements[0]);
UNIT_TEST_ASSERT(elements[0].previous == head);
/*
* Add after head.
* (tail) <--> 2 <--> 3 <--> 0 <--> 1 <--> (head)
*/
dbl_circ_list_add_after(cdll, dbl_circ_list_head(cdll), &elements[3]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 4);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[3].previous == head);
UNIT_TEST_ASSERT(elements[3].next == &elements[0]);
UNIT_TEST_ASSERT(elements[0].previous == &elements[3]);
/*
* Add at 3rd position by adding after 2nd
* (tail) <--> 2 <--> 3 <--> 4 <--> 0 <--> 1 <--> (head)
*/
dbl_circ_list_add_after(cdll, &elements[3], &elements[4]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 5);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[3].next == &elements[4]);
UNIT_TEST_ASSERT(elements[4].previous == &elements[3]);
UNIT_TEST_ASSERT(elements[4].next == &elements[0]);
UNIT_TEST_ASSERT(elements[0].previous == &elements[4]);
/*
* Add at 3rd position by adding before 3rd
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 1 <--> (head)
*/
dbl_circ_list_add_before(cdll, &elements[4], &elements[5]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 6);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[3].next == &elements[5]);
UNIT_TEST_ASSERT(elements[5].previous == &elements[3]);
UNIT_TEST_ASSERT(elements[5].next == &elements[4]);
UNIT_TEST_ASSERT(elements[4].previous == &elements[5]);
/*
* Add before tail
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 6 <--> 1 <--> (head)
*/
dbl_circ_list_add_before(cdll, dbl_circ_list_tail(cdll), &elements[6]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 7);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[1]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[0].next == &elements[6]);
UNIT_TEST_ASSERT(elements[6].previous == &elements[0]);
UNIT_TEST_ASSERT(elements[6].next == &elements[1]);
UNIT_TEST_ASSERT(elements[1].previous == &elements[6]);
/*
* Add after tail
* (tail) <--> 2 <--> 3 <--> 5 <--> 4 <--> 0 <--> 6 <--> 1 <--> 7 <--> (head)
*/
dbl_circ_list_add_after(cdll, dbl_circ_list_tail(cdll), &elements[7]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 8);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[1].next == &elements[7]);
UNIT_TEST_ASSERT(elements[7].previous == &elements[1]);
UNIT_TEST_ASSERT(elements[7].next == &elements[2]);
UNIT_TEST_ASSERT(elements[2].previous == &elements[7]);
/*
* Find and remove element 5
* (tail) <--> 2 <--> 3 <--> 4 <--> 0 <--> 6 <--> 1 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll, &elements[5]);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 7);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[3].next == &elements[4]);
UNIT_TEST_ASSERT(elements[4].previous == &elements[3]);
/*
* Find element 4 and remove what's after it
* (tail) <--> 2 <--> 3 <--> 4 <--> 6 <--> 1 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll, elements[4].next);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 6);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[4].next == &elements[6]);
UNIT_TEST_ASSERT(elements[6].previous == &elements[4]);
/*
* Find element 4 and remove what's before it
* (tail) <--> 2 <--> 4 <--> 6 <--> 1 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll, elements[4].previous);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 5);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[2].next == &elements[4]);
UNIT_TEST_ASSERT(elements[4].previous == &elements[2]);
/*
* Remove before tail
* (tail) <--> 2 <--> 4 <--> 6 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll,
((demo_struct_t *)dbl_circ_list_tail(cdll))->previous);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 4);
UNIT_TEST_ASSERT(head == &elements[2]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[6].next == &elements[7]);
UNIT_TEST_ASSERT(elements[7].previous == &elements[6]);
/*
* Remove after tail
* (tail) <--> 4 <--> 6 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll,
((demo_struct_t *)dbl_circ_list_tail(cdll))->next);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 3);
UNIT_TEST_ASSERT(head == &elements[4]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(tail->next == head);
UNIT_TEST_ASSERT(elements[7].next == &elements[4]);
UNIT_TEST_ASSERT(elements[4].previous == &elements[7]);
/*
* Remove after head
* (tail) <--> 4 <--> 7 <--> (head)
*/
dbl_circ_list_remove(cdll,
((demo_struct_t *)dbl_circ_list_head(cdll))->next);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 2);
UNIT_TEST_ASSERT(head == &elements[4]);
UNIT_TEST_ASSERT(tail == &elements[7]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(head->next == tail);
UNIT_TEST_ASSERT(tail->previous == head);
UNIT_TEST_ASSERT(tail->next == head);
/*
* Remove before head
* (tail) <--> 4 <--> (head)
*/
dbl_circ_list_remove(cdll,
((demo_struct_t *)dbl_circ_list_head(cdll))->previous);
head = dbl_circ_list_head(cdll);
tail = dbl_circ_list_tail(cdll);
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == false);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 1);
UNIT_TEST_ASSERT(head == &elements[4]);
UNIT_TEST_ASSERT(tail == &elements[4]);
UNIT_TEST_ASSERT(head->previous == tail);
UNIT_TEST_ASSERT(head->next == tail);
/* Remove head */
dbl_circ_list_remove(cdll, dbl_circ_list_head(cdll));
dbl_circ_list_remove(cdll, dbl_circ_list_head(cdll));
UNIT_TEST_ASSERT(dbl_circ_list_is_empty(cdll) == true);
UNIT_TEST_ASSERT(dbl_circ_list_length(cdll) == 0);
UNIT_TEST_ASSERT(dbl_circ_list_head(cdll) == NULL);
UNIT_TEST_ASSERT(dbl_circ_list_tail(cdll) == NULL);
UNIT_TEST_END();
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(data_structure_test_process, ev, data)
{
PROCESS_BEGIN();
printf("Run unit-test\n");
printf("---\n");
memset(elements, 0, sizeof(elements));
UNIT_TEST_RUN(test_stack);
UNIT_TEST_RUN(test_queue);
UNIT_TEST_RUN(test_csll);
UNIT_TEST_RUN(test_dll);
UNIT_TEST_RUN(test_cdll);
printf("=check-me= DONE\n");
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View File

@ -0,0 +1,25 @@
TIMEOUT(10000, log.testFailed());
var failed = false;
while(true) {
YIELD();
log.log(time + " " + "node-" + id + " "+ msg + "\n");
if(msg.contains("=check-me=") == false) {
continue;
}
if(msg.contains("FAILED")) {
failed = true;
}
if(msg.contains("DONE")) {
break;
}
}
if(failed) {
log.testFailed();
}
log.testOK();

View File

@ -0,0 +1,40 @@
#!/bin/bash
# Contiki directory
CONTIKI=$1
# Example code directory
CODE_DIR=$CONTIKI/tests/07-simulation-base/code-data-structures/
CODE=test-data-structures
# Starting Contiki-NG native node
echo "Starting native node"
make -C $CODE_DIR TARGET=native > make.log 2> make.err
$CODE_DIR/$CODE.native > $CODE.log 2> $CODE.err &
CPID=$!
sleep 2
echo "Closing native node"
sleep 2
pgrep $CODE | xargs kill -9
if grep -q "=check-me= FAILED" $CODE.log ; then
echo "==== make.log ====" ; cat make.log;
echo "==== make.err ====" ; cat make.err;
echo "==== $CODE.log ====" ; cat $CODE.log;
echo "==== $CODE.err ====" ; cat $CODE.err;
printf "%-32s TEST FAIL\n" "$CODE" | tee $CODE.testlog;
else
cp $CODE.log $CODE.testlog
printf "%-32s TEST OK\n" "$CODE" | tee $CODE.testlog;
fi
rm make.log
rm make.err
rm $CODE.log
rm $CODE.err
# We do not want Make to stop -> Return 0
# The Makefile will check if a log contains FAIL at the end
exit 0

View File

@ -0,0 +1 @@
include ../Makefile.script-test