/*
//@HEADER
// ************************************************************************
//
//                        Kokkos v. 2.0
//              Copyright (2014) Sandia Corporation
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// the U.S. Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/

#include <Kokkos_Core.hpp>

namespace TestAtomicViews {

//-------------------------------------------------
//-----------atomic view api tests-----------------
//-------------------------------------------------

template< class T, class ... P >
size_t allocation_count( const Kokkos::View< T, P... > & view )
{
  const size_t card  = view.size();
  const size_t alloc = view.span();

  const int memory_span = Kokkos::View< int* >::required_allocation_size( 100 );

  return ( card <= alloc && memory_span == 400 ) ? alloc : 0;
}

template< class DataType,
          class DeviceType,
          unsigned Rank = Kokkos::ViewTraits< DataType >::rank >
struct TestViewOperator_LeftAndRight;

template< class DataType, class DeviceType >
struct TestViewOperator_LeftAndRight< DataType, DeviceType, 1 >
{
  typedef typename DeviceType::execution_space  execution_space;
  typedef typename DeviceType::memory_space     memory_space;
  typedef typename execution_space::size_type   size_type;

  typedef int value_type;

  KOKKOS_INLINE_FUNCTION
  static void join( volatile value_type & update,
                    const volatile value_type & input )
    { update |= input; }

  KOKKOS_INLINE_FUNCTION
  static void init( value_type & update )
    { update = 0; }

  typedef Kokkos::View< DataType, Kokkos::LayoutLeft, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > left_view;

  typedef Kokkos::View< DataType, Kokkos::LayoutRight, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > right_view;

  typedef Kokkos::View< DataType, Kokkos::LayoutStride, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > stride_view;

  left_view    left;
  right_view   right;
  stride_view  left_stride;
  stride_view  right_stride;
  long         left_alloc;
  long         right_alloc;

  TestViewOperator_LeftAndRight()
    : left(  "left" )
    , right( "right" )
    , left_stride( left )
    , right_stride( right )
    , left_alloc( allocation_count( left ) )
    , right_alloc( allocation_count( right ) )
    {}

  static void testit()
  {
    TestViewOperator_LeftAndRight driver;

    int error_flag = 0;

    Kokkos::parallel_reduce( 1, driver, error_flag );

    ASSERT_EQ( error_flag, 0 );
  }

  KOKKOS_INLINE_FUNCTION
  void operator()( const size_type, value_type & update ) const
  {
    for ( unsigned i0 = 0; i0 < unsigned( left.extent(0) ); ++i0 )
    {
      // Below checks that values match, but unable to check the references.
      // Should this be able to be checked?
#ifdef KOKKOS_ENABLE_DEPRECATED_CODE
        if ( left( i0 )  != left( i0, 0, 0, 0, 0, 0, 0, 0 ) )  { update |= 3; }
        if ( right( i0 ) != right( i0, 0, 0, 0, 0, 0, 0, 0 ) ) { update |= 3; }
#else
        if ( left( i0 )  != left.access( i0, 0, 0, 0, 0, 0, 0, 0 ) )  { update |= 3; }
        if ( right( i0 ) != right.access( i0, 0, 0, 0, 0, 0, 0, 0 ) ) { update |= 3; }
#endif
      if ( left( i0 )  != left_stride( i0 ) ) { update |= 4; }
      if ( right( i0 ) != right_stride( i0 ) ) { update |= 8; }
/*
      if ( &left( i0 )  != &left( i0, 0, 0, 0, 0, 0, 0, 0 ) )  { update |= 3; }
      if ( &right( i0 ) != &right( i0, 0, 0, 0, 0, 0, 0, 0 ) ) { update |= 3; }
      if ( &left( i0 )  != &left_stride( i0 ) ) { update |= 4; }
      if ( &right( i0 ) != &right_stride( i0 ) ) { update |= 8; }
*/
    }
  }
};

template< typename T, class DeviceType >
class TestAtomicViewAPI
{
public:
  typedef DeviceType device;

  enum { N0 = 1000,
         N1 = 3,
         N2 = 5,
         N3 = 7 };

  typedef Kokkos::View< T, device > dView0;
  typedef Kokkos::View< T*, device > dView1;
  typedef Kokkos::View< T*[N1], device > dView2;
  typedef Kokkos::View< T*[N1][N2], device > dView3;
  typedef Kokkos::View< T*[N1][N2][N3], device > dView4;
  typedef Kokkos::View< const T*[N1][N2][N3], device > const_dView4;
  typedef Kokkos::View< T****, device, Kokkos::MemoryUnmanaged > dView4_unmanaged;
  typedef typename dView0::host_mirror_space host;

  typedef Kokkos::View< T, device, Kokkos::MemoryTraits< Kokkos::Atomic > > aView0;
  typedef Kokkos::View< T*, device, Kokkos::MemoryTraits< Kokkos::Atomic > > aView1;
  typedef Kokkos::View< T*[N1], device, Kokkos::MemoryTraits< Kokkos::Atomic > > aView2;
  typedef Kokkos::View< T*[N1][N2], device, Kokkos::MemoryTraits< Kokkos::Atomic > > aView3;
  typedef Kokkos::View< T*[N1][N2][N3], device, Kokkos::MemoryTraits< Kokkos::Atomic > > aView4;
  typedef Kokkos::View< const T*[N1][N2][N3], device, Kokkos::MemoryTraits< Kokkos::Atomic > > const_aView4;

  typedef Kokkos::View< T****, device, Kokkos::MemoryTraits< Kokkos::Unmanaged | Kokkos::Atomic > > aView4_unmanaged;

  typedef typename aView0::host_mirror_space host_atomic;

  TestAtomicViewAPI()
  {
    TestViewOperator_LeftAndRight< int[2], device >::testit();
    run_test_rank0();
    run_test_rank4();
    run_test_const();
  }

  static void run_test_rank0()
  {
    dView0 dx, dy;
    aView0 ax, ay, az;

    dx = dView0( "dx" );
    dy = dView0( "dy" );
    ASSERT_EQ( dx.use_count(), size_t( 1 ) );
    ASSERT_EQ( dy.use_count(), size_t( 1 ) );

    ax = dx;
    ay = dy;
    ASSERT_EQ( dx.use_count(), size_t( 2 ) );
    ASSERT_EQ( dy.use_count(), size_t( 2 ) );
    ASSERT_EQ( dx.use_count(), ax.use_count() );

    az = ax;
    ASSERT_EQ( dx.use_count(), size_t( 3 ) );
    ASSERT_EQ( ax.use_count(), size_t( 3 ) );
    ASSERT_EQ( az.use_count(), size_t( 3 ) );
    ASSERT_EQ( az.use_count(), ax.use_count() );
  }

  static void run_test_rank4()
  {
    dView4 dx, dy;
    aView4 ax, ay, az;

    dx = dView4( "dx", N0 );
    dy = dView4( "dy", N0 );
    ASSERT_EQ( dx.use_count(), size_t( 1 ) );
    ASSERT_EQ( dy.use_count(), size_t( 1 ) );

    ax = dx;
    ay = dy;
    ASSERT_EQ( dx.use_count(), size_t( 2 ) );
    ASSERT_EQ( dy.use_count(), size_t( 2 ) );
    ASSERT_EQ( dx.use_count(), ax.use_count() );

    dView4_unmanaged unmanaged_dx = dx;
    ASSERT_EQ( dx.use_count(), size_t( 2 ) );

    az = ax;
    ASSERT_EQ( dx.use_count(), size_t( 3 ) );
    ASSERT_EQ( ax.use_count(), size_t( 3 ) );
    ASSERT_EQ( az.use_count(), size_t( 3 ) );
    ASSERT_EQ( az.use_count(), ax.use_count() );

    aView4_unmanaged unmanaged_ax = ax;
    ASSERT_EQ( ax.use_count(), size_t( 3 ) );

    aView4_unmanaged unmanaged_ax_from_ptr_dx =
      aView4_unmanaged( dx.data(), dx.extent(0), dx.extent(1), dx.extent(2), dx.extent(3) );
    ASSERT_EQ( ax.use_count(), size_t( 3 ) );

    const_aView4 const_ax = ax;
    ASSERT_EQ( ax.use_count(), size_t( 4 ) );
    ASSERT_EQ( const_ax.use_count(), ax.use_count() );

    ASSERT_FALSE( ax.data() == 0 );
    ASSERT_FALSE( const_ax.data() == 0 ); // referenceable ptr
    ASSERT_FALSE( unmanaged_ax.data() == 0 );
    ASSERT_FALSE( unmanaged_ax_from_ptr_dx.data() == 0 );
    ASSERT_FALSE( ay.data() == 0 );
//    ASSERT_NE( ax, ay );
//    Above test results in following runtime error from gtest:
//    Expected: (ax) != (ay), actual: 32-byte object <30-01 D0-A0 D8-7F 00-00 00-31 44-0C 01-00 00-00 E8-03 00-00 00-00 00-00 69-00 00-00 00-00 00-00> vs 32-byte object <80-01 D0-A0 D8-7F 00-00 00-A1 4A-0C 01-00 00-00 E8-03 00-00 00-00 00-00 69-00 00-00 00-00 00-00>

    ASSERT_EQ( ax.extent(0), unsigned( N0 ) );
    ASSERT_EQ( ax.extent(1), unsigned( N1 ) );
    ASSERT_EQ( ax.extent(2), unsigned( N2 ) );
    ASSERT_EQ( ax.extent(3), unsigned( N3 ) );

    ASSERT_EQ( ay.extent(0), unsigned( N0 ) );
    ASSERT_EQ( ay.extent(1), unsigned( N1 ) );
    ASSERT_EQ( ay.extent(2), unsigned( N2 ) );
    ASSERT_EQ( ay.extent(3), unsigned( N3 ) );

    ASSERT_EQ( unmanaged_ax_from_ptr_dx.span(), unsigned( N0 ) * unsigned( N1 ) * unsigned( N2 ) * unsigned( N3 ) );
  }

  typedef T DataType[2];

  static void
  check_auto_conversion_to_const(
     const Kokkos::View< const DataType, device, Kokkos::MemoryTraits<Kokkos::Atomic> > & arg_const,
     const Kokkos::View< const DataType, device, Kokkos::MemoryTraits<Kokkos::Atomic> > & arg )
  {
    ASSERT_TRUE( arg_const == arg );
  }

  static void run_test_const()
  {
    typedef Kokkos::View< DataType, device, Kokkos::MemoryTraits<Kokkos::Atomic> > typeX;
    typedef Kokkos::View< const DataType, device, Kokkos::MemoryTraits<Kokkos::Atomic> > const_typeX;

    typeX x( "X" );
    const_typeX xc = x;

    //ASSERT_TRUE( xc == x ); // const xc is referenceable, non-const x is not
    //ASSERT_TRUE( x == xc );

    check_auto_conversion_to_const( x, xc );
  }
};

//---------------------------------------------------
//-----------initialization functors-----------------
//---------------------------------------------------

template<class T, class execution_space >
struct InitFunctor_Seq {
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  const long length;

  InitFunctor_Seq( view_type & input_, const long length_ )
    : input( input_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      input( i ) = (T) i;
    }
  }
};

template<class T, class execution_space >
struct InitFunctor_ModTimes {
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  const long length;
  const long remainder;

  InitFunctor_ModTimes( view_type & input_, const long length_, const long remainder_ )
    : input( input_ )
    , length( length_ )
    , remainder( remainder_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % ( remainder + 1 ) == remainder ) {
        input( i ) = (T) 2;
      }
      else {
        input( i ) = (T) 1;
      }
    }
  }
};

template<class T, class execution_space >
struct InitFunctor_ModShift {
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  const long length;
  const long remainder;

  InitFunctor_ModShift( view_type & input_, const long length_, const long remainder_ )
    : input( input_ )
    , length( length_ )
    , remainder( remainder_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % ( remainder + 1 ) == remainder ) {
        input( i ) = 1;
      }
    }
  }
};

//---------------------------------------------------
//-----------atomic view plus-equal------------------
//---------------------------------------------------

template<class T, class execution_space >
struct PlusEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type even_odd_result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator
  PlusEqualAtomicViewFunctor( const view_type & input_, view_type & even_odd_result_, const long length_ )
    : input( input_ )
    , even_odd_result( even_odd_result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 2 == 0 ) {
        even_odd_result( 0 ) += input( i );
      }
      else {
        even_odd_result( 1 ) += input( i );
      }
    }
  }
};

template< class T, class execution_space >
T PlusEqualAtomicView( const long input_length ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 2 );

  InitFunctor_Seq< T, execution_space > init_f( input, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  PlusEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy<execution_space>( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) + h_result_view( 1 ) );
}

template< class T >
T PlusEqualAtomicViewCheck( const long input_length ) {
  const long N = input_length;
  T result[2];

  if ( N % 2 == 0 ) {
    const long half_sum_end = ( N / 2 ) - 1;
    const long full_sum_end = N - 1;
    result[0] = half_sum_end * ( half_sum_end + 1 ) / 2; // Even sum.
    result[1] = ( full_sum_end * ( full_sum_end + 1 ) / 2 ) - result[0]; // Odd sum.
  }
  else {
    const long half_sum_end = (T) ( N / 2 );
    const long full_sum_end = N - 2;
    result[0] = half_sum_end * ( half_sum_end - 1 ) / 2; // Even sum.
    result[1] = ( full_sum_end * ( full_sum_end - 1 ) / 2 ) - result[0]; // Odd sum.
  }

  return (T) ( result[0] + result[1] );
}

template< class T, class DeviceType >
bool PlusEqualAtomicViewTest( long input_length )
{
  T res       = PlusEqualAtomicView< T, DeviceType >( input_length );
  T resSerial = PlusEqualAtomicViewCheck< T >( input_length );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = PlusEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//-----------atomic view minus-equal-----------------
//---------------------------------------------------

template<class T, class execution_space >
struct MinusEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type even_odd_result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  MinusEqualAtomicViewFunctor( const view_type & input_, view_type & even_odd_result_, const long length_ )
    : input( input_ )
    , even_odd_result( even_odd_result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 2 == 0 ) {
        even_odd_result( 0 ) -= input( i );
      }
      else {
        even_odd_result( 1 ) -= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T MinusEqualAtomicView( const long input_length ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 2 );

  InitFunctor_Seq< T, execution_space > init_f( input, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  MinusEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) + h_result_view( 1 ) );
}

template< class T >
T MinusEqualAtomicViewCheck( const long input_length ) {
  const long N = input_length;
  T result[2];

  if ( N % 2 == 0 ) {
    const long half_sum_end = ( N / 2 ) - 1;
    const long full_sum_end = N - 1;
    result[0] = -1 * ( half_sum_end * ( half_sum_end + 1 ) / 2 ); // Even sum.
    result[1] = -1 * ( ( full_sum_end * ( full_sum_end + 1 ) / 2 ) + result[0] ); // Odd sum.
  }
  else {
    const long half_sum_end = (long) ( N / 2 );
    const long full_sum_end = N - 2;
    result[0] = -1 * ( half_sum_end * ( half_sum_end - 1 ) / 2 ); // Even sum.
    result[1] = -1 * ( ( full_sum_end * ( full_sum_end - 1 ) / 2 ) + result[0] ); // Odd sum.
  }

  return ( result[0] + result[1] );
}

template< class T, class DeviceType >
bool MinusEqualAtomicViewTest( long input_length )
{
  T res       = MinusEqualAtomicView< T, DeviceType >( input_length );
  T resSerial = MinusEqualAtomicViewCheck< T >( input_length );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = MinusEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//-----------atomic view times-equal-----------------
//---------------------------------------------------

template<class T, class execution_space >
struct TimesEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator
  TimesEqualAtomicViewFunctor( const view_type & input_, view_type & result_, const long length_ )
    : input( input_ )
    , result( result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length && i > 0 ) {
      result( 0 ) *= (double) input( i );
    }
  }
};

template< class T, class execution_space >
T TimesEqualAtomicView( const long input_length, const long remainder ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 1 );
  deep_copy( result_view, 1.0 );

  InitFunctor_ModTimes< T, execution_space > init_f( input, length, remainder );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  TimesEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) );
}

template< class T >
T TimesEqualAtomicViewCheck( const long input_length, const long remainder ) {
  // Analytical result.
  const long N = input_length;
  T result = 1.0;

  for ( long i = 2; i < N; ++i ) {
    if ( i % ( remainder + 1 ) == remainder ) {
      result *= 2.0;
    }
    else {
      result *= 1.0;
    }
  }

  return (T) result;
}

template< class T, class DeviceType>
bool TimesEqualAtomicViewTest( const long input_length )
{
  const long remainder = 23;
  T res       = TimesEqualAtomicView< T, DeviceType >( input_length, remainder );
  T resSerial = TimesEqualAtomicViewCheck< T >( input_length, remainder );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = TimesEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//------------atomic view div-equal------------------
//---------------------------------------------------

template<class T, class execution_space >
struct DivEqualAtomicViewFunctor {
  typedef Kokkos::View< T, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T, execution_space > scalar_view_type;

  view_type input;
  atomic_view_type result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  DivEqualAtomicViewFunctor( const view_type & input_, scalar_view_type & result_, const long length_ )
    : input( input_ )
    , result( result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length && i > 0 ) {
      result() /= (double) ( input( i ) );
    }
  }
};

template< class T, class execution_space >
T DivEqualAtomicView( const long input_length, const long remainder ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T, execution_space > scalar_view_type;
  typedef typename scalar_view_type::HostMirror host_scalar_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  scalar_view_type result_view( "result_view" );
  Kokkos::deep_copy( result_view, 12121212121 );

  InitFunctor_ModTimes< T, execution_space > init_f( input, length, remainder );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  DivEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_scalar_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view() );
}

template< class T >
T DivEqualAtomicViewCheck( const long input_length, const long remainder ) {
  const long N = input_length;
  T result = 12121212121.0;
  for ( long i = 2; i < N; ++i ) {
    if ( i % ( remainder + 1 ) == remainder ) {
      result /= 1.0;
    }
    else {
      result /= 2.0;
    }
  }

  return (T) result;
}

template< class T, class DeviceType >
bool DivEqualAtomicViewTest( const long input_length )
{
  const long remainder = 23;

  T res       = DivEqualAtomicView< T, DeviceType >( input_length, remainder );
  T resSerial = DivEqualAtomicViewCheck< T >( input_length, remainder );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = DivEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//------------atomic view mod-equal------------------
//---------------------------------------------------

template< class T, class execution_space >
struct ModEqualAtomicViewFunctor {
  typedef Kokkos::View< T, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T, execution_space > scalar_view_type;

  view_type input;
  atomic_view_type result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  ModEqualAtomicViewFunctor( const view_type & input_, scalar_view_type & result_, const long length_ )
    : input( input_ )
    , result( result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length && i > 0 ) {
      result() %= (double) ( input( i ) );
    }
  }
};

template< class T, class execution_space >
T ModEqualAtomicView( const long input_length, const long remainder ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T, execution_space > scalar_view_type;
  typedef typename scalar_view_type::HostMirror host_scalar_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  scalar_view_type result_view( "result_view" );
  Kokkos::deep_copy( result_view, 12121212121 );

  InitFunctor_ModTimes< T, execution_space > init_f( input, length, remainder );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  ModEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_scalar_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view() );
}

template< class T >
T ModEqualAtomicViewCheck( const long input_length, const long remainder ) {
  const long N = input_length;
  T result = 12121212121;
  for ( long i = 2; i < N; ++i ) {
    if ( i % ( remainder + 1 ) == remainder ) {
      result %= 1;
    }
    else {
      result %= 2;
    }
  }

  return (T) result;
}

template< class T, class DeviceType >
bool ModEqualAtomicViewTest( const long input_length )
{
  static_assert( std::is_integral< T >::value, "ModEqualAtomicView Error: Type must be integral type for this unit test" );

  const long remainder = 23;

  T res       = ModEqualAtomicView< T, DeviceType >( input_length, remainder );
  T resSerial = ModEqualAtomicViewCheck< T >( input_length, remainder );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = ModEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//------------atomic view rs-equal------------------
//---------------------------------------------------

template< class T, class execution_space >
struct RSEqualAtomicViewFunctor {
  typedef Kokkos::View< T****, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T****, execution_space > result_view_type;

  const view_type input;
  atomic_view_type result;
  const long length;
  const long value;

  // Wrap the result view in an atomic view, use this for operator.
  RSEqualAtomicViewFunctor( const view_type & input_, result_view_type & result_, const long & length_, const long & value_ )
    : input( input_ )
    , result( result_ )
    , length( length_ )
    , value( value_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 4 == 0 ) {
        result( 1, 0, 0, 0 ) >>= input( i );
      }
      else if ( i % 4 == 1 ) {
        result( 0, 1, 0, 0 ) >>= input( i );
      }
      else if ( i % 4 == 2 ) {
        result( 0, 0, 1, 0 ) >>= input( i );
      }
      else if ( i % 4 == 3 ) {
        result( 0, 0, 0, 1 ) >>= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T RSEqualAtomicView( const long input_length, const long value, const long remainder ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T****, execution_space > result_view_type;
  typedef typename result_view_type::HostMirror host_scalar_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  result_view_type result_view( "result_view", 2, 2, 2, 2 );
  host_scalar_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  h_result_view( 1, 0, 0, 0 ) = value;
  h_result_view( 0, 1, 0, 0 ) = value;
  h_result_view( 0, 0, 1, 0 ) = value;
  h_result_view( 0, 0, 0, 1 ) = value;
  Kokkos::deep_copy( result_view, h_result_view );

  InitFunctor_ModShift< T, execution_space > init_f( input, length, remainder );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  RSEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length, value );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 1, 0, 0, 0 ) );
}

template< class T >
T RSEqualAtomicViewCheck( const long input_length, const long value, const long remainder ) {
  T result[4];
  result[0] = value;
  result[1] = value;
  result[2] = value;
  result[3] = value;

  T * input = new T[input_length];
  for ( long i = 0; i < input_length; ++i ) {
    if ( i % ( remainder + 1 ) == remainder ) {
      input[i] = 1;
    }
    else {
      input[i] = 0;
    }
  }

  for ( long i = 0; i < input_length; ++i ) {
    if ( i % 4 == 0 ) {
      result[0] >>= input[i];
    }
    else if ( i % 4 == 1 ) {
      result[1] >>= input[i];
    }
    else if ( i % 4 == 2 ) {
      result[2] >>= input[i];
    }
    else if ( i % 4 == 3 ) {
      result[3] >>= input[i];
    }
  }

  delete [] input;

  return (T) result[0];
}

template< class T, class DeviceType >
bool RSEqualAtomicViewTest( const long input_length )
{
  static_assert( std::is_integral< T >::value, "RSEqualAtomicViewTest: Must be integral type for test" );

  const long remainder = 61042; //prime - 1
  const long value = 1073741825; //  2^30+1
  T res       = RSEqualAtomicView< T, DeviceType >( input_length, value, remainder );
  T resSerial = RSEqualAtomicViewCheck< T >( input_length, value, remainder );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = RSEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//------------atomic view ls-equal------------------
//---------------------------------------------------

template<class T, class execution_space >
struct LSEqualAtomicViewFunctor {
  typedef Kokkos::View< T****, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T****, execution_space > result_view_type;

  view_type input;
  atomic_view_type result;
  const long length;
  const long value;

  // Wrap the result view in an atomic view, use this for operator.
  LSEqualAtomicViewFunctor( const view_type & input_, result_view_type & result_, const long & length_, const long & value_ )
    : input( input_ )
    , result( result_ )
    , length( length_ )
    , value( value_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 4 == 0 ) {
        result( 1, 0, 0, 0 ) <<= input( i );
      }
      else if ( i % 4 == 1 ) {
        result( 0, 1, 0, 0 ) <<= input( i );
      }
      else if ( i % 4 == 2 ) {
        result( 0, 0, 1, 0 ) <<= input( i );
      }
      else if ( i % 4 == 3 ) {
        result( 0, 0, 0, 1 ) <<= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T LSEqualAtomicView( const long input_length, const long value, const long remainder ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef Kokkos::View< T****, execution_space > result_view_type;
  typedef typename result_view_type::HostMirror host_scalar_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  result_view_type result_view( "result_view", 2, 2, 2, 2 );
  host_scalar_view_type h_result_view = Kokkos::create_mirror_view( result_view );
    h_result_view( 1, 0, 0, 0 ) = value;
    h_result_view( 0, 1, 0, 0 ) = value;
    h_result_view( 0, 0, 1, 0 ) = value;
    h_result_view( 0, 0, 0, 1 ) = value;
  Kokkos::deep_copy( result_view, h_result_view );

  InitFunctor_ModShift< T, execution_space > init_f( input, length, remainder );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  LSEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length, value );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 1, 0, 0, 0 ) );
}

template< class T >
T LSEqualAtomicViewCheck( const long input_length, const long value, const long remainder ) {
  T result[4];
  result[0] = value;
  result[1] = value;
  result[2] = value;
  result[3] = value;

  T * input = new T[input_length];
  for ( long i = 0; i < input_length; ++i ) {
    if ( i % ( remainder + 1 ) == remainder ) {
      input[i] = 1;
    }
    else {
      input[i] = 0;
    }
  }

  for ( long i = 0; i < input_length; ++i ) {
    if ( i % 4 == 0 ) {
      result[0] <<= input[i];
    }
    else if ( i % 4 == 1 ) {
      result[1] <<= input[i];
    }
    else if ( i % 4 == 2 ) {
      result[2] <<= input[i];
    }
    else if ( i % 4 == 3 ) {
      result[3] <<= input[i];
    }
  }

  delete [] input;

  return (T) result[0];
}

template< class T, class DeviceType >
bool LSEqualAtomicViewTest( const long input_length )
{
  static_assert( std::is_integral< T >::value, "LSEqualAtomicViewTest: Must be integral type for test" );

  const long remainder = 61042; //prime - 1
  const long value = 1; //  2^30+1
  T res       = LSEqualAtomicView< T, DeviceType >( input_length, value, remainder );
  T resSerial = LSEqualAtomicViewCheck< T >( input_length, value, remainder );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = RSEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//-----------atomic view and-equal-----------------
//---------------------------------------------------

template< class T, class execution_space >
struct AndEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type even_odd_result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  AndEqualAtomicViewFunctor( const view_type & input_, view_type & even_odd_result_, const long length_ )
    : input( input_ )
    , even_odd_result( even_odd_result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 2 == 0 ) {
        even_odd_result( 0 ) &= input( i );
      }
      else {
        even_odd_result( 1 ) &= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T AndEqualAtomicView( const long input_length ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 2 );
  Kokkos::deep_copy( result_view, 1 );

  InitFunctor_Seq< T, execution_space > init_f( input, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  AndEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) );
}

template< class T >
T AndEqualAtomicViewCheck( const long input_length ) {
  const long N = input_length;
  T result[2] = { 1 };
  for ( long i = 0; i < N; ++i ) {
    if ( N % 2 == 0 ) {
      result[0] &= (T) i;
    }
    else {
      result[1] &= (T) i;
    }
  }

  return ( result[0] );
}

template< class T, class DeviceType >
bool AndEqualAtomicViewTest( long input_length )
{
  static_assert( std::is_integral< T >::value, "AndEqualAtomicViewTest: Must be integral type for test" );

  T res       = AndEqualAtomicView< T, DeviceType >( input_length );
  T resSerial = AndEqualAtomicViewCheck< T >( input_length );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = AndEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//-----------atomic view or-equal-----------------
//---------------------------------------------------

template< class T, class execution_space >
struct OrEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type even_odd_result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  OrEqualAtomicViewFunctor( const view_type & input_, view_type & even_odd_result_, const long length_ )
    : input( input_ )
    , even_odd_result( even_odd_result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 2 == 0 ) {
        even_odd_result( 0 ) |= input( i );
      }
      else {
        even_odd_result( 1 ) |= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T OrEqualAtomicView( const long input_length ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 2 );

  InitFunctor_Seq< T, execution_space > init_f( input, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  OrEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) );
}

template< class T >
T OrEqualAtomicViewCheck( const long input_length ) {

  const long N = input_length;
  T result[2] = { 0 };
  for ( long i = 0; i < N; ++i ) {
    if ( i % 2 == 0 ) {
      result[0] |= (T) i;
    }
    else {
      result[1] |= (T) i;
    }
  }

  return (T) ( result[0] );
}

template< class T, class DeviceType >
bool OrEqualAtomicViewTest( long input_length )
{
  static_assert( std::is_integral< T >::value, "OrEqualAtomicViewTest: Must be integral type for test" );

  T res       = OrEqualAtomicView< T, DeviceType >( input_length );
  T resSerial = OrEqualAtomicViewCheck< T >( input_length );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = OrEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

//---------------------------------------------------
//-----------atomic view xor-equal-----------------
//---------------------------------------------------

template< class T, class execution_space >
struct XOrEqualAtomicViewFunctor {
  typedef Kokkos::View< T*, execution_space, Kokkos::MemoryTraits<Kokkos::Atomic> > atomic_view_type;
  typedef Kokkos::View< T*, execution_space > view_type;

  view_type input;
  atomic_view_type even_odd_result;
  const long length;

  // Wrap the result view in an atomic view, use this for operator.
  XOrEqualAtomicViewFunctor( const view_type & input_, view_type & even_odd_result_, const long length_ )
    : input( input_ )
    , even_odd_result( even_odd_result_ )
    , length( length_ )
  {}

  KOKKOS_INLINE_FUNCTION
  void operator()( const long i ) const {
    if ( i < length ) {
      if ( i % 2 == 0 ) {
        even_odd_result( 0 ) ^= input( i );
      }
      else {
        even_odd_result( 1 ) ^= input( i );
      }
    }
  }
};

template< class T, class execution_space >
T XOrEqualAtomicView( const long input_length ) {
  typedef Kokkos::View< T*, execution_space > view_type;
  typedef typename view_type::HostMirror host_view_type;

  const long length = input_length;

  view_type input( "input_view", length );
  view_type result_view( "result_view", 2 );

  InitFunctor_Seq< T, execution_space > init_f( input, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), init_f );

  XOrEqualAtomicViewFunctor< T, execution_space > functor( input, result_view, length );
  Kokkos::parallel_for( Kokkos::RangePolicy< execution_space >( 0, length ), functor );
  Kokkos::fence();

  host_view_type h_result_view = Kokkos::create_mirror_view( result_view );
  Kokkos::deep_copy( h_result_view, result_view );

  return (T) ( h_result_view( 0 ) );
}

template< class T >
T XOrEqualAtomicViewCheck( const long input_length ) {
  const long N = input_length;
  T result[2] = { 0 };
  for ( long i = 0; i < N; ++i ) {
    if ( i % 2 == 0 ) {
      result[0] ^= (T) i;
    }
    else {
      result[1] ^= (T) i;
    }
  }

  return (T) ( result[0] );
}

template< class T, class DeviceType >
bool XOrEqualAtomicViewTest( long input_length )
{
  static_assert( std::is_integral< T >::value, "XOrEqualAtomicViewTest: Must be integral type for test" );

  T res       = XOrEqualAtomicView< T, DeviceType >( input_length );
  T resSerial = XOrEqualAtomicViewCheck< T >( input_length );

  bool passed = true;

  if ( resSerial != res ) {
    passed = false;

    std::cout << "Loop<"
              << typeid( T ).name()
              << ">( test = XOrEqualAtomicViewTest"
              << " FAILED : "
              << resSerial << " != " << res
              << std::endl;
  }

  return passed;
}

// inc/dec?

//---------------------------------------------------
//--------------atomic_test_control------------------
//---------------------------------------------------

template< class T, class DeviceType >
bool AtomicViewsTestIntegralType( const int length, int test )
{
  static_assert( std::is_integral< T >::value, "TestAtomicViews Error: Non-integral type passed into IntegralType tests" );

  switch ( test ) {
    case 1: return PlusEqualAtomicViewTest< T, DeviceType >( length );
    case 2: return MinusEqualAtomicViewTest< T, DeviceType >( length );
    case 3: return RSEqualAtomicViewTest< T, DeviceType >( length );
    case 4: return LSEqualAtomicViewTest< T, DeviceType >( length );
    case 5: return ModEqualAtomicViewTest< T, DeviceType >( length );
    case 6: return AndEqualAtomicViewTest< T, DeviceType >( length );
    case 7: return OrEqualAtomicViewTest< T, DeviceType >( length );
    case 8: return XOrEqualAtomicViewTest< T, DeviceType >( length );
  }

  return 0;
}

template< class T, class DeviceType >
bool AtomicViewsTestNonIntegralType( const int length, int test )
{
  switch ( test ) {
    case 1: return PlusEqualAtomicViewTest< T, DeviceType >( length );
    case 2: return MinusEqualAtomicViewTest< T, DeviceType >( length );
    case 3: return TimesEqualAtomicViewTest< T, DeviceType >( length );
    case 4: return DivEqualAtomicViewTest< T, DeviceType >( length );
  }

  return 0;
}

} // namespace TestAtomicViews

namespace Test {

TEST_F( TEST_CATEGORY, atomic_views_integral )
{
  const long length = 1000000;
  {
    // Integral Types.
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 1 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 2 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 3 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 4 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 5 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 6 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 7 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestIntegralType< long, TEST_EXECSPACE >( length, 8 ) ) );
  }
}

TEST_F( TEST_CATEGORY, atomic_views_nonintegral )
{
  const long length = 1000000;
  {
    // Non-Integral Types.
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestNonIntegralType< double, TEST_EXECSPACE >( length, 1 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestNonIntegralType< double, TEST_EXECSPACE >( length, 2 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestNonIntegralType< double, TEST_EXECSPACE >( length, 3 ) ) );
    ASSERT_TRUE( ( TestAtomicViews::AtomicViewsTestNonIntegralType< double, TEST_EXECSPACE >( length, 4 ) ) );
  }
}

TEST_F( TEST_CATEGORY, atomic_view_api )
{
  TestAtomicViews::TestAtomicViewAPI< int, TEST_EXECSPACE >();
}
}
