• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*!
2 @file
3 Defines `boost::hana::mod`.
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_MOD_HPP
11 #define BOOST_HANA_MOD_HPP
12 
13 #include <boost/hana/fwd/mod.hpp>
14 
15 #include <boost/hana/concept/constant.hpp>
16 #include <boost/hana/concept/euclidean_ring.hpp>
17 #include <boost/hana/config.hpp>
18 #include <boost/hana/core/to.hpp>
19 #include <boost/hana/core/dispatch.hpp>
20 #include <boost/hana/detail/canonical_constant.hpp>
21 #include <boost/hana/detail/has_common_embedding.hpp>
22 #include <boost/hana/value.hpp>
23 
24 #include <type_traits>
25 
26 
27 BOOST_HANA_NAMESPACE_BEGIN
28     //! @cond
29     template <typename X, typename Y>
operator ()(X && x,Y && y) const30     constexpr decltype(auto) mod_t::operator()(X&& x, Y&& y) const {
31         using T = typename hana::tag_of<X>::type;
32         using U = typename hana::tag_of<Y>::type;
33         using Mod = BOOST_HANA_DISPATCH_IF(decltype(mod_impl<T, U>{}),
34             hana::EuclideanRing<T>::value &&
35             hana::EuclideanRing<U>::value &&
36             !is_default<mod_impl<T, U>>::value
37         );
38 
39     #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
40         static_assert(hana::EuclideanRing<T>::value,
41         "hana::mod(x, y) requires 'x' to be an EuclideanRing");
42 
43         static_assert(hana::EuclideanRing<U>::value,
44         "hana::mod(x, y) requires 'y' to be an EuclideanRing");
45 
46         static_assert(!is_default<mod_impl<T, U>>::value,
47         "hana::mod(x, y) requires 'x' and 'y' to be embeddable "
48         "in a common EuclideanRing");
49     #endif
50 
51         return Mod::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
52     }
53     //! @endcond
54 
55     template <typename T, typename U, bool condition>
56     struct mod_impl<T, U, when<condition>> : default_ {
57         template <typename ...Args>
58         static constexpr auto apply(Args&& ...) = delete;
59     };
60 
61     // Cross-type overload
62     template <typename T, typename U>
63     struct mod_impl<T, U, when<
64         detail::has_nontrivial_common_embedding<EuclideanRing, T, U>::value
65     >> {
66         using C = typename common<T, U>::type;
67         template <typename X, typename Y>
applymod_impl68         static constexpr decltype(auto) apply(X&& x, Y&& y) {
69             return hana::mod(hana::to<C>(static_cast<X&&>(x)),
70                              hana::to<C>(static_cast<Y&&>(y)));
71         }
72     };
73 
74     //////////////////////////////////////////////////////////////////////////
75     // Model for integral data types
76     //////////////////////////////////////////////////////////////////////////
77     template <typename T>
78     struct mod_impl<T, T, when<std::is_integral<T>::value &&
79                                !std::is_same<T, bool>::value>> {
80         template <typename X, typename Y>
applymod_impl81         static constexpr decltype(auto) apply(X&& x, Y&& y)
82         { return static_cast<X&&>(x) % static_cast<Y&&>(y); }
83     };
84 
85     //////////////////////////////////////////////////////////////////////////
86     // Model for Constants over an EuclideanRing
87     //////////////////////////////////////////////////////////////////////////
88     namespace detail {
89         template <typename C, typename X, typename Y>
90         struct constant_from_mod {
91             static constexpr auto value = hana::mod(hana::value<X>(), hana::value<Y>());
92             using hana_tag = detail::CanonicalConstant<typename C::value_type>;
93         };
94     }
95 
96     template <typename C>
97     struct mod_impl<C, C, when<
98         hana::Constant<C>::value &&
99         EuclideanRing<typename C::value_type>::value
100     >> {
101         template <typename X, typename Y>
applymod_impl102         static constexpr decltype(auto) apply(X const&, Y const&)
103         { return hana::to<C>(detail::constant_from_mod<C, X, Y>{}); }
104     };
105 BOOST_HANA_NAMESPACE_END
106 
107 #endif // !BOOST_HANA_MOD_HPP
108