/*!
|
@file
|
Defines `boost::hana::experimental::types`.
|
|
@copyright Louis Dionne 2013-2017
|
Distributed under the Boost Software License, Version 1.0.
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
*/
|
|
#ifndef BOOST_HANA_EXPERIMENTAL_TYPES_HPP
|
#define BOOST_HANA_EXPERIMENTAL_TYPES_HPP
|
|
#include <boost/hana/bool.hpp>
|
#include <boost/hana/concept/metafunction.hpp>
|
#include <boost/hana/config.hpp>
|
#include <boost/hana/detail/any_of.hpp>
|
#include <boost/hana/detail/type_at.hpp>
|
#include <boost/hana/fwd/at.hpp>
|
#include <boost/hana/fwd/contains.hpp>
|
#include <boost/hana/fwd/core/tag_of.hpp>
|
#include <boost/hana/fwd/equal.hpp>
|
#include <boost/hana/fwd/is_empty.hpp>
|
#include <boost/hana/fwd/transform.hpp>
|
#include <boost/hana/fwd/unpack.hpp>
|
#include <boost/hana/type.hpp>
|
|
#include <cstddef>
|
#include <type_traits>
|
#include <utility>
|
|
|
BOOST_HANA_NAMESPACE_BEGIN
|
namespace experimental {
|
//! @ingroup group-experimental
|
//! Container optimized for holding types.
|
//!
|
//! It is often useful to manipulate a sequence that contains types
|
//! only, without any associated runtime value. This container allows
|
//! storing and manipulating pure types in a much more compile-time
|
//! efficient manner than using `hana::tuple`, which must assume that
|
//! its contents might have runtime values.
|
template <typename ...T>
|
struct types;
|
|
struct types_tag;
|
|
template <typename ...T>
|
struct types { };
|
} // end namespace experimental
|
|
template <typename ...T>
|
struct tag_of<experimental::types<T...>> {
|
using type = experimental::types_tag;
|
};
|
|
// Foldable
|
template <>
|
struct unpack_impl<hana::experimental::types_tag> {
|
template <typename ...T, typename F, typename = typename std::enable_if<
|
!hana::Metafunction<F>::value
|
>::type>
|
static constexpr decltype(auto) apply(hana::experimental::types<T...> const&, F&& f) {
|
return static_cast<F&&>(f)(hana::type<T>{}...);
|
}
|
|
template <typename ...T, typename F, typename = typename std::enable_if<
|
hana::Metafunction<F>::value
|
>::type>
|
static constexpr hana::type<typename F::template apply<T...>::type>
|
apply(hana::experimental::types<T...> const&, F const&) { return {}; }
|
};
|
|
// Functor
|
template <>
|
struct transform_impl<hana::experimental::types_tag> {
|
template <typename ...T, typename F, typename = typename std::enable_if<
|
!hana::Metafunction<F>::value
|
>::type>
|
static constexpr auto apply(hana::experimental::types<T...> const&, F&& f)
|
-> hana::experimental::types<typename decltype(+f(hana::type<T>{}))::type...>
|
{ return {}; }
|
|
template <typename ...T, typename F, typename = typename std::enable_if<
|
hana::Metafunction<F>::value
|
>::type>
|
static constexpr hana::experimental::types<typename F::template apply<T>::type...>
|
apply(hana::experimental::types<T...> const&, F const&) { return {}; }
|
};
|
|
// Iterable
|
template <>
|
struct at_impl<hana::experimental::types_tag> {
|
template <typename ...T, typename N>
|
static constexpr auto
|
apply(hana::experimental::types<T...> const&, N const&) {
|
using Nth = typename detail::type_at<N::value, T...>::type;
|
return hana::type<Nth>{};
|
}
|
};
|
|
template <>
|
struct is_empty_impl<hana::experimental::types_tag> {
|
template <typename ...T>
|
static constexpr hana::bool_<sizeof...(T) == 0>
|
apply(hana::experimental::types<T...> const&)
|
{ return {}; }
|
};
|
|
template <>
|
struct drop_front_impl<hana::experimental::types_tag> {
|
template <std::size_t n, typename ...T, std::size_t ...i>
|
static hana::experimental::types<typename detail::type_at<i + n, T...>::type...>
|
helper(std::index_sequence<i...>);
|
|
template <typename ...T, typename N>
|
static constexpr auto
|
apply(hana::experimental::types<T...> const&, N const&) {
|
constexpr std::size_t n = N::value > sizeof...(T) ? sizeof...(T) : N::value;
|
using Indices = std::make_index_sequence<sizeof...(T) - n>;
|
return decltype(helper<n, T...>(Indices{})){};
|
}
|
};
|
|
// Searchable
|
template <>
|
struct contains_impl<hana::experimental::types_tag> {
|
template <typename U>
|
struct is_same_as {
|
template <typename T>
|
struct apply {
|
static constexpr bool value = std::is_same<U, T>::value;
|
};
|
};
|
|
template <typename ...T, typename U>
|
static constexpr auto apply(hana::experimental::types<T...> const&, U const&)
|
-> hana::bool_<
|
detail::any_of<is_same_as<typename U::type>::template apply, T...>::value
|
>
|
{ return {}; }
|
|
static constexpr hana::false_ apply(...) { return {}; }
|
};
|
|
// Comparable
|
template <>
|
struct equal_impl<hana::experimental::types_tag, hana::experimental::types_tag> {
|
template <typename Types>
|
static constexpr hana::true_ apply(Types const&, Types const&)
|
{ return {}; }
|
|
template <typename Ts, typename Us>
|
static constexpr hana::false_ apply(Ts const&, Us const&)
|
{ return {}; }
|
};
|
BOOST_HANA_NAMESPACE_END
|
|
#endif // !BOOST_HANA_EXPERIMENTAL_TYPES_HPP
|