1 /*!
2 @file
3 Defines `boost::hana::to` and related utilities.
4 
5 @copyright Louis Dionne 2013-2017
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 To, typename From, typename = void>
43         struct maybe_static_cast : no_conversion {
44             template <typename X>
applyconvert_detail::maybe_static_cast45             static constexpr auto apply(X const&) {
46                 static_assert(detail::wrong<to_impl<To, From>, X>{},
47                 "no conversion is available between the provided types");
48             }
49         };
50 
51         template <typename To, typename From>
52         struct maybe_static_cast<To, From, decltype((void)
53             static_cast<To>(std::declval<From>())
54         )> {
55             template <typename X>
applyconvert_detail::maybe_static_cast56             static constexpr To apply(X&& x)
57             { return static_cast<To>(static_cast<X&&>(x)); }
58         };
59     } // end namespace convert_detail
60 
61     template <typename To, typename From, bool condition>
62     struct to_impl<To, From, when<condition>>
63         : convert_detail::maybe_static_cast<To, From>
64     { };
65 
66     template <typename To>
67     struct to_impl<To, To> : embedding<> {
68         template <typename X>
applyto_impl69         static constexpr X apply(X&& x)
70         { return static_cast<X&&>(x); }
71     };
72 
73     //! @cond
74     template <typename To>
75     template <typename X>
operator ()(X && x) const76     constexpr decltype(auto) to_t<To>::operator()(X&& x) const {
77         using From = typename hana::tag_of<X>::type;
78         return to_impl<To, From>::apply(static_cast<X&&>(x));
79     }
80     //! @endcond
81 
82 #define BOOST_HANA_DEFINE_EMBEDDING_IMPL(TO, FROM)                          \
83     template <>                                                             \
84     struct to_impl<TO, FROM> : embedding<>                                  \
85     { static constexpr TO apply(FROM x) { return x; } }                     \
86 /**/
87     BOOST_HANA_DEFINE_EMBEDDING_IMPL(long double, double);
88     BOOST_HANA_DEFINE_EMBEDDING_IMPL(long double, float);
89     BOOST_HANA_DEFINE_EMBEDDING_IMPL(double     , float);
90 
91     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed long);
92     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed int);
93     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed short);
94     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long long, signed char);
95     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed int);
96     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed short);
97     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed long     , signed char);
98     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed int      , signed short);
99     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed int      , signed char);
100     BOOST_HANA_DEFINE_EMBEDDING_IMPL(signed short    , signed char);
101 
102     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned long);
103     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned int);
104     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned short);
105     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long long, unsigned char);
106     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned int);
107     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned short);
108     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned long     , unsigned char);
109     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned int      , unsigned short);
110     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned int      , unsigned char);
111     BOOST_HANA_DEFINE_EMBEDDING_IMPL(unsigned short    , unsigned char);
112 #undef BOOST_HANA_DEFINE_EMBEDDING_IMPL
113 
114     namespace detail {
115         template <typename T>
116         struct copy_char_signedness {
117             using type = typename std::conditional<std::is_signed<char>::value,
118                 std::make_signed<T>, std::make_unsigned<T>
119             >::type::type;
120         };
121     }
122 
123     // If `char` is signed, we define an embedding from `char` to any signed
124     // integral type. Otherwise, we define one from `char` to any unsigned
125     // integral type.
126 #define BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(TO)                           \
127     template <>                                                             \
128     struct to_impl<detail::copy_char_signedness<TO>::type, char>            \
129         : embedding<>                                                       \
130     {                                                                       \
131         static constexpr detail::copy_char_signedness<TO>::type             \
132         apply(char x)                                                       \
133         { return x; }                                                       \
134     }                                                                       \
135 /**/
136     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(long long);
137     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(long);
138     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(int);
139     BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL(short);
140 #undef BOOST_HANA_DEFINE_CHAR_EMBEDDING_IMPL
141 
142     template <typename T>
143     struct to_impl<T*, decltype(nullptr)> : embedding<> {
applyto_impl144         static constexpr T* apply(decltype(nullptr)) { return nullptr; }
145     };
146 
147     //////////////////////////////////////////////////////////////////////////
148     // is_convertible
149     //////////////////////////////////////////////////////////////////////////
150     template <typename From, typename To, typename>
151     struct is_convertible : std::true_type { };
152 
153     template <typename From, typename To>
154     struct is_convertible<From, To, decltype((void)
155         static_cast<convert_detail::no_conversion>(*(to_impl<To, From>*)0)
156     )> : std::false_type { };
157 
158     //////////////////////////////////////////////////////////////////////////
159     // is_embedded
160     //////////////////////////////////////////////////////////////////////////
161     template <typename From, typename To, typename>
162     struct is_embedded : std::false_type { };
163 
164     template <typename From, typename To>
165     struct is_embedded<From, To, decltype((void)
166         static_cast<embedding<true>>(*(to_impl<To, From>*)0)
167     )> : std::true_type { };
168 
169     //////////////////////////////////////////////////////////////////////////
170     // Conversion for Constants
171     //////////////////////////////////////////////////////////////////////////
172     template <typename To, typename From>
173     struct to_impl<To, From, when<
174         hana::Constant<From>::value &&
175         is_convertible<typename From::value_type, To>::value
176     >> : embedding<is_embedded<typename From::value_type, To>::value> {
177         template <typename X>
applyto_impl178         static constexpr decltype(auto) apply(X const&)
179         { return hana::to<To>(hana::value<X>()); }
180     };
181 
182     //////////////////////////////////////////////////////////////////////////
183     // Foldable -> Sequence
184     //////////////////////////////////////////////////////////////////////////
185     template <typename S, typename F>
186     struct to_impl<S, F, when<
187         hana::Sequence<S>::value &&
188         hana::Foldable<F>::value
189     >> : embedding<Sequence<F>::value> {
190         template <typename Xs>
applyto_impl191         static constexpr decltype(auto) apply(Xs&& xs)
192         { return hana::unpack(static_cast<Xs&&>(xs), hana::make<S>); }
193     };
194 BOOST_HANA_NAMESPACE_END
195 
196 #endif // !BOOST_HANA_CORE_TO_HPP
197