// TemplateList.h

// This file declares defines a singly linked list.
// It also demonstrates the use of Templates in C++.
// Some source code is inlined for efficiency.
// It all has to be in the header file (due to the templating).

// Author: Dr. Jeffrey Blessing

#define WIN32_LEAN_AND_MEAN			// speeds up non-MFC builds
#include <cstdlib>					// defines NULL
#include <iostream>					// used when overloading <<
using namespace std;

// Declare the List class so the Node class can forward reference it.

template<class T> class LinkedList;

// The Node class defines the elements in the list.

template<class T>
class Node
{
public:
	Node(T d=0, Node<T>* p=NULL): data(d), next(p) { }
private:
	T		data;
	Node<T>* next;
	friend class LinkedList<T>;
	template<class T>
	friend ostream& operator<<(ostream& os, const LinkedList<T>& src);
};

// The LinkedList class declares the list properties.

template<class T>
class LinkedList
{
public:
	LinkedList();		// constructor
	void add(T d);		// adds to the end of the list
	T getNext();		// returns the next element
	void start();		// resets the pointer to start of list
	~LinkedList();		// destructor
	LinkedList(const LinkedList<T>& src);	// copy constructor
	LinkedList<T>& operator=(const LinkedList<T>& src);	// assign. op.
	template<class T>
	friend ostream& operator<<(ostream& os, const LinkedList<T>& src);
private:
	Node<T>* head;		// start of list pointer
	Node<T>* tail;		// end of list pointer
	Node<T>* ptr;		// current element pointer
};

// The linked list implementation follows:

template<class T>
inline LinkedList<T>::LinkedList()
{
	// create header cell
	head = tail = ptr = new Node<T>();
//	ptr->next = NULL;
}

template<class T>
inline void LinkedList<T>::add(T d)
{
	// add to end of the list
	tail->next = new Node<T>();
	tail = tail->next;
	tail->data = d;
//	tail->next = NULL;
}

template<class T>
inline T LinkedList<T>::getNext()
{
	ptr = ptr->next;
	return ptr->data;
}

template<typename T>				// some prefer typename to class
inline void LinkedList<T>::start()
{
	ptr = head;
}

// destructor

template<class T>
inline LinkedList<T>::~LinkedList()
{
	// loop thru list destroying nodes
	start();
	while (ptr != NULL)
	{
		Node<T>* tmp = ptr->next;

		delete ptr;
		ptr = tmp;
	}
}

// copy constructor implementation

template<class T>
LinkedList<T>::LinkedList(const LinkedList<T>& src)
{
	// create hdr cell
	head = tail = ptr = new Node<T>();
	Node<T>* p = src.head;
	Node<T>* t = head;

	// copy the data elements
	while (p->next != NULL)
	{	t->next = new Node<T>();
		p = p->next;			// skip the header cell
		t = t->next;
		t->data = p->data;
		if (p == src.ptr) ptr = t;
	}

	// take care of last node
	tail = t;
}

// assignment operator implementation

template<class T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& src)
{
	// check first for self assignment
	if (this != &src)
	{
		// Destroy the dest list, then copy the src list into
		// this object's current location using the "placement
		// new" operator (Lippman's C++ Primer 3rd Ed. Ex.13.7)
		this->~LinkedList();
		new (this) LinkedList(src);
	}
	return *this;
}

// globally overloaded << operator

template<class T>
ostream& operator<<(ostream& os, const LinkedList<T>& src)
{
	Node<T>* p = src.head;

	do
	{	p = p->next;			// skip the header cell
		os << p->data << ", ";
	} while (p->next != NULL);

	return os;
}

