//============================================================================
//  Copyright (c) Kitware, Inc.
//  All rights reserved.
//  See LICENSE.txt for details.
//
//  This software is distributed WITHOUT ANY WARRANTY; without even
//  the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//  PURPOSE.  See the above copyright notice for more information.
//============================================================================
#ifndef vtk_m_cont_internal_AtomicInterfaceExecution_h
#define vtk_m_cont_internal_AtomicInterfaceExecution_h

#include <vtkm/Types.h>

namespace vtkm
{
namespace cont
{
namespace internal
{

/// Class template that provides a collection of static methods that perform
/// atomic operations on raw addresses. It is the responsibility of the caller
/// to ensure that the addresses are properly aligned.
///
/// The class defines a WordTypePreferred member that is the fastest available
/// for bitwise operations of the given device. At minimum, the interface must
/// support operations on WordTypePreferred and vtkm::WordTypeDefault, which may
/// be the same. A full list of supported word types is advertised in the type
/// list @a WordTypes.
///
/// To implement this on devices that share the control environment, subclass
/// vtkm::cont::internal::AtomicInterfaceControl, which may also be used
/// directly from control-side code.
template <typename DeviceTag>
class AtomicInterfaceExecution
#ifdef VTKM_DOXYGEN_ONLY
{
  /// The preferred word type for the target device for bitwise atomic
  /// operations.
  using WordTypePreferred = FastestWordTypeForDevice;

  using WordTypes = vtkm::ListTagBase<vtkm::WordTypeDefault, WordTypePreferred>;

  /// Atomically load a value from memory while enforcing, at minimum, "acquire"
  /// memory ordering.
  VTKM_EXEC static vtkm::WordTypeDefault Load(vtkm::WordTypeDefault* addr);
  VTKM_EXEC static WordTypePreferred Load(WordTypePreferred* addr);

  /// Atomically write a value to memory while enforcing, at minimum, "release"
  /// memory ordering.
  VTKM_EXEC static void Store(vtkm::WordTypeDefault* addr, vtkm::WordTypeDefault value);
  VTKM_EXEC static void Store(WordTypePreferred* addr, WordTypePreferred value);

  /// Perform a bitwise atomic not operation on the word at @a addr.
  /// This operation performs a full memory barrier around the atomic access.
  /// @{
  VTKM_EXEC static vtkm::WordTypeDefault Not(vtkm::WordTypeDefault* addr);
  VTKM_EXEC static WordTypePreferred Not(WordTypePreferred* addr);
  /// @}

  /// Perform a bitwise atomic and operation on the word at @a addr.
  /// This operation performs a full memory barrier around the atomic access.
  /// @{
  VTKM_EXEC static vtkm::WordTypeDefault And(vtkm::WordTypeDefault* addr,
                                             vtkm::WordTypeDefault mask);
  VTKM_EXEC static WordTypePreferred And(WordTypePreferred* addr, WordTypePreferred mask);
  /// @}

  /// Perform a bitwise atomic or operation on the word at @a addr.
  /// This operation performs a full memory barrier around the atomic access.
  /// @{
  VTKM_EXEC static vtkm::WordTypeDefault Or(vtkm::WordTypeDefault* addr,
                                            vtkm::WordTypeDefault mask);
  VTKM_EXEC static WordTypePreferred Or(WordTypePreferred* addr, WordTypePreferred mask);
  /// @}

  /// Perform a bitwise atomic xor operation on the word at @a addr.
  /// This operation performs a full memory barrier around the atomic access.
  /// @{
  VTKM_EXEC static vtkm::WordTypeDefault Xor(vtkm::WordTypeDefault* addr,
                                             vtkm::WordTypeDefault mask);
  VTKM_EXEC static WordTypePreferred Xor(WordTypePreferred* addr, WordTypePreferred mask);
  /// @}

  /// Perform an atomic CAS operation on the word at @a addr.
  /// This operation performs a full memory barrier around the atomic access.
  /// @{
  VTKM_EXEC static vtkm::WordTypeDefault CompareAndSwap(vtkm::WordTypeDefault* addr,
                                                        vtkm::WordTypeDefault newWord,
                                                        vtkm::WordTypeDefault expected);
  VTKM_EXEC static WordTypePreferred CompareAndSwap(WordTypePreferred* addr,
                                                    WordTypePreferred newWord,
                                                    WordTypePreferred expected);
  /// @}
}
#endif // VTKM_DOXYGEN_ONLY
;
}
}
} // end namespace vtkm::cont::internal

#endif // vtk_m_cont_internal_AtomicInterfaceExecution_h
