/**
*************************************************************
* @file ArduinoList.pde
* Another implementation of linked lists to use in Arduino.
* Copyright (C) 2011 Gaspar Fernández
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* @brief Linked list implementation for Arduino
*
* Features:
* - Can access to head and tail directly
* - Can pop back and front from this class
* - Can access any item from the item number
* - Can set a callback function when an error occurs
*
* @author Gaspar Fernández
* @web http://totaki.com/poesiabinaria
* @version 0.1
* @date 27 nov 2011
* Change history
*
* To-do:
* - Better control over non-critical errors, maybe another callback
* - Pre-defined error methods: by serial, by output leds...
*************************************************************/
#define LLIST_ERROR_NOMEMORY 1 // Not enough memory to insert element
#define LLIST_ERROR_NOTAIL 2 // Can't get last items
#define LLIST_ERROR_NOFRONT 3 // Can't get head items
#define LLIST_ERROR_NOITEMS 4 // List empty, can't read items
#define LLIST_ERROR_NEITEMS 5 // Not enough items (pos>=sz)
template
class LList
{
public:
typedef void (*ErrorCallback)(int);
// We can add more error types
enum ListErrorType
{
NO_ERROR_REPORTING, // No error reporting
CALLBACK // Errors will trigger a callback
};
// Destruction. Clear data
~LList();
// Initialization
LList();
// Inserts new item in the last position
void push_back(const Type item);
// Is the list empty?
inline bool isEmpty() const;
// Returns the size of the list
inline int size();
// Returns the last item
inline Type back();
// Returns the first item
inline Type front();
// Return the last item and delete it
Type pop_back();
// Return the first item and delete it
Type pop_front();
// Get the item at position pos
Type getElement(unsigned pos);
// Insert a new item at position pos
void insert(int pos, Type item);
// set error callback function
void setErrorCallback(ErrorCallback cback);
// no error reporting
void setNoErrorReporting();
// clears the list
void clear();
private:
// Reports an error
void report_error(int err);
// Deletes a list when there is only one element
void delete_list();
typedef struct node
{
Type item;
node *next;
} node;
node *head; // Pointer to the head
node *tail; // Pointer to the tail
int sz; // List size
ListErrorType errorType;
ErrorCallback ecback; // Callback when reporting an error
};
template
LList::LList()
{
head=NULL;
tail=NULL;
sz=0;
errorType=NO_ERROR_REPORTING;
}
template
LList::~LList()
{
clear(); // Clears the list before destroying
}
template
void LList::push_back(const Type item)
{
node *aux=tail;
// Reserve memory for a new node
tail=(node*)malloc(sizeof(node));
if (tail==NULL)
{
report_error(LLIST_ERROR_NOMEMORY);
return;
}
// Stores the item information
tail->item=item;
tail->next=NULL;
// Link to the list
if (isEmpty())
head=tail;
else
aux->next=tail;
sz++;
}
template
bool LList::isEmpty() const
{
return (sz==0); // (sz==0) = EMPTY
}
template
int LList::size()
{
return sz;
}
template
inline Type LList::back()
{
if (isEmpty()) // List empty = No last item
{
Type t;
report_error(LLIST_ERROR_NOTAIL);
return t;
}
return tail->item;
}
template
inline Type LList::front()
{
if (isEmpty()) // List empty = No first item
{
Type t;
report_error(LLIST_ERROR_NOFRONT);
return t;
}
return head->item;
}
template
Type LList::pop_back()
{
node *aux=head;
Type t;
if (isEmpty()) // List empty = No last item
{
report_error(LLIST_ERROR_NOTAIL);
return t;
}
if (head==tail) // If there is only 1 item
{
t=head->item;
delete_list();
return t;
}
else
{ // More than one item
while (aux->next!=tail) // Searches for the item previous to the last
aux=aux->next;
t=tail->item; // I will return the tail item
free(tail);
tail=aux; // Define the new tail
tail->next=NULL;
sz--; // 1 item less
return t;
}
}
template
Type LList::pop_front()
{
Type t;
node *aux=head;
if (isEmpty()) // List empty = No head
{
report_error(LLIST_ERROR_NOFRONT);
return t;
}
t=aux->item; // I will return the head
head=head->next; // The new head is the item after the head
free(aux);
if (head==NULL) // If I had deleted the last item, replace the tail
tail=NULL; // too.
sz--;
return t;
}
template
void LList::delete_list()
{
free(head); // I will call this method when deleting
head=NULL; // a list with only one element, so all
tail=NULL; // the variables are set.
sz=0;
}
template
void LList::insert(int pos, Type item)
{
node *newitem;
node *aux=head;
int i;
// Allocate memory for the new item
newitem=(node*)malloc(sizeof(node));
if (newitem==NULL)
{
report_error(LLIST_ERROR_NOMEMORY);
return;
}
// Stores the item information
newitem->item=item;
newitem->next=NULL;
// Link the item to the list
if (isEmpty())
{ // If the list is empty there will be only
head=newitem; // one item, so it will be the head and the
tail=newitem; // tail.
}
else if (pos==0) // If the item is going to be inserted at the beginning
{
newitem->next=head; // we will move the head
head=newitem;
}
else if (pos>=sz) // If the position is greater than the last item's position
{ // it will be inserted after this item, at the tail.
tail->next=newitem;
tail=newitem;
}
else
{ // If not, we will have to find the position of the
i=0; // previous item to link its next pointer to the new
while (inext;
++i;
}
newitem->next=aux->next; // And then link the next pointer of our new element
aux->next=newitem; // to where the next pointer of the previour element
} // was pointing.
sz++;
}
template
Type LList::getElement(unsigned pos)
{
int i=0;
Type t;
node *aux=head;
if (isEmpty()) // If the list is empty = No data
{
report_error(LLIST_ERROR_NOITEMS);
return t;
}
if (pos>=sz) // If the item asked for is greater than the
{ // last item's position. There is no valid element
report_error(LLIST_ERROR_NEITEMS);
return t;
}
if (pos==sz-1) // If the item we asked for is the last, we can
return tail->item; // return it inmediately
while (inext;
i++;
}
return aux->item;
}
template
void LList::setErrorCallback(ErrorCallback cback)
{
ecback=cback; // This method sets the error callback to invoke
errorType=CALLBACK; // when an error occurs.
}
template
void LList::report_error(int err)
{
if (errorType==CALLBACK) // If the error reporting is through a callback,
{ // call it.
ecback(err);
}
}
template
void LList::clear()
{
node *aux;
while (head!=NULL) // Delete all elements
{
aux=head;
head=head->next;
free(aux);
}
tail=NULL; // Restore variable stats
sz=0;
}
template
void LList::setNoErrorReporting()
{
errorType=NO_ERROR_REPORTING;
}
// Test program
// LList l;
// void blink(int err)
// {
// while (1)
// {
// digitalWrite(11,HIGH);
// delay(1000);
// digitalWrite(11, LOW);
// delay(1000);
// }
// }
// void setup()
// {
// pinMode(11, OUTPUT);
// Serial.begin(9600);
// l.setErrorCallback(blink);
// l.push_back(45);
// l.push_back(42);
// l.push_back(47);
// l.push_back(89);
// l.insert(0, 33);
// l.insert(1, 53);
// l.insert(9, 73);
// // 33
// // 53
// // 45
// // 42
// // 47
// // 89
// // 73
// }
// void loop()
// {
// char r;
// if (Serial.available()>0)
// {
// while (Serial.available()>0)
// {
// r=Serial.read();
// delayMicroseconds(10000);
// }
// for (unsigned i=0; i