piranha  0.10
monomial_common.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_DETAIL_MONOMIAL_COMMON_HPP
30 #define PIRANHA_DETAIL_MONOMIAL_COMMON_HPP
31 
32 #include <cstddef>
33 #include <type_traits>
34 #include <utility>
35 
36 #include <piranha/config.hpp>
37 #include <piranha/math.hpp>
38 #include <piranha/mp_integer.hpp>
39 #include <piranha/safe_cast.hpp>
40 #include <piranha/type_traits.hpp>
41 
42 // Code shared in the implementation of monomials.
43 
44 namespace piranha
45 {
46 
47 inline namespace impl
48 {
49 
50 // Dispatcher for the monomial exponentiation algorithm.
51 // Here T is the monomial's expo type, U the type of the power
52 // to which the monomial will be raised.
53 template <typename T, typename U>
54 using monomial_pow_dispatcher = disjunction_idx<
55  // Case 0: T and U are both integrals.
56  conjunction<std::is_integral<T>, std::is_integral<U>>,
57  // Case 1: T and U are the same type, and they support math::mul3.
58  conjunction<std::is_same<T, U>, has_mul3<U>>,
59  // Case 2: T * U is well-defined, yielding T.
60  std::is_same<detected_t<mul_t, T, U>, T>,
61  // Case 3: T * U is well-defined, yielding a type that
62  // can be safely cast back to T.
63  has_safe_cast<T, detected_t<mul_t, T, U>>>;
64 
65 // Implementation of case 0.
66 template <typename T, typename U>
67 inline void monomial_pow_mult_exp(T &ret, const T &exp, const U &x, const std::integral_constant<std::size_t, 0u> &)
68 {
69  // NOTE: we could actually use the GCC intrinsics here to detect
70  // overflow on integral multiply.
71  PIRANHA_MAYBE_TLS integer tmp1, tmp2, tmp3;
72  tmp1 = exp;
73  tmp2 = x;
74  mul(tmp3, tmp1, tmp2);
75  // NOTE: we are assuming that T is move-assignable here.
76  // This will result in std::overflow_error in case the result is too
77  // large or small.
78  ret = static_cast<T>(tmp3);
79 }
80 
81 // Implementation of case 1.
82 template <typename T, typename U>
83 inline void monomial_pow_mult_exp(T &ret, const T &exp, const U &x, const std::integral_constant<std::size_t, 1u> &)
84 {
85  math::mul3(ret, exp, x);
86 }
87 
88 // Implementation of case 2.
89 template <typename T, typename U>
90 inline void monomial_pow_mult_exp(T &ret, const T &exp, const U &x, const std::integral_constant<std::size_t, 2u> &)
91 {
92  ret = exp * x;
93 }
94 
95 // Implementation of case 3.
96 template <typename T, typename U>
97 inline void monomial_pow_mult_exp(T &ret, const T &exp, const U &x, const std::integral_constant<std::size_t, 3u> &)
98 {
99 // NOTE: gcc here complains when x is a float and exp a large integer type,
100 // on the basis that the conversion from integral to fp might not preserve
101 // the value exactly (which is of course true). We don't care about this
102 // corner case, let's just disable "-Wconversion" temporarily.
103 #if defined(PIRANHA_COMPILER_IS_GCC)
104 #pragma GCC diagnostic push
105 #pragma GCC diagnostic ignored "-Wconversion"
106 #endif
107  ret = safe_cast<T>(exp * x);
108 #if defined(PIRANHA_COMPILER_IS_GCC)
109 #pragma GCC diagnostic pop
110 #endif
111 }
112 
113 // The enabler.
114 template <typename T, typename U>
115 using monomial_pow_enabler = enable_if_t<(monomial_pow_dispatcher<T, U>::value < 4u), int>;
116 }
117 }
118 
119 #endif
mp_integer< 1 > integer
Alias for piranha::mp_integer with 1 limb of static storage.
Definition: mp_integer.hpp:63
Root piranha namespace.
Definition: array_key.hpp:52
Type traits.
auto mul3(T &a, const T &b, const T &c) -> decltype(mul3_impl< T >()(a, b, c))
Ternary multiplication.
Definition: math.hpp:2726
safe_cast_type< To, From > safe_cast(const From &x)
Safe cast.
Definition: safe_cast.hpp:219