Program Listing for File helpers.hpp

Return to documentation for file (camp/helpers.hpp)

/*
Copyright (c) 2016-18, Lawrence Livermore National Security, LLC.
Produced at the Lawrence Livermore National Laboratory
Maintained by Tom Scogland <scogland1@llnl.gov>
CODE-756261, All rights reserved.
This file is part of camp.
For details about use and distribution, please read LICENSE and NOTICE from
http://github.com/llnl/camp
*/

#ifndef CAMP_HELPERS_HPP
#define CAMP_HELPERS_HPP

#include <cstddef>
#include <utility>

#include "camp/defines.hpp"

namespace camp
{

template <typename T>
T* declptr();

template <typename T>
CAMP_HOST_DEVICE auto val() noexcept -> decltype(std::declval<T>());

template <typename T>
CAMP_HOST_DEVICE auto cval() noexcept -> decltype(std::declval<T const>());

template <typename... Ts>
CAMP_HOST_DEVICE constexpr inline void sink(Ts const&...)
{
}

namespace detail
{
  using __expand_array_type = int[];
}
#define CAMP_EXPAND(...) static_cast<void>( \
  ::camp::detail::__expand_array_type { 0, ((void)(__VA_ARGS__), 0)... })

template <typename Fn, typename... Args>
CAMP_HOST_DEVICE constexpr void for_each_arg(Fn&& f, Args&&... args)
{
  CAMP_EXPAND(f((Args &&) args));
}

// bring common utility routines into scope to allow ADL
using std::begin;
using std::swap;

namespace type
{
  namespace ref
  {
    template <class T>
    struct rem_s {
      using type = T;
    };
    template <class T>
    struct rem_s<T&> {
      using type = T;
    };
    template <class T>
    struct rem_s<T&&> {
      using type = T;
    };

    template <class T>
    using rem = typename rem_s<T>::type;

    template <class T>
    using add = T&;
  }  // end namespace ref

  namespace rvref
  {
    template <class T>
    using add = T&&;
  }  // end namespace rvref

  namespace ptr
  {
    template <class T>
    struct rem_s {
      using type = T;
    };
    template <class T>
    struct rem_s<T*> {
      using type = T;
    };

    template <class T>
    using rem = typename rem_s<T>::type;

    template <class T>
    using add = T*;
  }  // end namespace ptr

  namespace c
  {
    template <class T>
    struct rem_s {
      using type = T;
    };
    template <class T>
    struct rem_s<const T> {
      using type = T;
    };

    template <class T>
    using rem = typename rem_s<T>::type;

    template <class T>
    using add = const T;
  }  // namespace c

  namespace v
  {
    template <class T>
    struct rem_s {
      using type = T;
    };
    template <class T>
    struct rem_s<volatile T> {
      using type = T;
    };

    template <class T>
    using rem = typename rem_s<T>::type;

    template <class T>
    using add = volatile T;
  }  // namespace v

  namespace cv
  {
    template <class T>
    struct rem_s {
      using type = T;
    };
    template <class T>
    struct rem_s<const T> {
      using type = T;
    };
    template <class T>
    struct rem_s<volatile T> {
      using type = T;
    };
    template <class T>
    struct rem_s<const volatile T> {
      using type = T;
    };

    template <class T>
    using rem = typename rem_s<T>::type;

    template <class T>
    using add = const volatile T;
  }  // namespace cv
}  // end namespace type

template <typename T>
using decay = type::cv::rem<type::ref::rem<T>>;

template <typename T>
using plain = type::ref::rem<T>;

template <typename T>
using diff_from = decltype(val<plain<T>>() - val<plain<T>>());
template <typename T, typename U>
using diff_between = decltype(val<plain<T>>() - val<plain<U>>());

template <typename T>
using iterator_from = decltype(begin(val<plain<T>>()));

template <class T>
CAMP_HOST_DEVICE constexpr T&& forward(type::ref::rem<T>& t) noexcept
{
  return static_cast<T&&>(t);
}
template <class T>
CAMP_HOST_DEVICE constexpr T&& forward(type::ref::rem<T>&& t) noexcept
{
  return static_cast<T&&>(t);
}

template <typename T>
CAMP_HOST_DEVICE constexpr type::ref::rem<T>&& move(T&& t) noexcept
{
  return static_cast<type::ref::rem<T>&&>(t);
}

template <typename T>
CAMP_HOST_DEVICE void safe_swap(T& t1, T& t2)
{
#if defined(__CUDA_ARCH__) || defined(__HIP_DEVICE_COMPILE__)
  T temp{std::move(t1)};
  t1 = std::move(t2);
  t2 = std::move(temp);
#else
  using std::swap;
  swap(t1, t2);
#endif
}

template <typename T, typename = decltype(sink(swap(val<T>(), val<T>())))>
CAMP_HOST_DEVICE void safe_swap(T& t1, T& t2)
{
  using std::swap;
  swap(t1, t2);
}
}  // namespace camp

#endif /* CAMP_HELPERS_HPP */