#include<iostream>
#include <iterator>
using std::cout;
using std::endl;

template<typename T>
class MyList {
	struct Node {
		T val;
		Node* next;
	};
	Node* head;

	void copyFrom(const MyList& other) {
		if (!other.head) {
			head = nullptr;
			return;
		}

		Node* newLast = new Node();
		newLast->val = other.head->val;
		head = newLast;

		Node* otherNode = other.head->next;
		while (otherNode) {
			Node * newNode = new Node();
			newNode->val = otherNode->val;
			newLast->next = newNode;
			newLast = newNode;

			otherNode = otherNode->next;
		}

		newLast->next = nullptr;
	}

	public:
	MyList() :
		head(nullptr)
	{}
	~MyList()
	{
		while (!empty())
			pop();
	}

	MyList(const MyList & other) {
		copyFrom(other);
	}

	MyList & operator= (const MyList & other) {
		this->~MyList();

		copyFrom(other);
		return *this;
	}

	void push(const T& value) {
		Node* newNode = new Node();
		newNode->val = value;
		newNode->next = head;
		head = newNode;
	}

	T& front() const {
		return head->val;
	}

	bool empty() const {
		return !head;
	}

	void pop() {
		Node* tmp = head->next;
		delete head;
		head = tmp;
	}

	void clear(){
		while(!empty()){
			pop();
		}
	}

	class iterator {
		Node* curr;

		public:
		iterator(Node* head) {
			curr = head;
		}
		iterator &operator++() {
			curr = curr->next;
			return *this;
		}
		T &operator*(){
			return curr->val;
		}
		bool operator==(const iterator& other)
		{
			return curr == other.curr;
		}
		bool operator!=(const iterator& other)
		{
			return curr != other.curr;
		}

	};
#if someone_did_it
	const_iterator begin() const {
		return const_iterator(head);
	}
#endif

	iterator begin() {
		return iterator(head);
	}

	iterator end() {
		return iterator(nullptr);
	}

};

void test2() {
	MyList<MyList<int>> list;
	list.push(MyList<int>());
}

void test1() {
	MyList<int> a;

	a.push(1);
	a.push(2);
	a.push(3);

	MyList<int> b;
	b = a;
	MyList<int> c(a);

	a.pop();

	std::cout << b.front() << std::endl;
	std::cout << c.front() << std::endl;
}

void test()
{
	MyList<int> list;

	std::cout << list.empty() << std::endl;

	list.push(1);
	list.push(2);
	list.push(3);

	std::cout << list.front() << std::endl;
	std::cout << list.empty() << std::endl;

	list.pop();
	std::cout << list.front() << std::endl;
}

void printmylist(const MyList<float>& a) {
	for(auto i:a) cout << i << endl;
}

int main() 
{
	MyList<float> list;
	list.push(1);
	list.push(1);
	list.push(4);
	list.push(7);

	printmylist(list);

	return 0;
}

