/*! \file 
 * \brief Instanciation explicite pour les types `int`, `float` et `double` des fonctions
 *   reduceCPU, reduceGPU, sumCPU
 * 
 * 
 */
#include <cuda_runtime.h>

// Utilities and system includes
#include <helper_functions.h>
#include <helper_cuda.h>

// includes, project
#include "MyReduction.hpp"

/*! \brief  todo
 * 
*/
extern "C"
bool isPow2(unsigned int x)
{
    return ((x&(x-1))==0);
}

/*! \brief  todo
 * 
*/
unsigned int nextPow2( unsigned int x ) {
    --x;
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
    return ++x;
}

/*! \brief  todo
 * 
*/
#define LOCMIN(x,y) ((x < y) ? x : y)

/*! \brief  todo
 *  Compute the number of threads and blocks to use for the given reduction kernel
 *  For the kernels >= 3, we set threads / block to the minimum of maxThreads and
 *  n/2. For kernels < 3, we set to the minimum of maxThreads and n.  For kernel 
 *  6, we observe the maximum specified number of blocks, because each thread in 
 *  that kernel can process a variable number of elements.
*/
void getNumBlocksAndThreads(int n, int maxBlocks, int maxThreads, int &blocks, int &threads)
{
  threads = (n < maxThreads*2) ? nextPow2((n + 1)/ 2) : maxThreads;
  blocks = (n + (threads * 2 - 1)) / (threads * 2);
  blocks = LOCMIN(maxBlocks, blocks);
}

// Instanciation

////////////////////////////////////////////////////////////////////////////////
// Instanciation explicite pour les types <int>, <float> et <double> de :
//   reduceGPU, reduceCPU, sumCPU
////////////////////////////////////////////////////////////////////////////////
/*! \brief  Instantiate with `int`
 * 
*/
template int reduceGPU<int>(int *d_idata, int  n,
                int  maxThreads,
                int  maxBlocks, 
                int  cpuFinalThreshold);

/*! \brief  Instantiate with `float`
 * 
*/
template float reduceGPU<float>(float *d_idata, int  n,
                int  maxThreads,
                int  maxBlocks, 
                int  cpuFinalThreshold);

/*! \brief  Instantiate with `double`
 * 
*/
template double reduceGPU<double>(double *d_idata, int  n,
                int  maxThreads,
                int  maxBlocks, 
                int  cpuFinalThreshold);
		
/*! \brief  Instantiate with `int`
 * 
*/
template int reduceCPU<int>(int *data, int size);

/*! \brief  Instantiate with `float`
 * 
*/
template float reduceCPU<float>(float *data, int size);

/*! \brief  Instantiate with `double`
 * 
*/
template double reduceCPU<double>(double *data, int size);

/*! \brief  Instantiate with `int`
 * 
*/
template int sumCPU<int>(int *data, int size);

/*! \brief  Instantiate with `float`
 * 
*/
template float sumCPU<float>(float *data, int size);

/*! \brief  Instantiate with `double`
 * 
*/
template double sumCPU<double>(double *data, int size);
