// SPDX-FileComment: This file is part of TNL - Template Numerical Library (https://tnl-project.org/)
// SPDX-License-Identifier: MIT

#pragma once

#include <TNL/Backend.h>

namespace TNL::Algorithms::Segments::detail {

// This can be used for tuning the number of CUDA threads per block depending on the size of Value
// TODO: Perform some tests
static constexpr int CSRAdaptiveKernelParametersCudaBlockSizes[] = { 256, 256, 256, 256, 256, 256 };

template< int SizeOfValue = 1, int StreamedSharedMemory_ = 24576 >
struct CSRAdaptiveKernelParameters
{
   static constexpr int MaxValueSizeLog = 6;

   [[nodiscard]] static constexpr int
   getSizeValueLogConstexpr( int i );

   [[nodiscard]] static constexpr int
   getSizeOfValue()
   {
      return SizeOfValue;
   }

   static constexpr int SizeOfValueLog = getSizeValueLogConstexpr( SizeOfValue );

   static_assert( SizeOfValueLog < MaxValueSizeLog, "Parameter SizeOfValue is too large." );

   /**
    * \brief Computes number of CUDA threads per block depending on Value type.
    *
    * \return CUDA block size.
    */
   static constexpr int
   CudaBlockSize()
   {
      return CSRAdaptiveKernelParametersCudaBlockSizes[ SizeOfValueLog ];
   }
   //{ return SizeOfValue == 8 ? 128 : 256; };

   /**
    * \brief Returns amount of shared memory dedicated for stream CSR kernel.
    *
    * \return Stream shared memory.
    */
   [[nodiscard]] static constexpr std::size_t
   StreamedSharedMemory()
   {
      return StreamedSharedMemory_;
   }

   /**
    * \brief Number of elements fitting into streamed shared memory.
    */
   [[nodiscard]] static constexpr std::size_t
   StreamedSharedElementsCount()
   {
      return StreamedSharedMemory() / SizeOfValue;
   }

   /**
    * \brief Computes number of warps in one CUDA block.
    */
   [[nodiscard]] static constexpr std::size_t
   WarpsCount()
   {
      return CudaBlockSize() / Backend::getWarpSize();
   }

   /**
    * \brief Computes number of elements to be streamed into the shared memory.
    *
    * \return Number of elements to be streamed into the shared memory.
    */
   [[nodiscard]] static constexpr std::size_t
   StreamedSharedElementsPerWarp()
   {
      return StreamedSharedElementsCount() / WarpsCount();
   }

   /**
    * \brief Returns maximum number of elements per warp for vector and hybrid kernel.
    *
    * \return Maximum number of elements per warp for vector and hybrid kernel.
    */
   [[nodiscard]] static constexpr int
   MaxVectorElementsPerWarp()
   {
      return 384;
   }

   /**
    * \brief Returns maximum number of elements per warp for adaptive kernel.
    *
    * \return Maximum number of elements per warp for adaptive kernel.
    */
   [[nodiscard]] static constexpr int
   MaxAdaptiveElementsPerWarp()
   {
      return 512;
   }

   [[nodiscard]] static int
   getSizeValueLog( const int i )
   {
      if( i == 1 )
         return 0;
      if( i == 2 )
         return 1;
      if( i <= 4 )
         return 2;
      if( i <= 8 )
         return 3;
      if( i <= 16 )
         return 4;
      return 5;
   }
};

template< int SizeOfValue, int StreamedSharedMemory_ >
constexpr int
CSRAdaptiveKernelParameters< SizeOfValue, StreamedSharedMemory_ >::getSizeValueLogConstexpr( const int i )
{
   if( i == 1 )
      return 0;
   if( i == 2 )
      return 1;
   if( i <= 4 )
      return 2;
   if( i <= 8 )
      return 3;
   if( i <= 16 )
      return 4;
   if( i <= 32 )
      return 5;
   return 6;
}

}  // namespace TNL::Algorithms::Segments::detail
