Program Listing for File concepts.hpp

Return to documentation for file (camp/concepts.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_CONCEPTS_HPP
#define CAMP_CONCEPTS_HPP

#include <iterator>
#include <type_traits>

#include "camp/helpers.hpp"
#include "camp/list.hpp"
#include "camp/number.hpp"

#include "camp/type_traits/is_same.hpp"

namespace camp
{

namespace concepts
{

  namespace metalib
  {
    using camp::is_same;

    template <typename T>
    struct negate_t : num<!T::value> {
    };

    template <bool... Bs>
    struct all_of : metalib::is_same<list<t, num<Bs>...>, list<num<Bs>..., t>> {
    };

    template <bool... Bs>
    struct none_of
        : metalib::is_same<idx_seq<false, Bs...>, idx_seq<Bs..., false>> {
    };

    template <bool... Bs>
    struct any_of : negate_t<none_of<Bs...>> {
    };

    template <typename... Bs>
    struct all_of_t : all_of<Bs::value...> {
    };

    template <typename... Bs>
    struct none_of_t : none_of<Bs::value...> {
    };

    template <typename... Bs>
    struct any_of_t : any_of<Bs::value...> {
    };

  }  // end namespace metalib

}  // end namespace concepts
}  // end namespace camp

template <typename... T>
camp::true_type ___valid_expr___(T &&...) noexcept;
#define DefineConcept(...) decltype(___valid_expr___(__VA_ARGS__))

#define DefineTypeTraitFromConcept(TTName, ConceptName)             \
  template <typename... Args>                                       \
  struct TTName : camp::concepts::requires_<ConceptName, Args...> { \
  }
namespace camp
{
namespace concepts
{

  namespace detail
  {

    template <class...>
    struct TL {
    };

    template <class...>
    struct voider {
      using type = void;
    };

    template <class Default,
              class /* always void*/,
              template <class...> class Concept,
              class TArgs>
    struct detector {
      using value_t = false_type;
      using type = Default;
    };

    template <class Default, template <class...> class Concept, class... Args>
    struct detector<Default,
                    typename voider<Concept<Args...>>::type,
                    Concept,
                    TL<Args...>> {
      using value_t = true_type;
      using type = Concept<Args...>;
    };

    template <template <class...> class Concept, class TArgs>
    using is_detected = detector<void, void, Concept, TArgs>;

    template <template <class...> class Concept, class TArgs>
    using detected = typename is_detected<Concept, TArgs>::value_t;


    template <typename Ret, typename T>
    Ret returns(T const &) noexcept;

  }  // end namespace detail

  template <typename T>
  using negate = metalib::negate_t<T>;

  template <typename T, typename U>
  constexpr auto convertible_to(U &&u) noexcept
      -> decltype(detail::returns<camp::true_type>(static_cast<T>((U &&) u)));

  template <typename T, typename U>
  constexpr auto has_type(U &&) noexcept -> metalib::is_same<T, U>;

  template <typename BoolLike>
  constexpr auto is(BoolLike) noexcept
      -> camp::if_<BoolLike, camp::true_type, camp::false_type>;

  template <typename BoolLike>
  constexpr auto is_not(BoolLike) noexcept
      -> camp::if_c<!BoolLike::value, camp::true_type, camp::false_type>;

  template <typename... Args>
  struct all_of : metalib::all_of_t<Args...> {
  };

  template <typename... Args>
  struct none_of : metalib::none_of_t<Args...> {
  };

  template <typename... Args>
  struct any_of : metalib::any_of_t<Args...> {
  };

  template <typename... Args>
  using enable_if = typename std::enable_if<all_of<Args...>::value, void>::type;

  template <typename T, typename... Args>
  using enable_if_t = typename std::enable_if<all_of<Args...>::value, T>::type;

  template <template <class...> class Op, class... Args>
  struct requires_ : detail::detected<Op, detail::TL<Args...>> {
  };

  template <typename T>
  struct Swappable : DefineConcept(swap(val<T>(), val<T>())) {
  };

  template <typename T>
  struct LessThanComparable
      : DefineConcept(convertible_to<bool>(val<T>() < val<T>())) {
  };

  template <typename T>
  struct GreaterThanComparable
      : DefineConcept(convertible_to<bool>(val<T>() > val<T>())) {
  };

  template <typename T>
  struct LessEqualComparable
      : DefineConcept(convertible_to<bool>(val<T>() <= val<T>())) {
  };

  template <typename T>
  struct GreaterEqualComparable
      : DefineConcept(convertible_to<bool>(val<T>() >= val<T>())) {
  };

  template <typename T>
  struct EqualityComparable
      : DefineConcept(convertible_to<bool>(val<T>() == val<T>())) {
  };

  template <typename T, typename U>
  struct ComparableTo
      : DefineConcept(convertible_to<bool>(val<U>() < val<T>()),
                      convertible_to<bool>(val<T>() < val<U>()),
                      convertible_to<bool>(val<U>() <= val<T>()),
                      convertible_to<bool>(val<T>() <= val<U>()),
                      convertible_to<bool>(val<U>() > val<T>()),
                      convertible_to<bool>(val<T>() > val<U>()),
                      convertible_to<bool>(val<U>() >= val<T>()),
                      convertible_to<bool>(val<T>() >= val<U>()),
                      convertible_to<bool>(val<U>() == val<T>()),
                      convertible_to<bool>(val<T>() == val<U>()),
                      convertible_to<bool>(val<U>() != val<T>()),
                      convertible_to<bool>(val<T>() != val<U>())) {
  };

  template <typename T>
  struct Comparable : ComparableTo<T, T> {
  };

  template <typename T>
  struct Arithmetic : DefineConcept(is(std::is_arithmetic<T>())) {
  };

  template <typename T>
  struct FloatingPoint : DefineConcept(is(std::is_floating_point<T>())) {
  };

  template <typename T>
  struct Integral : DefineConcept(is(std::is_integral<T>())) {
  };

  template <typename T>
  struct Signed : DefineConcept(Integral<T>(), is(std::is_signed<T>())) {
  };

  template <typename T>
  struct Unsigned : DefineConcept(Integral<T>(), is(std::is_unsigned<T>())) {
  };

  template <typename T>
  struct Iterator
      : DefineConcept(is_not(Integral<T>()),  // hacky NVCC 8 workaround
                      *(val<T>()),
                      has_type<T &>(++val<T &>())) {
  };

  template <typename T>
  struct ForwardIterator
      : DefineConcept(Iterator<T>(), val<T &>()++, *val<T &>()++) {
  };

  template <typename T>
  struct BidirectionalIterator
      : DefineConcept(ForwardIterator<T>(),
                      has_type<T &>(--val<T &>()),
                      convertible_to<T const &>(val<T &>()--),
                      *val<T &>()--) {
  };

  template <typename T>
  struct RandomAccessIterator
      : DefineConcept(BidirectionalIterator<T>(),
                      Comparable<T>(),
                      has_type<T &>(val<T &>() += val<diff_from<T>>()),
                      has_type<T>(val<T>() + val<diff_from<T>>()),
                      has_type<T>(val<diff_from<T>>() + val<T>()),
                      has_type<T &>(val<T &>() -= val<diff_from<T>>()),
                      has_type<T>(val<T>() - val<diff_from<T>>()),
                      val<T>()[val<diff_from<T>>()]) {
  };

  template <typename T>
  struct HasBeginEnd : DefineConcept(std::begin(val<T>()), std::end(val<T>())) {
  };

  template <typename T>
  struct Range : DefineConcept(HasBeginEnd<T>(), Iterator<iterator_from<T>>()) {
  };

  template <typename T>
  struct ForwardRange
      : DefineConcept(HasBeginEnd<T>(), ForwardIterator<iterator_from<T>>()) {
  };

  template <typename T>
  struct BidirectionalRange
      : DefineConcept(HasBeginEnd<T>(),
                      BidirectionalIterator<iterator_from<T>>()) {
  };

  template <typename T>
  struct RandomAccessRange
      : DefineConcept(HasBeginEnd<T>(),
                      RandomAccessIterator<iterator_from<T>>()) {
  };

}  // end namespace concepts

namespace type_traits
{
  DefineTypeTraitFromConcept(is_iterator, camp::concepts::Iterator);
  DefineTypeTraitFromConcept(is_forward_iterator,
                             camp::concepts::ForwardIterator);
  DefineTypeTraitFromConcept(is_bidirectional_iterator,
                             camp::concepts::BidirectionalIterator);
  DefineTypeTraitFromConcept(is_random_access_iterator,
                             camp::concepts::RandomAccessIterator);

  DefineTypeTraitFromConcept(is_range, camp::concepts::Range);
  DefineTypeTraitFromConcept(is_forward_range, camp::concepts::ForwardRange);
  DefineTypeTraitFromConcept(is_bidirectional_range,
                             camp::concepts::BidirectionalRange);
  DefineTypeTraitFromConcept(is_random_access_range,
                             camp::concepts::RandomAccessRange);

  DefineTypeTraitFromConcept(is_comparable, camp::concepts::Comparable);
  DefineTypeTraitFromConcept(is_comparable_to, camp::concepts::ComparableTo);

  DefineTypeTraitFromConcept(is_arithmetic, camp::concepts::Arithmetic);
  DefineTypeTraitFromConcept(is_floating_point, camp::concepts::FloatingPoint);
  DefineTypeTraitFromConcept(is_integral, camp::concepts::Integral);
  DefineTypeTraitFromConcept(is_signed, camp::concepts::Signed);
  DefineTypeTraitFromConcept(is_unsigned, camp::concepts::Unsigned);

  template <typename T>
  using IterableValue = decltype(*std::begin(camp::val<T>()));

  template <typename T>
  using IteratorValue = decltype(*camp::val<T>());

  namespace detail
  {

    template <typename, template <typename...> class, typename...>
    struct IsSpecialized : camp::false_type {
    };

    template <template <typename...> class Template, typename... T>
    struct IsSpecialized<typename concepts::detail::voider<decltype(
                             camp::val<Template<T...>>())>::type,
                         Template,
                         T...> : camp::true_type {
    };

    template <template <class...> class,
              template <class...> class,
              bool,
              class...>
    struct SpecializationOf : camp::false_type {
    };

    template <template <class...> class Expected,
              template <class...> class Actual,
              class... Args>
    struct SpecializationOf<Expected, Actual, true, Args...>
        : camp::concepts::metalib::is_same<Expected<Args...>, Actual<Args...>> {
    };

  }  // end namespace detail


  template <template <class...> class Outer, class... Args>
  using IsSpecialized = detail::IsSpecialized<void, Outer, Args...>;

  template <template <class...> class, typename T>
  struct SpecializationOf : camp::false_type {
  };

  template <template <class...> class Expected,
            template <class...> class Actual,
            class... Args>
  struct SpecializationOf<Expected, Actual<Args...>>
      : detail::SpecializationOf<Expected,
                                 Actual,
                                 IsSpecialized<Expected, Args...>::value,
                                 Args...> {
  };

}  // end namespace type_traits
}  // namespace camp

#endif /* CAMP_CONCEPTS_HPP */