Skip to content

Instantly share code, notes, and snippets.

@amitsingh19975
Last active October 6, 2020 13:52
Show Gist options
  • Save amitsingh19975/d44f15789dd127ad516781c0a9f75503 to your computer and use it in GitHub Desktop.
Save amitsingh19975/d44f15789dd127ad516781c0a9f75503 to your computer and use it in GitHub Desktop.
metaprogramming
//
// Copyright (c) 2018-2020, Cem Bassoy, cem.bassoy@gmail.com
// Copyright (c) 2019-2020, Amit Singh, amitsingh19975@gmail.com
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// The authors gratefully acknowledge the support of
// Google and Fraunhofer IOSB, Ettlingen, Germany
//
#ifndef _BOOST_UBLAS_TENSOR_INTERFACE_META_HPP
#define _BOOST_UBLAS_TENSOR_INTERFACE_META_HPP
/// This file provides the interface for metaprogramming
/// rather than including the library directly, we create
/// a layer on the existing library so that we can easily plug
/// any library.
/// We will be using Boost.MP11 for metaprogramming
#include <boost/mp11/list.hpp>
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/function.hpp>
namespace boost::numeric::ublas {
template <class ExtentsType, ExtentsType... E> class basic_static_extents;
} // namespace boost::numeric::ublas
namespace boost::numeric::ublas::meta {
template <class... Ts> using list = boost::mp11::mp_list<Ts...>;
template <class T, T... Is> using list_c = boost::mp11::mp_list_c<T, Is...>;
template <class L> using size = boost::mp11::mp_size<L>;
template <class L> using empty = boost::mp11::mp_empty<L>;
template <class L> using clear = boost::mp11::mp_clear<L>;
template <class L> using front = boost::mp11::mp_front<L>;
template <class L> using back = boost::mp11::mp_back<L>;
template <class L> using pop_front = boost::mp11::mp_pop_front<L>;
template <class L> using pop_back = boost::mp11::mp_pop_back<L>;
template <class L> using reverse = boost::mp11::mp_reverse<L>;
template <class L, class... Ts>
using push_front = boost::mp11::mp_push_front<L, Ts...>;
template <class L, class... Ts>
using push_back = boost::mp11::mp_push_back<L, Ts...>;
template <template <class...> class F, class L>
using apply = boost::mp11::mp_apply<F, L>;
template <class... Ls> using append = boost::mp11::mp_append<Ls...>;
template <template <class...> class F, class... Ls>
using transform = boost::mp11::mp_transform<F, Ls...>;
template <template <class...> class P, template <class...> class F, class... Ls>
using transform_if = boost::mp11::mp_transform_if<P, F, Ls...>;
template <template <class...> class P, class... Ls>
using filter = boost::mp11::mp_filter<P, Ls...>;
template <class L, class N> using repeat = boost::mp11::mp_repeat<L, N>;
template <class L, std::size_t N>
using repeat_c = boost::mp11::mp_repeat_c<L, N>;
template <class L, class N> using drop = boost::mp11::mp_drop<L, N>;
template <class L, std::size_t N> using drop_c = boost::mp11::mp_drop_c<L, N>;
template <class L, class N> using at = boost::mp11::mp_at<L, N>;
template <class L, std::size_t N> using at_c = boost::mp11::mp_at_c<L, N>;
template <class N> using iota = boost::mp11::mp_iota<N>;
template <std::size_t N> using iota_c = boost::mp11::mp_iota_c<N>;
template <class L, class V, class W>
using replace = boost::mp11::mp_replace<L, V, W>;
template <class L, class I, class W>
using replace_at = boost::mp11::mp_replace_at<L, I, W>;
template <class L, std::size_t I, class W>
using replace_at_c = boost::mp11::mp_replace_at_c<L, I, W>;
/// @returns the function back
template <class L, class F> constexpr auto for_each(F&& f)
{
return boost::mp11::mp_for_each<L>(std::forward<F>(f));
}
namespace detail {
/// This is helper, which helps the rec_for_each
/// (recursive for_each) to iterate over a range.
/// This is different than for_each in terms of return
/// value, it can return compared to for_each which returns
/// the function itself.
/// It is useful when we need the return type of the function and
/// we need this return value as the next input for the function.
/// @code
/// auto r1 = fn(0,r0);
/// auto r2 = fn(1,r1);
/// auto r3 = fn(2,r2);
/// @endcode
template <std::size_t I, std::size_t End> struct rec_for_each_helper {
template <typename BinaryFn, typename T>
constexpr auto operator()(T&& ret, BinaryFn&& fn) const
{
if constexpr (End <= I) {
return ret;
}
else {
std::integral_constant<std::size_t, I> curr_idx{};
auto n_ret = fn(curr_idx, ret);
return rec_for_each_helper<I + 1, End>{}(std::move(n_ret),
std::forward<BinaryFn>(fn));
}
}
};
} // namespace detail
template <std::size_t Start, std::size_t End, typename T, typename BinaryFn>
constexpr auto rec_for_each(T&& ret, BinaryFn&& fn)
{
return detail::rec_for_each_helper<Start, End>{}(std::forward<T>(ret),
std::forward<BinaryFn>(fn));
}
} // namespace boost::numeric::ublas::meta
namespace boost::numeric::ublas::meta {
template <typename T> struct to_list;
template <typename T> using to_list_t = typename to_list<T>::type;
template <typename T, T... Es> struct to_list<basic_static_extents<T, Es...>> {
using type = list_c<T, Es...>;
};
template <typename T> struct to_static_extents;
template <typename T>
using to_static_extents_t = typename to_static_extents<T>::type;
template <typename T, T... Es>
struct to_static_extents<list<std::integral_constant<T, Es>...>> {
using type = basic_static_extents<T, Es...>;
};
} // namespace boost::numeric::ublas::meta
#endif // _BOOST_UBLAS_TENSOR_INTERFACE_META_HPP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment