/***************************************************************************
                          ArrayAssignment.h  -  description
                             -------------------
    begin                : Apr 4, 2019
    copyright            : (C) 2019 by Tomas Oberhuber
    email                : tomas.oberhuber@fjfi.cvut.cz
 ***************************************************************************/

/* See Copyright Notice in tnl/Copyright */

#pragma once

#include <TNL/TypeTraits.h>
#include <TNL/Algorithms/MemoryOperations.h>
#include <TNL/Algorithms/MultiDeviceMemoryOperations.h>

namespace TNL {
namespace Containers {
namespace detail {

template< typename Array,
          typename T,
          bool isArrayType = IsArrayType< T >::value >
struct ArrayAssignment;

/**
 * \brief Specialization for array-array assignment with containers implementing
 * getArrayData method.
 */
template< typename Array,
          typename T >
struct ArrayAssignment< Array, T, true >
{
   static void resize( Array& a, const T& t )
   {
      a.setSize( t.getSize() );
   }

   static void assign( Array& a, const T& t )
   {
      TNL_ASSERT_EQ( a.getSize(), t.getSize(), "The sizes of the arrays must be equal." );
      // skip assignment of empty arrays
      if( a.getSize() == 0 )
         return;
      Algorithms::MultiDeviceMemoryOperations< typename Array::DeviceType, typename T::DeviceType >::template
         copy< typename Array::ValueType, typename T::ValueType, typename Array::IndexType >
         ( a.getArrayData(), t.getArrayData(), t.getSize() );
   }
};

/**
 * \brief Specialization for array-value assignment for other types. We assume
 * that T is convertible to Array::ValueType.
 */
template< typename Array,
          typename T >
struct ArrayAssignment< Array, T, false >
{
   static void resize( Array& a, const T& t )
   {
   }

   static void assign( Array& a, const T& t )
   {
      // skip assignment to an empty array
      if( a.getSize() == 0 )
         return;
      Algorithms::MemoryOperations< typename Array::DeviceType >::template
         set< typename Array::ValueType, typename Array::IndexType >
         ( a.getArrayData(), ( typename Array::ValueType ) t, a.getSize() );
   }
};

} // namespace detail
} // namespace Containers
} // namespace TNL
