1 /*!
2 @file
3 Defines `boost::hana::to` and related utilities.
4 
5 @copyright Louis Dionne 2013-2016
6 Distributed under the Boost Software License, Version 1.0.
7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
8  */
9 
10 #ifndef BOOST_HANA_CORE_TO_HPP
11 #define BOOST_HANA_CORE_TO_HPP
12 
13 #include <boost/hana/fwd/core/to.hpp>
14 
15 #include <boost/hana/concept/constant.hpp>
16 #include <boost/hana/concept/foldable.hpp>
17 #include <boost/hana/concept/sequence.hpp>
18 #include <boost/hana/config.hpp>
19 #include <boost/hana/core/common.hpp>
20 #include <boost/hana/core/dispatch.hpp>
21 #include <boost/hana/core/make.hpp>
22 #include <boost/hana/detail/wrong.hpp>
23 #include <boost/hana/unpack.hpp>
24 #include <boost/hana/value.hpp>
25 
26 #include <type_traits>
27 #include <utility>
28 
29 
30 BOOST_HANA_NAMESPACE_BEGIN
31     //////////////////////////////////////////////////////////////////////////
32     // to
33     //////////////////////////////////////////////////////////////////////////
34     //! @cond
35     template <typename To, typename From, typename>
36     struct to_impl : to_impl<To, From, when<true>> { };
37     //! @endcond
38 
39     namespace convert_detail {
40         struct no_conversion { };
41 
42         template <typename ...>
43         struct is_valid { static constexpr bool value = true; };
44     }
45 
46     template <typename To, typename From, bool condition>
47     struct to_impl<To, From, when<condition>> : convert_detail::no_conversion {
48         template <typename X>
applyto_impl49         static constexpr auto apply(X const&) {
50             static_assert(detail::wrong<to_impl<To, From>, X>{},
51             "no conversion is available between the provided types");
52         }
53     };
54 
55     template <typename To, typename From>
56     struct to_impl<To, From, when<convert_detail::is_valid<
57         decltype(static_cast<To>(std::declval<From>()))
58     >::value>> {
59         template <typename X>
applyto_impl60         static constexpr To apply(X&& x)
61         { return static_cast<To>(static_cast<X&&>(x)); }
62     };
63 
64     template <typename To>
65     struct to_impl<To, To> : embedding<> {
66         template <typename X>
applyto_impl67         static constexpr X apply(X&& x)
68         { return static_cast<X&&>(x); }
69     };
70 
71     //! @cond
72     template <typename To>
73     template <typename X>
operator ()(X && x) const74     constexpr decltype(auto) to_t<To>::operator()(X&& x) const {
75         using From = typename hana::tag_of<X>::type;
76         return to_impl<To, From>::apply(static_cast<X&&>(x));
77     }
78     //! @endcond
79 
80 #define BOOST_HANA_DEFINE_EMBEDDING_IMPL(TO, FROM)                          \
81     template <>                                                             \
82     struct to_impl<TO, FROM> : embedding<>                                  \
83     { static constexpr TO apply(FROM x) { return x; } }                     \
84 /**/
85     BOOST_HANA_DEFINE_EMBEDDING_IMPL(long double, double);
86     BOOST_HANA_DEFINE_EMBEDDING_IMPL(long double, float);
87     BOOST_HANA_DEFINE_EMBEDDING_IMPL(double     , float);
88 
89     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed long);
90     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed int);
91     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed short);
92     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed char);
93     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed int);
94     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed short);
95     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed char);
96     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed int      , signed short);
97     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed int      , signed char);
98     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed short    , signed char);
99 
100     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned long);
101     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned int);
102     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned short);
103     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned char);
104     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned int);
105     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned short);
106     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned char);
107     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned int      , unsigned short);
108     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned int      , unsigned char);
109     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned short    , unsigned char);
110 #undef BOOST_HANA_DEFINE_EMBEDDING_IMPL
111 
112     namespace detail {
113         template <typename T>
114         struct copy_char_signedness {
115             using type = typename std::conditional<std::is_signed<char>::value,
116                 std::make_signed<T>, std::make_unsigned<T>
117             >::type::type;
118         };
119     }
120 
121     // If `char` is signed, we define an embedding from `char` to any signed
122     // integral type. Otherwise, we define one from `char` to any unsigned
123     // integral type.
124 #define BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(TO)                           \
125     template <>                                                             \
126     struct to_impl<detail::copy_char_signedness<TO>::type, char>            \
127         : embedding<>                                                       \
128     {                                                                       \
129         static constexpr detail::copy_char_signedness<TO>::type             \
130         apply(char x)                                                       \
131         { return x; }                                                       \
132     }                                                                       \
133 /**/
134     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(long long);
135     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(long);
136     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(int);
137     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(short);
138 #undef BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL
139 
140     template <typename T>
141     struct to_impl<T*, decltype(nullptr)> : embedding<> {
applyto_impl142         static constexpr T* apply(decltype(nullptr)) { return nullptr; }
143     };
144 
145     //////////////////////////////////////////////////////////////////////////
146     // is_convertible
147     //////////////////////////////////////////////////////////////////////////
148     template <typename From, typename To, typename>
149     struct is_convertible : std::true_type { };
150 
151     template <typename From, typename To>
152     struct is_convertible<From, To, decltype((void)
153         static_cast<convert_detail::no_conversion>(*(to_impl<To, From>*)0)
154     )> : std::false_type { };
155 
156     //////////////////////////////////////////////////////////////////////////
157     // is_embedded
158     //////////////////////////////////////////////////////////////////////////
159     template <typename From, typename To, typename>
160     struct is_embedded : std::false_type { };
161 
162     template <typename From, typename To>
163     struct is_embedded<From, To, decltype((void)
164         static_cast<embedding<true>>(*(to_impl<To, From>*)0)
165     )> : std::true_type { };
166 
167     //////////////////////////////////////////////////////////////////////////
168     // Conversion for Constants
169     //////////////////////////////////////////////////////////////////////////
170     template <typename To, typename From>
171     struct to_impl<To, From, when<
172         hana::Constant<From>::value &&
173         is_convertible<typename From::value_type, To>::value
174     >> : embedding<is_embedded<typename From::value_type, To>::value> {
175         template <typename X>
applyto_impl176         static constexpr decltype(auto) apply(X const&)
177         { return hana::to<To>(hana::value<X>()); }
178     };
179 
180     //////////////////////////////////////////////////////////////////////////
181     // Foldable -> Sequence
182     //////////////////////////////////////////////////////////////////////////
183     template <typename S, typename F>
184     struct to_impl<S, F, when<
185         hana::Sequence<S>::value &&
186         hana::Foldable<F>::value
187     >> : embedding<Sequence<F>::value> {
188         template <typename Xs>
applyto_impl189         static constexpr decltype(auto) apply(Xs&& xs)
190         { return hana::unpack(static_cast<Xs&&>(xs), hana::make<S>); }
191     };
192 BOOST_HANA_NAMESPACE_END
193 
194 #endif // !BOOST_HANA_CORE_TO_HPP
195