/*
 * Instituto Superior de Engenharia do Porto
 *
 * Estruturas de Informação
 *
 * 2000/2001
 *
 * (C) Paulo Sousa
 *
 * ------------------------------------------
 *
 * Trabalho nº 1
 *
 *	funções de utilitarios
 *
 */

#ifndef __UTILS_INC__
#define __UTILS_INC__


#define log2(N)		log(N)/log(2)

template <class T>
T min(T a, T b);

template <class T>
T max(T a, T b);

template <class T>
void troca(T& a, T& b);

template <class T>
bool verifica_ordenacao(const T v[], int nSize);

string tostring(bool v);

int random(int l, int h);

const int ERRO_ORDENACAO_INCORRECTA = -1;
const int ERRO_POLITICA_INVALIDA = -2;
const int ERRO_FUNCAO_INVALIDA = -3;


//
// macros auxiliares para teste de vectores de pequenas dimensões
//	(não esquecer de declarar simbolo do preprocessador __TEST_SMALL nos settings do projecto
//   ou retirar comentario na linha #define em baixo )
//	(para utilizar, colocar esta instrução nas comparações entre elementos do vector a ordenar,
//	 bem como nas atribuições aos elementos do vector)
//

//#define __TEST_SMALL

#ifdef __TEST_SMALL
#define TEST_SMALL_DELAY		{ int _j = 1; for (int _i = 0; _i < 500000; _i++) _j *= _i; }
#else
#define TEST_SMALL_DELAY
#endif


//
// macros auxiliares para contagem de instruções
//	(não esquecer de declarar simbolo do preprocessador __PROBE nos settings do projecto
//   ou retirar comentario na linha #define em baixo )
//

//#define __PROBE


#ifdef __PROBE
#define PROBE_DECLARE	\
	static int m_nComparisions;	\
	static int m_nSwaps;	\
	static int m_nAssignments;
#else
#define PROBE_DECLARE
#endif


#ifdef __PROBE
#define PROBE_IMPLEMENT(_Class)	\
	int _Class::m_nComparisions = 0;	\
	int _Class::m_nSwaps = 0;	\
	int _Class::m_nAssignments = 0;
#else
#define PROBE_DECLARE
#endif


#ifdef __PROBE
#define PROBE_INIT	\
	m_nComparisions = m_nSwaps = m_nAssignments = 0;
#else
#define PROBE_INIT
#endif


#ifdef __PROBE
#define PROBE_INC_CMP(i)	m_nComparisions += i;
#else
#define PROBE_INC_CMP(i)
#endif


#ifdef __PROBE
#define PROBE_INC_CMP1	m_nComparisions++;
#else
#define PROBE_INC_CMP1
#endif


#ifdef __PROBE
#define PROBE_INC_ASG(i)	m_nAssignments += i;
#else
#define PROBE_INC_ASG(i)
#endif


#ifdef __PROBE
#define PROBE_INC_ASG1	m_nAssignments++;
#else
#define PROBE_INC_ASG1
#endif


#ifdef __PROBE
#define PROBE_INC_SWP(i)	m_nSwaps += i;
#else
#define PROBE_INC_SWP(i)
#endif


#ifdef __PROBE
#define PROBE_INC_SWP1	m_nSwaps++;
#else
#define PROBE_INC_SWP1
#endif


#ifdef __PROBE
#define PROBE_OUTPUT(S)	\
	S << "-probe- C:" << m_nComparisions << " S:" << m_nSwaps << " A:" << m_nAssignments << endl;
#else
#define PROBE_OUTPUT(S)
#endif


//
// exemplo de utilização (no método)
//
/****

template <class T>
void BubbleSort<T>::bubblesort_1(T A[], int nSize)
{
	PROBE_INIT;

	PROBE_INC_ASG1;					// int i = nSize;
	for (int i = nSize; i > 1; i--)
	{
		PROBE_INC_CMP1;				// i > 1
		PROBE_INC_ASG1;				// int j = 0;
		for (int j = 0; j < i-1; j++)
		{
			PROBE_INC_CMP(2);		// j < i-1
									// A[j] > A[j+1]
			if (A[j] > A[j+1])
			{
				PROBE_INC_SWP1;		// troca(A[j], A[j+1]);
				troca(A[j], A[j+1]);
			}
			PROBE_INC_ASG1;			// j++
		}
		PROBE_INC_CMP1;				// j < i-1
		PROBE_INC_ASG1;				// i--
	}
	PROBE_INC_CMP1;					// i > 1

	PROBE_OUTPUT(cout);
}

 ****/

//
// exemplo de utilização (num qualquer ficheiro .cpp)
//
/****

  PROBE_IMPLEMENT(BubbleSort<int>);

 ****/


//----------------------------------------------------------
//
//				I M P L E M E N T A Ç Ã O
//
//----------------------------------------------------------



template <class T>
T min(T a, T b)
{
	return (a < b ? a : b);
}

template <class T>
T max(T a, T b)
{
	return (a > b ? a : b);
}

template <class T>
void troca(T& a, T& b)
{
	T c = a;
	a = b;
	b = c;

	TEST_SMALL_DELAY	// teste a vectores de dimensão reduzida
}

template <class T>
bool verifica_ordenacao(const T v[], int nSize)
{
	for (int i = 1; i < nSize; i++)
	{
		if (v[i-1] > v[i])
			return false;
	}
	return true;
}


#endif
