Program Listing for File at.hpp

Return to documentation for file (camp/list/at.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_list_at_hpp
#define __CAMP_list_at_hpp

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

namespace camp
{

namespace detail
{
  template <typename T, idx_t Idx>
  struct _at;

  #if CAMP_USE_TYPE_PACK_ELEMENT
  template <idx_t Idx, template <class...> class T, typename... Pack>
  struct _at<T<Pack...>, Idx> {
    using type = __type_pack_element<Idx, Pack...>;
  };
  #else
  // Lookup from metal::at machinery
  template <idx_t, typename>
  struct entry {
  };

  template <typename, typename>
  struct entries;

  template <idx_t... keys, typename... vals>
  struct entries<idx_seq<keys...>, list<vals...>> : entry<keys, vals>... {
  };

  template <idx_t key, typename val>
  value<val> _lookup_impl(entry<key, val>*);

  template <typename>
  value<> _lookup_impl(...);

  template <typename vals, typename indices, idx_t Idx>
  struct _lookup
      : decltype(_lookup_impl<Idx>(declptr<entries<indices, vals>>())) {
  };

  template <template <class...> class T, typename X, typename... Rest>
  struct _at<T<X, Rest...>, 0> {
    using type = X;
  };
  template <template <class...> class T,
            typename X,
            typename Y,
            typename... Rest>
  struct _at<T<X, Y, Rest...>, 1> {
    using type = Y;
  };
  template <template <class...> class T, idx_t Idx, typename... Rest>
  struct _at<T<Rest...>, Idx> {
    static_assert(Idx < sizeof...(Rest), "at: index out of range");
    using type = typename _lookup<T<Rest...>,
                                  make_idx_seq_t<sizeof...(Rest)>,
                                  Idx>::type;
  };
  #endif
}  // namespace detail

// TODO: document
template <typename Seq, typename Num>
struct at;
template <typename T, idx_t Val>
struct at<T, num<Val>> {
  using type = typename detail::_at<T, Val>::type;
};


template <typename T>
using first = typename at<T, num<0>>::type;

template <typename T>
using second = typename at<T, num<1>>::type;

// TODO: document
template <typename T, idx_t Idx>
using at_v = typename at<T, num<Idx>>::type;

// TODO: document
template <typename T, typename U>
using at_t = typename at<T, U>::type;
}  // namespace camp


#endif /* __CAMP_list_at_hpp */