1 // Copyright 2016-2021 Francesco Biscani (bluescarni@gmail.com)
2 //
3 // This file is part of the mp++ library.
4 //
5 // This Source Code Form is subject to the terms of the Mozilla
6 // Public License v. 2.0. If a copy of the MPL was not distributed
7 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #ifndef MPPP_CONCEPTS_HPP
10 #define MPPP_CONCEPTS_HPP
11 
12 #include <mp++/config.hpp>
13 
14 #include <complex>
15 #include <cstddef>
16 #include <string>
17 #include <type_traits>
18 
19 #if defined(MPPP_HAVE_STRING_VIEW)
20 #include <string_view>
21 #endif
22 
23 #include <mp++/detail/type_traits.hpp>
24 
25 namespace mppp
26 {
27 
28 // Type trait to check if T is a C++ integral type, including possibly __(u)int128_t.
29 // NOTE: mppp::detail::is_integral, for consistency with std::is_integral, will be true also for cv qualified
30 // integral types. is_cpp_integral, however, is used in contexts where the cv qualifications
31 // matter, and we want this type trait not to be satisfied by integral types which are, e.g.,
32 // const qualified.
33 template <typename T>
34 using is_cpp_integral = detail::conjunction<detail::is_integral<T>, std::is_same<detail::remove_cv_t<T>, T>>;
35 
36 #if defined(MPPP_HAVE_CONCEPTS)
37 
38 template <typename T>
39 MPPP_CONCEPT_DECL cpp_integral = is_cpp_integral<T>::value;
40 
41 #endif
42 
43 template <typename T>
44 using is_cpp_unsigned_integral = detail::conjunction<is_cpp_integral<T>, detail::is_unsigned<T>>;
45 
46 #if defined(MPPP_HAVE_CONCEPTS)
47 
48 template <typename T>
49 MPPP_CONCEPT_DECL cpp_unsigned_integral = is_cpp_unsigned_integral<T>::value;
50 
51 #endif
52 
53 template <typename T>
54 using is_cpp_signed_integral = detail::conjunction<is_cpp_integral<T>, detail::is_signed<T>>;
55 
56 #if defined(MPPP_HAVE_CONCEPTS)
57 
58 template <typename T>
59 MPPP_CONCEPT_DECL cpp_signed_integral = is_cpp_signed_integral<T>::value;
60 
61 #endif
62 
63 template <typename T>
64 using is_cpp_floating_point = detail::conjunction<std::is_floating_point<T>, std::is_same<detail::remove_cv_t<T>, T>>;
65 
66 #if defined(MPPP_HAVE_CONCEPTS)
67 
68 template <typename T>
69 MPPP_CONCEPT_DECL cpp_floating_point = is_cpp_floating_point<T>::value;
70 
71 #endif
72 
73 template <typename T>
74 using is_cpp_arithmetic = detail::disjunction<is_cpp_integral<T>, is_cpp_floating_point<T>>;
75 
76 #if defined(MPPP_HAVE_CONCEPTS)
77 
78 template <typename T>
79 MPPP_CONCEPT_DECL cpp_arithmetic = is_cpp_arithmetic<T>::value;
80 
81 #endif
82 
83 template <typename T>
84 using is_cpp_complex = detail::disjunction<std::is_same<T, std::complex<float>>, std::is_same<T, std::complex<double>>,
85                                            std::is_same<T, std::complex<long double>>>;
86 
87 #if defined(MPPP_HAVE_CONCEPTS)
88 
89 template <typename T>
90 MPPP_CONCEPT_DECL cpp_complex = is_cpp_complex<T>::value;
91 
92 #endif
93 
94 namespace detail
95 {
96 
97 // NOTE: remove_pointer_t removes the top level qualifiers of the pointer as well:
98 // http://en.cppreference.com/w/cpp/types/remove_pointer
99 // After removal of pointer, we could still have a type which is cv qualified. Thus,
100 // we remove cv qualifications after pointer removal.
101 template <typename T>
102 using is_char_pointer = conjunction<std::is_pointer<T>, std::is_same<remove_cv_t<remove_pointer_t<T>>, char>>;
103 
104 } // namespace detail
105 
106 template <typename T>
107 using is_string_type
108     = detail::disjunction<std::is_same<detail::remove_cv_t<T>, std::string>, detail::is_char_pointer<T>,
109                           // NOTE: detail::remove_cv_t does remove cv qualifiers from arrays.
110                           detail::conjunction<std::is_array<detail::remove_cv_t<T>>,
111                                               std::is_same<detail::remove_extent_t<detail::remove_cv_t<T>>, char>>
112 #if defined(MPPP_HAVE_STRING_VIEW)
113                           ,
114                           std::is_same<detail::remove_cv_t<T>, std::string_view>
115 #endif
116                           >;
117 
118 #if defined(MPPP_HAVE_CONCEPTS)
119 
120 template <typename T>
121 MPPP_CONCEPT_DECL string_type = is_string_type<T>::value;
122 
123 #endif
124 
125 } // namespace mppp
126 
127 #endif
128