1 /*!
2 @file
3 Defines `boost::hana::common` and `boost::hana::common_t`.
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_COMMON_HPP
11 #define BOOST_HANA_CORE_COMMON_HPP
12 
13 #include <boost/hana/fwd/core/common.hpp>
14 
15 #include <boost/hana/concept/constant.hpp>
16 #include <boost/hana/config.hpp>
17 #include <boost/hana/core/when.hpp>
18 #include <boost/hana/detail/canonical_constant.hpp>
19 #include <boost/hana/detail/std_common_type.hpp>
20 #include <boost/hana/detail/void_t.hpp>
21 
22 #include <type_traits>
23 
24 
25 BOOST_HANA_NAMESPACE_BEGIN
26     //////////////////////////////////////////////////////////////////////////
27     // common
28     //////////////////////////////////////////////////////////////////////////
29     //! @cond
30     template <typename T, typename U, typename>
31     struct common : common<T, U, when<true>> { };
32     //! @endcond
33 
34     template <typename T, typename U, bool condition>
35     struct common<T, U, when<condition>>
36         : detail::std_common_type<T, U>
37     { };
38 
39     template <typename T>
40     struct common<T, T> {
41         using type = T;
42     };
43 
44     //////////////////////////////////////////////////////////////////////////
45     // has_common
46     //////////////////////////////////////////////////////////////////////////
47     template <typename T, typename U, typename>
48     struct has_common : std::false_type { };
49 
50     template <typename T, typename U>
51     struct has_common<T, U, detail::void_t<typename common<T, U>::type>>
52         : std::true_type
53     { };
54 
55     //////////////////////////////////////////////////////////////////////////
56     // Provided common data types for Constants
57     //////////////////////////////////////////////////////////////////////////
58     namespace constant_detail {
59         //! @todo
60         //! This is an awful hack to avoid having
61         //! @code
62         //!     common<integral_constant_tag<int>, integral_constant_tag<long>>
63         //!         ==
64         //!     CanonicalConstant<long>
65         //! @endcode
66         template <typename A, typename B, typename C>
67         struct which {
68             using type = detail::CanonicalConstant<C>;
69         };
70 
71         template <template <typename ...> class A, typename T, typename U, typename C>
72         struct which<A<T>, A<U>, C> {
73             using type = A<C>;
74         };
75     }
76 
77     template <typename A, typename B>
78     struct common<A, B, when<
79         hana::Constant<A>::value &&
80         hana::Constant<B>::value &&
81         has_common<typename A::value_type, typename B::value_type>::value
82     >> {
83         using type = typename constant_detail::which<
84             A, B,
85             typename common<typename A::value_type,
86                             typename B::value_type>::type
87         >::type;
88     };
89 
90     template <typename A, typename B>
91     struct common<A, B, when<
92         hana::Constant<A>::value &&
93         !hana::Constant<B>::value &&
94         has_common<typename A::value_type, B>::value
95     >> {
96         using type = typename common<typename A::value_type, B>::type;
97     };
98 
99     template <typename A, typename B>
100     struct common<A, B, when<
101         !hana::Constant<A>::value &&
102         hana::Constant<B>::value &&
103         has_common<A, typename B::value_type>::value
104     >> {
105         using type = typename common<A, typename B::value_type>::type;
106     };
107 BOOST_HANA_NAMESPACE_END
108 
109 #endif // !BOOST_HANA_CORE_COMMON_HPP
110