#include <cstddef>

template <class T>
class Node {
	public:
		T value;
		Node* next;
		Node* prev;
};

// forward declaration
template <class T> class ds_list;

template <class T>
class list_iterator{
	private:
		Node<T>* ptr;
	public:
		// default constructor
		list_iterator(){
			ptr = NULL;
		}
		list_iterator(Node<T>* p){
			ptr = p;
		}
		T operator*(){
			return ptr->value;
		}
		list_iterator operator++(){
			ptr = ptr->next;
			return *this;
		}
		bool operator!=(const list_iterator& other){
			return (ptr != other.ptr);
		}
		bool operator==(const list_iterator& other){
			return (ptr == other.ptr);
		}
		friend class ds_list<T>;
};

template <class T>
class ds_list {
	public:
		typedef list_iterator<T> iterator;
		// default constructor
		ds_list(){
			head = NULL;
			tail = NULL;
			m_size = 0;
		}
		// destructor
		~ds_list(){
			Node<T>* p = head;
			while(p != NULL){
				Node<T>* p2 = p->next;
				delete p;
				p = p2;
			}
		}
		void push_back(const T& v);
		void push_front(const T& v);
		void pop_back();
		T front(){
			return head->value;
		}
		T back(){
			return tail->value;
		}
		int size(){
			return m_size;
		}
		iterator begin(){
			return iterator(head);
		}
		iterator end(){
			return iterator(NULL);
		}
	private:
		Node<T>* head;
		Node<T>* tail;
		int m_size;
};

template <class T>
void ds_list<T>::push_back(const T& v){
	Node<T>* p = new Node<T>;
	p->value = v;
	// we are trying to add the first node
	if(tail == NULL){
		tail = p;
		head = p;
	}else{
		tail->next = p;
		p->prev = tail;
		tail = p;
		p->next = NULL;
	}
	++m_size;
}

template <class T>
void ds_list<T>::push_front(const T& v){
	Node<T>* p = new Node<T>;
	p->value = v;
	// we are trying to add the first node
	if(head == NULL){
		head = p;
		tail = p;
	}else{
		p->next = head;
		head->prev = p;
		head = p;
		p->prev = NULL;
	}
	++m_size;
}

template <class T>
void ds_list<T>::pop_back(){
	if(m_size < 1){
		return;
	}else if(m_size == 1){
		delete tail;
		head = NULL;
		tail = NULL;

	}else{
		// if(m_size > 1)
		Node<T>* p = tail->prev;
		p->next = NULL;
		delete tail;
		tail = p;
	}
	--m_size;
}
