#include <iostream>
#include <string>
#include <list>
#include <vector>
#include <cmath>
#include <algorithm>
#include <iterator>
using namespace std;

int max_prime(int n);
template<class T> struct EqualValue;
template<class T, class EV> class HashTable;
template<class T, class EV> ostream& operator<< (ostream& out, HashTable<T, EV> rhs);

template<class T, class EV>
class HashTable{
	friend ostream& operator<< <T,EV>(ostream& out, HashTable<T, EV> rhs);
public:
    HashTable(int s);
    void add_data(T data);
    void modify_data(T replace, T original);
    void remove_data(T data);
    bool find(T data);
    void print();
private:
	std::size_t hash_value(T data);
	
    int _size;
	vector<list<T> > u;
	EV equal_value;
};

template<class T, class EV>
HashTable<T, EV>::HashTable(int s=37):_size(max_prime(s)), u(vector<list<T> >(_size, list<T>())), equal_value(){}

template<class T, class EV>
std::size_t HashTable<T, EV>::hash_value(T data){
	return equal_value(data)%_size;
}

template<class T, class EV>
void HashTable<T, EV>::add_data(T data){
	u[hash_value(data)].push_back(data);
}

template<class T, class EV>
bool HashTable<T, EV>::find(T data){
	int index = hash_value(data);
    return u[index].end() == find(u[index].begin(), u[index].end(), data);
}

template<class T, class EV>
void HashTable<T, EV>::remove_data(T data){
	u[hash_value(data)].remove(data);
}

template<class T, class EV>
void HashTable<T, EV>::modify_data(T replace, T original){
	remove_data(original);
	add_data(replace);
}

template<class T, class EV>
ostream& operator<< (ostream& out, HashTable<T, EV> rhs){
	for(unsigned int i=0;i<rhs.u.size(); ++i){
		copy(rhs.u[i].begin(), rhs.u[i].end(), ostream_iterator<T>(out, " "));
		out << endl;
	}
	return out;
}

template<class T>
struct EqualValue{
   std::size_t operator()(T data){ return data.get_num(); }
};

template<> struct EqualValue<int>{
	std::size_t operator()(int data){ return data; };
};

int max_prime(int n){
    for(unsigned int i=n; 1; i++){
    	bool control = true;
    	unsigned int sqr = static_cast<unsigned int>(sqrt(static_cast<double>(i)));
        for(unsigned int j=2; j<sqr; j++){
        	if(i%j==0){
        		control = false;
        		break;
        	}
        }
    	if(control)  return i;
    }
}

int main() {
	HashTable<int, EqualValue<int> > u;
}
