piranha  0.10
pow.hpp
1 /* Copyright 2009-2017 Francesco Biscani (bluescarni@gmail.com)
2 
3 This file is part of the Piranha library.
4 
5 The Piranha library is free software; you can redistribute it and/or modify
6 it under the terms of either:
7 
8  * the GNU Lesser General Public License as published by the Free
9  Software Foundation; either version 3 of the License, or (at your
10  option) any later version.
11 
12 or
13 
14  * the GNU General Public License as published by the Free Software
15  Foundation; either version 3 of the License, or (at your option) any
16  later version.
17 
18 or both in parallel, as here.
19 
20 The Piranha library is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24 
25 You should have received copies of the GNU General Public License and the
26 GNU Lesser General Public License along with the Piranha library. If not,
27 see https://www.gnu.org/licenses/. */
28 
29 #ifndef PIRANHA_POW_HPP
30 #define PIRANHA_POW_HPP
31 
32 #include <cmath>
33 #include <cstddef>
34 #include <type_traits>
35 #include <utility>
36 
37 #include <piranha/mp_integer.hpp>
38 #include <piranha/type_traits.hpp>
39 
40 namespace piranha
41 {
42 
43 namespace math
44 {
45 
47 
51 template <typename T, typename U, typename = void>
52 struct pow_impl {
53 };
54 }
55 
56 inline namespace impl
57 {
58 
59 // Enabler for the pow overload for arithmetic and floating-point types.
60 template <typename T, typename U>
61 using pow_fp_arith_enabler
62  = enable_if_t<conjunction<std::is_arithmetic<T>, std::is_arithmetic<U>,
63  disjunction<std::is_floating_point<T>, std::is_floating_point<U>>>::value>;
64 }
65 
66 namespace math
67 {
68 
70 
74 template <typename T, typename U>
75 struct pow_impl<T, U, pow_fp_arith_enabler<T, U>> {
77 
85  auto operator()(const T &x, const U &y) const -> decltype(std::pow(x, y))
86  {
87  return std::pow(x, y);
88  }
89 };
90 }
91 
92 inline namespace impl
93 {
94 
95 // Enabler for math::pow().
96 template <typename T, typename U>
97 using math_pow_t_ = decltype(math::pow_impl<T, U>{}(std::declval<const T &>(), std::declval<const U &>()));
98 
99 template <typename T, typename U>
100 using math_pow_t = enable_if_t<is_returnable<math_pow_t_<T, U>>::value, math_pow_t_<T, U>>;
101 }
102 
103 namespace math
104 {
105 
107 
125 template <typename T, typename U>
126 inline math_pow_t<T, U> pow(const T &x, const U &y)
127 {
128  return pow_impl<T, U>{}(x, y);
129 }
130 }
131 
132 inline namespace impl
133 {
134 
135 // Enabler for integral power.
136 template <typename T, typename U>
137 using integer_pow_enabler
138  = enable_if_t<disjunction<conjunction<is_mp_integer<T>, mppp::mppp_impl::is_supported_interop<U>>,
139  conjunction<is_mp_integer<U>, mppp::mppp_impl::is_supported_interop<T>>,
140  conjunction<std::is_integral<T>, std::is_integral<U>>, is_same_mp_integer<T, U>>::value>;
141 
142 // Wrapper for ADL.
143 template <typename T, typename U>
144 inline auto mp_integer_pow_wrapper(const T &base, const U &exp) -> decltype(pow(base, exp))
145 {
146  return pow(base, exp);
147 }
148 }
149 
150 namespace math
151 {
152 
153 // NOTE: this specialisation must be here as in the integral-integral overload we use mp_integer inside,
154 // so the declaration of mp_integer must be avaiable. On the other hand, we cannot put this in mp_integer.hpp
155 // as the integral-integral overload is supposed to work without including mp_integer.hpp.
157 
170 template <typename T, typename U>
171 struct pow_impl<T, U, integer_pow_enabler<T, U>> {
172 private:
173  // C++ integral -- C++ integral.
174  template <typename T2, typename U2,
175  enable_if_t<conjunction<std::is_integral<T2>, std::is_integral<U2>>::value, int> = 0>
176  static integer impl(const T2 &b, const U2 &e)
177  {
178  return mp_integer_pow_wrapper(integer{b}, e);
179  }
180  // The other cases.
181  template <typename T2, typename U2,
182  enable_if_t<negation<conjunction<std::is_integral<T2>, std::is_integral<U2>>>::value, int> = 0>
183  static auto impl(const T2 &b, const U2 &e) -> decltype(mp_integer_pow_wrapper(b, e))
184  {
185  return mp_integer_pow_wrapper(b, e);
186  }
187  using ret_type = decltype(impl(std::declval<const T &>(), std::declval<const U &>()));
188 
189 public:
191 
199  ret_type operator()(const T &b, const U &e) const
200  {
201  return impl(b, e);
202  }
203 };
204 }
205 
206 inline namespace impl
207 {
208 
209 // Type resulting from the application of math::pow().
210 template <typename Base, typename Expo>
211 using pow_t = decltype(math::pow(std::declval<const Base &>(), std::declval<const Expo &>()));
212 }
213 
215 
219 template <typename T, typename U>
221 {
222  static const bool implementation_defined = is_detected<pow_t, T, U>::value;
223 
224 public:
226  static const bool value = implementation_defined;
227 };
228 
229 // Static init.
230 template <typename T, typename U>
232 }
233 
234 #endif
math_pow_t< T, U > pow(const T &x, const U &y)
Exponentiation.
Definition: pow.hpp:126
Multiprecision integer class.
Definition: mp++.hpp:869
Type trait for exponentiable types.
Definition: pow.hpp:220
Default functor for the implementation of piranha::math::pow().
Definition: pow.hpp:52
static const bool value
Value of the type trait.
Definition: pow.hpp:226
Root piranha namespace.
Definition: array_key.hpp:52
ret_type operator()(const T &b, const U &e) const
Call operator.
Definition: pow.hpp:199
Type traits.
auto operator()(const T &x, const U &y) const -> decltype(std::pow(x, y))
Call operator.
Definition: pow.hpp:85