Last active
October 6, 2020 13:52
-
-
Save amitsingh19975/d44f15789dd127ad516781c0a9f75503 to your computer and use it in GitHub Desktop.
metaprogramming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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