#include <memory.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

template<class TYPE>
class mallocator
{
public:
	typedef TYPE			ELEMENT;
	typedef TYPE&			REF_ELEMENT;
	typedef const TYPE&		CONST_REF_ELEMENT;
	typedef TYPE*			PTR_ELEMENT;
	typedef PTR_ELEMENT		ITERATOR_TYPE;
	typedef const TYPE*		CONST_PTR_ELEMENT;
	typedef CONST_PTR_ELEMENT 	CONST_ITERATOR_TYPE;
	typedef ptrdiff_t		DIFERENCE;
	typedef size_t			SIZE;

	template<class OTHER_TYPE> struct other_mallocator{typedef mallocator<OTHER_TYPE> OTHER_MALLOCATOR;};

	mallocator(){}

	virtual ~mallocator(){}

	
	//allocate: reserva un hueco de memoria de n elementos de tipo TYPE. Si no es posible, se dispara la
	//excepción NOT_ENOUGH_MEMORY. La función devuelve la dirección del hueco de memoria.

	PTR_ELEMENT	allocate( SIZE n )
	{
		PTR_ELEMENT adress = PTR_ELEMENT( calloc(n, sizeof(TYPE) ) );
		if (!adress) cout <<"No hay memoria suficiente";//throw NOT_ENOUGH_MEMORY(elements);
		return adress;
	}


	//deallocate: libera un hueco de memoria previamente asignado. El parámetro que recibe indica la dirección
	//            de memoria donde comienza el hueco

	void deallocate( PTR_ELEMENT p )
	{
		free( (void *) p);
	}


	//construct: Construye, a través del constructor copia, un objeto de tipo TYPE en la dirección de memoria
	//           que se indica en el primer parámetro

	void construct( PTR_ELEMENT p, CONST_REF_ELEMENT value = TYPE () )
	{		
		new (p) TYPE (value); 
	}

	//destroy: Destruye un objeto de tipo TYPE localizado en la dirección de memoria que indica el parámetro.

	void destroy( PTR_ELEMENT p )
	{
		p->~ELEMENT();
	}

};

//Estructura genérica que engloba a todos los iteradores de toda estructura y que de ella derivan siguiendo 
//un orden según su funcionalidad, su tipo de contenedor y de cómo se calculan las distancias entre sus elementos
template<	class ITERATOR_TAG_CLASS,	//Define qué tipo de iter es, si de ent, de sal, si uni o bi o random
		class ELEMENT_CLASS,		//Tipo del contenedor
		class DISTANCE_CLASS      >     //Unids. de medida del resultado del cálculo de la distancia
class MITERATOR
{
	public:
		typedef ITERATOR_TAG_CLASS	ITERATOR_TAG;
		typedef DISTANCE_CLASS		DISTANCE;
		typedef ELEMENT_CLASS		ELEMENT;
		typedef ELEMENT_CLASS&		REF_ELEMENT;
		typedef ELEMENT_CLASS*		PTR_ELEMENT;
};

//Guía para derivaciones según tipo de iterador

struct OUTPUT_ITERATOR_TAG {}; 
struct INPUT_ITERATOR_TAG {};

struct FORWARD_ITERATOR_TAG : 		public INPUT_ITERATOR_TAG, public OUTPUT_ITERATOR_TAG {};
struct BIDIRECCIONAL_ITERATOR_TAG : 	public FORWARD_ITERATOR_TAG {};
struct RANDOM_ACCESS_ITERATOR_TAG : 	public BIDIRECCIONAL_ITERATOR_TAG {};

//Clase MITERATOR_TRAITS. ALMACENA INFORMACIÓN RELATIVA AL ELEMENTO
template <class ITERATOR>
struct MITERATOR_TRAITS
{
	typedef typename ITERATOR::ITERATOR_TAG	ITERATOR_TAG;
	typedef typename ITERATOR::DISTANCE	DISTANCE;
	typedef typename ITERATOR::ELEMENT	ELEMENT;
	typedef typename ITERATOR::REF_ELEMENT	REF_ELEMENT;
	typedef typename ITERATOR::PTR_ELEMENT	PTR_ELEMENT;
};


template <class PARAMETER, class RET>
struct munary_function
{
	typedef PARAMETER	ARG;

	typedef RET		RESULT;
};

//Restricción para funciones de dos parámetros
template <class PARAMETER1, class PARAMETER2, class RET>
struct mbinary_function
{
	typedef PARAMETER1	ARG1;
	typedef PARAMETER2	ARG2;

	typedef RET		RESULT;
};

//Clase que transforma una clase-función binaria en monaria
template <class BINARY_FUNCTION>
class set_arg1 : public munary_function<typename BINARY_FUNCTION::ARG2, typename BINARY_FUNCTION::RESULT>
{
	BINARY_FUNCTION 		bf;
	typename BINARY_FUNCTION::ARG1	arg1;

public:
	//Constructor copia
	set_arg1(const BINARY_FUNCTION& pbf, const typename BINARY_FUNCTION::ARG1& parg1):  bf(pbf), arg1(parg1) {}
	
	//Operador sobrecargado que devuelve el resultado de la funcíon ofb
	typename BINARY_FUNCTION::RESULT operator() (const typename BINARY_FUNCTION::ARG2& arg2)
	{
		return bf(arg1, arg2);
	}
};

template <class BINARY_FUNCTION>
class set_arg2 : public munary_function<typename BINARY_FUNCTION::ARG1, typename BINARY_FUNCTION::RESULT>
{
	BINARY_FUNCTION 		bf;
	typename BINARY_FUNCTION::ARG2	arg2;

public:
	//Constructor copia
	set_arg2(const BINARY_FUNCTION& pbf,  const typename BINARY_FUNCTION::ARG2& parg2):  bf(pbf), arg2(parg2) {}
	
	//Operador sobrecargado que devuelve el resultado de la funcíon ofb
	typename BINARY_FUNCTION::RESULT operator() (const typename BINARY_FUNCTION::ARG2& arg1)
	{
		return bf(arg1, arg2);
	}
};

//Funciones que llaman a set_arg1 y set_arg2 para hacer el código de llamadas más sencillo
template <class BINARY_FUNCTION>
set_arg1<BINARY_FUNCTION> setarg1(const BINARY_FUNCTION& bf, const typename BINARY_FUNCTION::ARG1& arg1)
{
	return set_arg1<BINARY_FUNCTION>(bf,arg1);
}

template <class BINARY_FUNCTION>
set_arg2<BINARY_FUNCTION> setarg2(const BINARY_FUNCTION& bf, const typename BINARY_FUNCTION::ARG1& arg2)
{
	return set_arg1<BINARY_FUNCTION>(bf,arg2);
}

//Función que recibe una función-método y que se transforma en un objeto función

template<class TYPE, class RET>
class member_to_function_ref : munary_function<TYPE&, RET>
{
	RET (TYPE::*pmf) ();
public:
	member_to_function_ref(RET (TYPE::*ppmf) () ): pmf(ppmf) {}
	RET operator () (TYPE& element) { return (element.*pmf) (); }
};

//función facilitadora para que quede bonita la llamada: mfor_each(a,a+19, membertofunctionref(&xxx::show));
//y ejecuta la función por cada elemento de a

template<class TYPE, class RET>
member_to_function_ref<TYPE, RET> membertofunctionref(RET (TYPE::*pmf) () )
{
	return member_to_function_ref<TYPE, RET>(pmf);
}

template<class TYPE, class RET>
class member_to_function_ptr : munary_function<TYPE*,RET>
{
	RET (TYPE::*pmf) ();
public:
	member_to_function_ptr(RET (TYPE::*ppmf) () ): pmf(ppmf) {}
	RET operator () (TYPE* element) { return (element->*pmf) (); }
};

//función facilitadora. Lo mismo pero lo hace sobre contenedores de punteros, y lo hace sobre elementos apuntados
template<class TYPE, class RET>
member_to_function_ref<TYPE, RET> membertofunctionptr(RET (TYPE::*pmf) () )
{
	return member_to_function_ptr<TYPE, RET>(pmf);
}

//Lo mismo de las dos clases anteriores pero cuando se le quiere pasar un parámetro al método 
template<class TYPE, class RET, class ARG>
class member_to_function_ref_p : munary_function<TYPE&, RET>
{
	RET (TYPE::*pmf) (ARG);
	ARG a;
public:
	member_to_function_ref_p(RET (TYPE::*ppmf) (ARG),ARG pa): pmf(ppmf),a(pa) {}
	RET operator () (TYPE& element) { return (element.*pmf) (a); }
};

//función facilitadora. 

template<class TYPE, class RET, class ARG>
member_to_function_ref_p<TYPE,RET,ARG> membertofunctionrefp(RET (TYPE::*pmf) (ARG), ARG a )
{
	return member_to_function_ref_p<TYPE, RET, ARG> (pmf,a);
}


template<class TYPE, class RET, class ARG>
class member_to_function_ptr_p : munary_function<TYPE*,RET>
{
	RET (TYPE::*pmf) (ARG);
	ARG a;
public:
	member_to_function_ptr_p(RET (TYPE::*ppmf) (ARG),ARG pa): pmf(ppmf),a(pa) {}
	RET operator () (TYPE& element) { return (element->*pmf) (a); }
};

//función facilitadora. Lo mismo pero lo hace sobre contenedores que son punteros

template<class TYPE, class RET, class ARG>
member_to_function_ref_p<TYPE, RET, ARG> membertofunctionptrp(RET (TYPE::*pmf) (ARG), ARG a )
{
	return member_to_function_ptr_p<TYPE, RET, ARG> (pmf,a);
}
