/*!
* \file typelist.h
* \brief A template parameter "container"
*
* Copyright (C) 2018 Christos Choutouridis
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see .
*/
#ifndef __utl_meta_pack_h__
#define __utl_meta_pack_h__
#include
#include
#include
#include
#include
#include
/*!
* \ingroup meta
* \defgroup typelist
*/
//! @{
namespace utl {
namespace meta {
/*!
* A class template that just holds a parameter pack.
* The idea came from MPL's sequence concept[1] and from N4115[2].
* In addition to N4115's name "packer" we just prefer a name which is object, not a subject.
* This way the name gives the feeling of a container and smells like Python.
*
* In addition to tuple we lack members, so typelist could serve as an empty base class,
* and an object of the ultimate type could always be instantiated
* (even if the parameter typelist contains void or some type that lacks
* a default constructor).
* ex:
* using l1 = typelist;
*
* boost::hana[3] suggest a more powerful scheme were type invariant structures can be used
* for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
* responsibility that comse along). So a simple python-like list with some extra vector-like
* element access functionalities and no iterators is good enough(for now).
*
* [1]: https://www.boost.org/doc/
* [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html
* [3]: https://github.com/boostorg/hana
*/
template
struct typelist {
using type = typelist; //!< act as identity
//! \return sizeof...(Ts)
static constexpr size_t size() noexcept {
return sizeof...(Ts);
}
//! \return true if empty
static constexpr bool empty() noexcept {
return (sizeof...(Ts) == 0);
}
};
/*!
* An integral constant wrapper that is the size of the \c meta::typelist
* Complexity \f$ O(1) \f$.
* \param List A typelist
* \return The size of the typelist
*/
template
using size = size_t_;
/*!
* An Boolean constant wrapper that returns if the typelist is empty
* Complexity \f$ O(1) \f$.
* \param List A typelist
* \return Empty or not
*/
template
using empty = bool_;
//! pair
//! A special typelist with only 2 Types
//! @{
template
using pair = typelist;
//! @}
//! apply
//! like:
//! template
//! constexpr decltype(auto) apply(F&& f, Tuple&& t);
namespace detail {
template
struct apply_ { };
// apply Param =Ret(Args...)
template
struct apply_
: invoke { };
// apply Param = F
template class F, typename... Args>
struct apply_>
: invoke { };
// apply Param = integer_sequence
template
struct apply_>
: invoke...> { };
}
//! Apply the Invocable \p Fn using the types in the type \p Param as arguments.
template
using apply = detail::apply_;
//! @}
/*
* ========= typelist operations =========
*/
//! fold, rev_fold
//! @{
namespace detail {
// fold<, V, F> == F, T2>, T3>
template
struct fold_ { }; // ill formed
// recursive call
template
struct fold_, V, Fn> {
using type = type_<
fold_<
typelist,
invoke,
Fn
>
>;
};
// termination call
template
struct fold_, V0, Fn> {
using type = V0;
};
// rev_fold<, V, F> == F>>
template
struct rev_fold_ { }; // ill formed
// recursive call
template
struct rev_fold_, V, Fn> {
using type = invoke <
Fn, Head, type_<
rev_fold_ <
typelist,
V,
Fn
>
>
>;
};
// termination call
template
struct rev_fold_ , V, Fn> {
using type = invoke;
};
// termination call
template
struct rev_fold_ , V, Fn> {
using type = invoke;
};
}
/*!
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
* and initial value \p V
* Complexity \f$ O(N) \f$
* \param List The list to fold
* \param V The initial item feeded to Fn
* \param Fn The binary Invocable
*/
template
using fold = type_>;
//! accumulate is an stl name for fold
template
using accumulate = fold;
/*!
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
* and initial value \p V
* Complexity \f$ O(N) \f$
* \param List The list to fold
* \param V The initial item feeded to Fn
* \param Fn The binary Invocable
*/
template
using rev_fold = type_>;
//! @}
//! Concatenation
//! @{
namespace detail {
template
struct concat_ { };
template <>
struct concat_<> {
using type = typelist<>;
};
template
struct concat_> {
using type = typelist;
};
template
struct concat_, typelist> {
using type = typelist;
};
template
struct concat_, typelist, typelist> {
using type = typelist;
};
template
struct concat_, typelist, typelist, Rest...>
: concat_, Rest...> { };
template
struct concat_, typelist, typelist, typelist, Rest...>
: concat_, Rest...> { };
}
/*!
* Transformation that concatenates several lists into a single typelist.
* The parameters must all be instantiations of \c meta::typelist.
* Complexity: \f$ O(L) \f$
* where \f$ L \f$ is the number of lists in the typelist of lists.
*/
template
using concat = type_>;
//! @}
//! Transform
//! @{
namespace detail {
template
struct transform_ { };
template
struct transform_, Fn>, void_...>> {
using type = typelist...>;
};
template
struct transform_, typelist, Fn>,
void_...>> {
using type = typelist...>;
};
} // namespace detail
/*!
* Transform One or two lists with invocable \c Fn and return a new typelist
* Syntax:
* 1) transform Unary invocable
* 2) transform Binary invocable
* Complexity \f$ O(N) \f$.
*/
template
using transform = type_>>;
//! @}
//! repeat_n
//! @{
namespace detail {
template
using first_ = T;
template
struct repeat_n_c_ { };
template
struct repeat_n_c_> {
using type = typelist...>;
};
}
/*!
* Generate typelist of size \c N arguments.
* Complexity \f$ O(log N) \f$.
*/
template
using repeat_n_c = type_>>;
/*!
* Generate typelist of size \c N::type::value arguments.
* Complexity \f$ O(log N) \f$.
*/
template
using repeat_n = repeat_n_c;
//! @}
//! at
//! @{
namespace detail {
template
struct at_impl_;
template
struct at_impl_> {
static nil_ eval(...);
template
static T eval(VoidPtrs..., T *, Us *...);
};
template
struct at_ { };
template
struct at_, N>
: decltype(
at_impl_>::eval(static_cast *>(nullptr)...)
) { };
} // namespace detail
/// Return the \p N th element in the \c meta::typelist \p L.
/// Complexity \f$ O(1) \f$.
template
using at_c = type_>;
//! Return the \p N th element in the \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template
using at = at_c;
//!@}
//! front
//! @{
namespace detail {
template
struct front_ { };
template
struct front_> {
using type = Head;
};
}
//! Return the first element in \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template
using front = type_>;
//! @}
//! back
//! @{
namespace detail {
template
struct back_ { };
template
struct back_> {
using type = at_c, sizeof...(Tail)>;
};
}
//! Return the last element in \c meta::typelist \p L.
//! Complexity \f$ O(1) \f$.
template
using back = type_>;
//! @}
//! pop_front
//! @{
namespace detail {
template
struct pop_front_ { };
template
struct pop_front_> {
using type = typelist;
};
}
/*!
* Return a new \c meta::typelist by removing the first element from the
* front of \p L.
* Complexity \f$ O(1) \f$.
*/
template
using pop_front = type_>;
//! @}
}}
//! @}
#endif /* __utl_meta_pack_h__ */